TM1638芯片+DS1302驱动共阴数码管时钟
- 格式:doc
- 大小:290.50 KB
- 文档页数:27
DS1302 数字时钟芯片总结人:孟令军时间:2014/5/14学习在于总结,学习贵于交流__欢迎交流QQ:1300780479自己总结拒绝繁琐的数据手册系列————DS1302 数字时钟芯片1)简介:DS1302 是DALLAS 公司推出的涓流充电时钟芯片内含有一个实时时钟/日历和31 字节静态RAM 通过简单的串行接口与单片机进行通信实时时钟/ 日历电路提供秒分时日日期月年的信息每月的天数和闰年的天数可自动调整时钟操作可通过AM/PM 指示决定采用24 或12 小时格式DS1302 与单片机之间能简单地采用同步串行的方式进行通信仅需用到三个口线 1 RES 复位 2 I/O 数据线 3 SCLK 串行时钟时钟/RAM 的读/写数据以一个字节或多达31 个字节的字符组方式通信DS1302 工作时功耗很低保持数据和时钟信息时功率小于1mWX1,X2时钟晶振32.768khzVCC电源正极GND电源负极SCLK时钟线RST复位脚I/O数据输入2)内部寄存器:它的内部含有许多寄存器。
具体图在下一页,我简单介绍(1)时钟,对于时钟要写入,且要读取并显示,写入的位置寄存器在哪?读出从哪读?这就是第一种寄存器下表左边是寄存器的位置(理解为地址吧)他们有特点,最后一位为1是read最后一位为0时为write秒,分,时,日,月,星期,年0x80>>一直加下表右边是填写格式。
(2)控制位(读写保护位)0x8e或0x8f 内容为0x80添加写保护0x00去除写保护注意:CH: 时钟停止位寄存器2 的第7 位12/24 小时标志CH=0 振荡器工作允许bit7=1,12 小时模式CH=1 振荡器停止bit7=0,24 小时模式WP: 写保护位寄存器2 的第5 位:AM/PM 定义WP=0 寄存器数据能够写入AP=1 下午模式WP=1 寄存器数据不能写入AP=0 上午模式WP=1 寄存器数据不能写入AP=0 上午模式TCS: 涓流充电选择DS: 二极管选择位TCS=1010 使能涓流充电DS=01 选择一个二极管TCS= 其它禁止涓流充电DS=10 选择两个二极管DS=00 或11, 即使TCS=1010, 充电功能也被禁止`3)程序书写clk时钟线,rst复位端,io数据线①写函数写一字节:Void ds1302_write_byte(uchar dat){uint i;for(i=0;i<8;i++)//分八次送数据{clk=0;io=dat&0x01;clk=1;dat>>=1;}}写数据函数void ds1302_write(uchar add,uchar dat){ //分别送地址及要对应送入的数据rst=0;_nop_();clk=0; _nop_(); //初期复位状态rst=1; _nop_(); //复位拉高开始传送信号ds1302_write_byte(uchar add);ds1302_write_byte(uchar dat);rst=0; _nop_();//释放io口及clk时钟线io=1;clk=1;写数据时序图读数据时序图②读函数void ds1302_read(uchar add){rst=0;_nop_();clk=0; _nop_(); //初期复位状态rst=1; _nop_(); //复位拉高开始传送信号ds1302_write_byte(uchar add);//先把地址传入再读取它的数据for(i=0;i<8;i++){clk=0;value=value>>1;clk=1;if(io)value|=0x80;clk=1;}sck=0;_nop_();clk=0;_nop_();io=1;clk=1;}②读取温度void readtemp ()❶先将保存在数组里的数据(秒分时星期月日年)分别转换为十六进制并储存在原数组。
DS1302DS1302是美国DALLAS公司推出的一种高性能、低功耗的实时时钟芯片,附加31字节静态RAM,采用SPI三线接口与CPU进行同步通信,并可采用突发方式一次传送多个字节的时钟信号和RAM数据。
实时时钟可提供秒、分、时、日、星期、月和年,一个月小与31天时可以自动调整,且具有闰年补偿功能。
工作电压宽达2.5~5.5V。
采用双电源供电(主电源和备用电源),可设置备用电源充电方式,提供了对后背电源进行涓细电流充电的能力。
下面是标准的接线电路图:DS1302有关日历、时间的寄存器共有12个,其中有7个寄存器(读时81h~8Dh,写时80h~8Ch)是存放秒、分,小时、日、月、年、周数据的,存放的数据格式为BCD码形式它的内部时间寄存器如下:将初始设置的时间、日期数据写入这几个寄存器,然后再不断地读取这几个寄存器来获取实时时间和日期。
这几个寄存器的说明如下:1、秒寄存器(81h、80h)的位7定义为时钟暂停标志(CH)。
当初始上电时该位置为1,时钟振荡器停止,DS1302处于低功耗状态;只有将秒寄存器的该位置改写为0时,时钟才能开始运行。
2、控制寄存器(8Fh、8Eh)的位7是写保护位(WP),其它7位均置为0。
在任何的对时钟和RAM的写操作之前,WP位必须为0。
当WP位为1时,写保护位防止对任一寄存器的写操作。
也就是说在电路上电的初始态WP是1,这时是不能改写上面任何一个时间寄存器的,只有首先将WP改写为0,才能进行其它寄存器的写操作。
3、控制寄存器(8Fh、8Eh)的位7是写保护位(WP),其它7位均置为0。
在任何的对时钟和RAM的写操作之前,WP位必须为0。
当WP位为1时,写保护位防止对任一寄存器的写操作。
也就是说在电路上电的初始态WP是1,这时是不能改写上面任何一个时间寄存器的,只有首先将WP改写为0,才能进行其它寄存器的写操作。
下面来说说如果对DS1302进行读写:上面的电路图可以看出,除了电源和接地,DS1302只有三根线和单片机连接,SCLK、I/O 和RST(有的也写成CE),先看时序图:DS1302的数据读写是通过I/O串行进行的。
第十四讲时钟芯片DS1302DS1302 是DALLAS 公司推出的涓流充电时钟芯片,内含有一个实时时钟/日历和31 字节静态RAM ,通过简单的串行接口与单片机进行通信。
实时时钟/日历电路提供秒、分、时、日、周、月、年的信息,每月的天数和闰年的天数可自动调整。
时钟操作可通过AM/PM 指示决定采用24 或12 小时格式。
DS1302 与单片机之间能简单地采用同步串行的方式进行通信,仅需用到三个口线:(1)RES 复位(2)I/O 数据线(3)SCLK 串行时钟。
时钟/RAM 的读/写数据以一个字节或多达31个字节的字符组方式通信。
DS1302 工作时功耗很低保持数据和时钟信息时功率小于1mW。
DS1302由DS1202改进而来增加了以下的特性:双电源管脚用于主电源和备份电源供应,Vcc1为可编程涓流充电电源,附加七个字节存储器。
它广泛应用于电话、传真、便携式仪器以及电池供电的仪器仪表等产品领域下面。
将主要的性能指标作一综合:★实时时钟具有能计算2100 年之前的秒、分、时、日、星期、月、年的能力,还有闰年调整的能力★ 31 8位暂存数据存储RAM★串行I/O口方式使得管脚数量最少★宽范围工作电压2.0 5.5V★工作电流2.0V时,小于300nA★读/写时钟或RAM 数据时有两种传送方式单字节传送和多字节传送字符组方式★ 8 脚DIP封装或可选的8脚SOIC封装根据表面装配★简单3线接口★与TTL兼容Vcc=5V★可选工业级温度范围-40---+85★双电源管用于主电源和备份电源供应以上是DS1302的一些全面的预览,以下为DS1302管脚图:1)VCC2:主用电源引脚2)X1、X2:DS1302外部晶振引脚3)GND:地4)RST:复位引脚5)I/O:串行数据引脚,数据输出或者输入都从这个引脚6)SCLK:串行时钟引脚7)VCC1:备用电源1)VCC 为主电源接5V,CX10 为滤波电容2)2、外接32.768K 的晶振3)3、 5、6、7 脚分别与控制器相联,注意外部4.7K 上拉电阻4)4、备用电源脚,注意是3.3V,DS1302 要求备用电源电压稍微低于主用电源下面讲讲DS1302 的具体操作。
分享一下调试DS1302时钟芯片的经验这几天,着手把以前用DS12C887 时钟芯片做的万年历,改成用DS1302 来做,以前写DS12C887 的代码时感觉蛮轻松,但是写DS1302 感觉有些棘手,在调试的过程中更是不顺的种种。
开始写代码,一开始用开发板做实验,用LCD1602 做显示,这个还是很轻松就搞定了(一天过去了)。
然后自己用DS1302 芯片焊了块板子,然后用杜邦线连接到开发板上面进行测试,不过LCD1602 什么都没有显示,(以为程序有问题不停改来改去花了很多时间,然后才确定肯定是硬件问题而不是软件问题,以为数据都没有写进DS1302 中),经过分析可能是开发板上面的某些芯片可能会对SPI 的数据传输造成一些影响(一天过去了)自己又焊了一块单片机的板子,把LCD1602 给放上去然后连接好DS1302,一上电时钟开始走了,顿时感觉轻松了,结果仔细一看,时间全部都是乱的,我又开始怀疑是程序问题,我开始修改程序,但是怎么样都没有结果(感觉很久没有写程序,放这10 多天的假已经没有感觉,感觉无从下手,很是郁闷),找不到问题只能又把LCD1602 放到开发板上面去做测试,一试还是可以在开发板上面正常工作,难道是芯片的问题,或者是和晶振没有接电容的关系,马上开始查资料,换芯片,结果还是一样,于是乎真的就傻眼了(一天过去了)第二天一开始就先在百度上面搜原因和解决方法,最后也没有收到一个解决的方法,我准备在进行一次测试,把LCD1602 从开发板上门取下来,然后放到自己做的单片机板子上面,一上电,上面都没有LCD1602 亮的不亮,一看引脚,原来插错了,于是就重新插,结果只有背光亮,屏幕没有反应了,试了几次看样子的果断被烧坏了(感觉太背时了)。
一想就气愤,调了这么久没有结果还把东西烧了,觉得不爽还想继续,。
DS1302实时时钟原理与应用
1.原理:
DS1302实时时钟通过一个简单的三线接口与微控制器相连,这三根
线分别是:数据线、时钟线和复位线。
通过这三根线,微控制器可以向
DS1302写入和读取时钟和日期信息。
具体的通信协议可以通过发送特定
的命令字节来实现。
当写入数据时,数据线的电平可以提供有效数据,而
时钟线的上升沿控制数据的传输。
当读取数据时,数据线的电平会反映
DS1302存储器中的信息。
2.应用:
a.数字时钟和日期显示器:DS1302实时时钟可以用来驱动数字时钟
和日期显示器,供人们查看当前时间和日期。
b.考勤系统:DS1302实时时钟可以用来记录员工的考勤信息,如签
到和签退时间。
c.定时器:DS1302实时时钟可以用来控制各种定时器,如定时开关、定时器插座等。
d.定时报警器:使用DS1302实时时钟可以实现定时报警功能,如定
时提醒服药、定时关机等。
e.温度和湿度监测:结合温湿度传感器,DS1302实时时钟可以用来
记录环境的温度和湿度信息,并提供时间戳。
f.数据日志记录器:DS1302实时时钟可以用来记录各种传感器的数据,并提供时间戳,以便后续分析和处理。
总之,DS1302实时时钟是一种非常实用的集成电路,具有精确和可靠的时间计量功能。
它可以广泛应用于各种需要时间记录和计量的电子设备和系统中。
通过合理的设计和应用,我们可以充分发挥DS1302实时时钟的功能,提高系统的可靠性和稳定性。
DS1302是Dallas公司生产的一种实时时钟芯片。
它通过串行方式与单片机进行数据传送,能够向单片机提供包括秒、分、时、日、月、年等在内的实时时间信息,并可对月末日期、闰年天数自动进行调整;它还拥有用于主电源和备份电源的双电源引脚,在主电源关闭的情况下,也能保持时钟的连续运行。
另外,它还能提供31字节的用于高速数据暂存的RAM。
鉴于上述特点,DS1302已在许多单片机系统中得到应用,为系统提供所需的实时时钟信息。
一、DS1302的主要特性1. 引脚排列500)this.width=500 border=0>图1 DS1302引脚排列图DS1302的引脚排列如图1所示,各引脚的功能如下:X1,X2——32768Hz晶振引脚端;RST——复位端;I/O——数据输入/输出端;SCLK——串行时钟端;GND——地;VCC2,VCC1——主电源与后备电源引脚端。
2. 主要功能DS1302时钟芯片内主要包括移位寄存器、控制逻辑电路、振荡器、实时时钟电路以及用于高速暂存的31字节RAM。
DS1302与单片机系统的数据传送依靠RST,I/O,SCLK三根端线即可完成。
其工作过程可概括为:首先系统RST引脚驱动至高电平,然后在作用于SCLK时钟脉冲的作用下,通过I/O引脚向DS1302输入地址/命令字节,随后再在SCLK时钟脉冲的配合下,从I/O引脚写入或读出相应的数据字节。
因此,其与单片机之间的数据传送是十分容易实现的。
二、时钟的产生及存在的问题(1) 在实际使用中,我们发现DS1302的工作情况不够稳定,主要表现在实时时间的传送有时会出现误差,有时甚至整个芯片停止工作。
我们对DS1302的工作电路进行了分析,其与单片机系统的连接如图2所示。
从图中可以看出,DS1302的外部电路十分简单,惟一外接的元件是32768Hz的晶振。
通过实验我们发现:当外接晶振电路振荡时,DS1302计时正确;当外接晶振电路停振时,DS1302计时停止。
时钟芯片DS1302中文资料概述DS1302 是DALLAS 公司推出的涓流充电时钟芯片,内含有一个实时时钟/日历和31 字节静态RAM,通过简单的串行接口与单片机进行通信实时时钟/日历电路.提供秒分时日日期.月年的信息,每月的天数和闰年的天数可自动调整时钟操作可通过AM/PM 指示决定采用24 或12 小时格式.DS1302 与单片机之间能简单地采用同步串行的方式进行通信,仅需用到三个口线:1 RES 复位,2 I/O 数据线,3 SCLK串行时钟.时钟/RAM 的读/写数据以一个字节或多达31 个字节的字符组方式通信.DS1302 工作时功耗很低,保持数据和时钟信息时功率小于1mW.DS1302 是由DS1202 改进而来,增加了以下的特性.双电源管脚用于主电源和备份电源供应Vcc1,为可编程涓流充电电源附加七个字节存储器.它广泛应用于电话传真便携式仪器以及电池供电的仪器仪表等产品领域.下面将主要的性能指标作一综合:实时时钟具有能计算2100 年之前的秒分时日日期星期月年的能力还有闰年调整的能力;31 8 位暂存数据存储RAM;串行I/O 口方式使得管脚数量最少;宽范围工作电压2.0 5.5V;工作电流2.0V 时,小于300nA;读/写时钟或RAM 数据时有两种传送方式单字节传送和多字节传送字符组方式;8 脚DIP 封装或可选的8 脚SOIC 封装根据表面装配;简单3 线接口;与TTL 兼容Vcc=5V;可选工业级温度范围-40 +85;与DS1202 兼容;在DS1202 基础上增加的特性;对Vcc1 有可选的涓流充电能力;双电源管用于主电源和备份电源供应;备份电源管脚可由电池或大容量电容输入;附加的7 字节暂存存储器;1 DS1302 的基本组成和工作原理DS1302 的引脚功能排列及描述如下图所示.ds1302引脚图管脚描述X1 X2 32.768KHz 晶振管脚GND 地RST 复位脚I/O 数据输入/输出引脚SCLK 串行时钟Vcc1,Vcc2 电源供电管脚DS1302 串行时钟芯片8 脚DIPDS1302S 串行时钟芯片8 脚SOIC 200milDS1302Z 串行时钟芯片8 脚SOIC 150mil2. DS1302 内部寄存器CH: 时钟停止位存器2 的第7 位12/24 小时标志CH=0 振荡器工作允许 bit7=1,12 小时模式CH=1 振荡器停止 bit7=0,24 小时模式WP: 写保护位寄存器2 的第5 位:AM/PM 定义WP=0 寄存器数据能够写入 AP=1 下午模式WP=1 寄存器数据不能写入 AP=0 上午模式TCS: 涓流充电选择 DS: 二极管选择位TCS=1010 使能涓流充电 DS=01 选择一个二极管TCS=其它禁止涓流充电 DS=10 选择两个二极管DS=00 或11, 即使TCS=1010, 充电功能也被禁止时钟:DS1302 与微控制器的接口软件及功能应用举例下面首先给出基本的接口软件然后举例说明各种功能的应用1 写保护寄存器操作当写保护寄存器的最高位为0 时允许数据写入寄存器写保护寄存器可以通过命令字节8E,8F 来规定禁止写入/读出写保护位不能在多字节传送模式下写入Write_Enable:MOV Command,#8Eh ;命令字节为8EMOV ByteCnt,#1 ;单字节传送模式MOV R0,#XmtDat 数据地址覆给R0MOV XmtDat,#00h 数据内容为0 写入允许ACALL Send_Byte 用写入数据子程序RET 返回调用本子程序处当写保护寄存器的最高位为1 时禁止数据写入寄存器Write_Disable:MOV Command,#8Eh ;命令字节为8EMOV ByteCnt,#1 ;单字节传送模式MOV R0,#XmtDat 数据地址覆给R0MOV XmtDat,#80h 数据内容为80h 禁止写入ACALL Send_Byte 调用写入数据子程序RET 返回调用本子程序处以上程序调用了基本数据发送(Send_Byte)模块及一些内存单元定义, 其源程序清单在附录中给出下面的程序亦使用了这个模块2 时钟停止位操作当把秒寄存器的第7 位时钟停止位设置为0 时起动时钟开始Osc_Enable:MOV Command,#80h ; 命令字节为80MOV ByteCnt,#1 ; 单字节传送模式MOV 0,#XmtDat 数据地址覆给R0MOV XmtDat,#00h 数据内容为0 振荡器工作允许ACALL Send_Byte 调用写入数据子程序RET 返回调用本子程序处当把秒寄存器的第7 位时钟停止位设置为1 时时钟振荡器停止HT1380 进入低功耗方式Osc_Disable:MOV Command,#80h ;命令字节为80MOV ByteCnt,#1 ;单字节传送模式MOV R0,#XmtDat 数据地址覆给R0MOV XmtDat,#80h 数据内容为80h 振荡器停止ACALL Send_Byte 调用写入数据子程序RET 返回调用本子程序处3. 多字节传送方式当命令字节为BE 或BF 时DS1302 工作在多字节传送模式8 个时钟/日历寄存器从寄存器0 地址开始连续读写从0 位开始的数据当命令字节为FE 或FF 时DS1302 工作在多字节RAM 传送模式31 个RAM 寄存器从0 地址开始连续读写从0 位开始的数据例如写入00 年6 月21 日星期三13 时59 分59 秒程序设置如下Write_Multiplebyte:MOV Command,#0BEh ;命令字节为BEhMOV ByteCnt,#8 ;多字节写入模式此模块为8 个MOV R0,#XmtDat 数据地址覆给R0MOV XmtDat,#59h 秒单元内容为59hMOV XmtDat+1,#59h 分单元内容为59hMOV XmtDat+2,#13h 时单元内容为13hMOV XmtDat+3,#21h 日期单元内容为21hMOV XmtDat+4,#06h 月单元内容为06hMOV XmtDat+5,#03h 星期单元内容为03hMOV XmtDat+6,#0 年单元内容为00hMOV XmtDat+7,#0 写保护单元内容为00hACALL Send_Byte 调用写入数据子程序RET 返回调用本子程序处读出寄存器0-7 的内容程序设置如下Read_Multiplebyte:MOV Command,#0BFh 命令字节为BFhMOV ByteCnt,#8 ; 多字节读出模式此模块为8 个MOV R1,#RcvDat 数据地址覆给R1ACALL Receive_Byte 调用读出数据子程序RET 返回调用本子程序处以上程序调用了基本数据接收(Receive_Byte)模块及一些内存单元定义, 其源程序清单在附录中给出下面的程序亦使用了这个模块4. 单字节传送方式例如写入8 时12 小时模式程序设置如下Write_Singlebyte:MOV Command,#84h ; 命令字节为84hMOV ByteCnt,#1 ; 单字节传送模式MOV R0,#XmtDat 数据地址覆给R0MOV XmtDat,#88h 数据内容为88hACALL Send_Byte 调用写入数据子程序RET 返回调用本子程序处上面所列出的程序模块Write_Enable Write_Disable Osc_Enable Osc_Disable 与单字节写入模块Write_Singlebyte 的程序架构完全相同仅只是几个入口参数不同本文是为了强调功能使用的不同才将其分为不同模块另外,与涓流充电相关的设定也是单字节操作方式,这里就不再单独列出,用户在使用中可灵活简略.下面模块举例说明如何单字节读出小时单元的内容.Read_Singlebyte:MOV Command,#85h ; 命令字节为85hMOV ByteCnt,#1 ; 单字节传送模式MOV R1,#RcvDat 数据地址覆给R1ACALL Receive_Byte 调用读出数据子程序RET 返回调用本子程序处DS1302 应用电路原理图P87LPC764 单片机选取内部振荡及内部复位电路附录数据发送与接收模块源程序清单; CPU 工作频率最大不超过20MHz;; P87LPC762/4 主控器发送接受数据程序; 说明本程序是利用Philips 公司的P87LPC764 单片机任何具有51 内核或其它合适的单片机都可在此作为主控器的普通I/O 口(如P1.2/P1.3/P1.4)实现总线的功能对总线上的器件本程序采用DS1302进行读写操作命令字节在Command 传送字节数在ByteCnt 中所发送的数据在XmtDat 中所接收的数据在RcvDat 中;;P87LPC762/4 主控器总线发送接受数据程序头文件;内存数据定义BitCnt data 30h ; 数据位计数器ByteCnt data 31h ; 数据字节计数器Command data 32h ; 命令字节地址RcvDat DATA 40H ; 接收数据缓冲区XmtDat DATA 50H ; 发送数据缓冲区;端口位定义IO_DATA bit P1.3 ; 数据传送总线SCLK bit P1.4 ; 时钟控制总线RST bit P1.2 ; 复位总线;;发送数据程序;名称:Send_Byte;描述:发送ByteCnt 个字节给被控器DS1302;命令字节地址在Command 中;所发送数据的字节数在ByteCnt 中发送的数据在XmtDat 缓冲区中;Send_Byte:CLR RST ;复位引脚为低电平所有数据传送终止NOPCLR SCLK 清时钟总线NOPSETB RST ;复位引脚为高电平逻辑控制有效NOPMOV A,Command 准备发送命令字节MOV BitCnt,#08h 传送位数为8S_Byte0:RRC A 将最低位传送给进位位CMOV IO_DATA,C 位传送至数据总线NOPSETB SCLK 时钟上升沿发送数据有效NOPCLR SCLK 清时钟总线DJNZ BitCnt,S_Byte0 位传送未完毕则继续NOPS_Byte1: 准备发送数据MOV A,@R0 传送数据过程与传送命令相同MOV BitCnt,#08hS_Byte2:RRC AMOV IO_DATA,CNOPSETB SCLKNOPCLR SCLKDJNZ BitCnt,S_Byte2INC R0 发送数据的内存地址加1DJNZ ByteCnt,S_Byte1 字节传送未完毕则继续NOPCLR RST 逻辑操作完毕清RSTRET;接收数据程序;;名称:Receive_Byte;描述:从被控器DS1302 接收ByteCnt 个字节数据;命令字节地址在Command 中;所接收数据的字节数在ByteCnt 中接收的数据在RcvDat 缓冲区中Receive_Byte:CLR RST ;复位引脚为低电平所有数据传送终止NOPCLR SCLK 清时钟总线NOPSETB RST ;复位引脚为高电平逻辑控制有效MOV A,Command 准备发送命令字节MOV BitCnt,#08h 传送位数为8R_Byte0:RRC A 将最低位传送给进位位CMOV IO_DATA,C 位传送至数据总线NOPSETB SCLK 时钟上升沿发送数据有效NOPCLR SCLK 清时钟总线DJNZ BitCnt,R_Byte0 位传送未完毕则继续NOPR_Byte1: 准备接收数据CLR A 清类加器CLR C 清进位位CMOV BitCnt,#08h 接收位数为8R_Byte2:NOPMOV C,IO_DATA 数据总线上的数据传送给CRRC A 从最低位接收数据SETB SCLK 时钟总线置高NOPCLR SCLK 时钟下降沿接收数据有效DJNZ BitCnt,R_Byte2 位接收未完毕则继续MOV @R1,A 接收到的完整数据字节放入接收内存缓冲区INC R1 接收数据的内存地址加1DJNZ ByteCnt,R_Byte1 字节接收未完毕则继续NOPCLR RST 逻辑操作完毕清RSTRETEND直流参数表:主要电参数表:交流参数表:电容配置表:。
单片机与可编程器件LED数码管时钟电路采用24h计时方式,时、分、秒用六位数码管显示,其中小时、分、秒之间用小数点分开。
该电路采用AT89C52单片机和DS1302实时时钟芯片,使用5V电源进行供电,使用两个按键进行调时,调整过程中被调节的分钟或时钟将进入闪亮状态,看上去非常直观,另外,本设计还具有快速调时功能,当按键一直被按下时,便进入快速调时状态。
由于本时钟电路的计时是由芯片DS1302来完成的,计时准确 ,单片机通过串行通信来控制DS1302工作,同时进行键盘和显示的控制。
DS1302芯片介绍1.DS1302的功能及其结构DS1302芯片是美国DALLAS公司推出的低功耗实时时钟芯片,它采用串行通信方式,只需3条线便可以和单片机通信,并且其片内均含RAM,可增加系统的RAM,DS1302的时钟校准比较容易,若采用专用的晶体振荡器,几乎无须调整即可以达到国家要求的时钟误差标准。
DS1302有两个电源输入端,其中的一个用来做备用电源,这样避免了由于突然停电而造成时钟停止,因此它非常适合于长时间无人职守的监测控制系统或需经常记录某些具有特殊意义的数据及对应时间的场合。
DS1302提供秒、分、时、日、星期、月、年的信息,每月的天数和闰年的天数可自动调整,并可通过AM/PM 指示决定采用24 或12 小时格式。
DS1302串行时钟芯片主要由移位寄存器、控制逻辑、振荡器、实时时钟及31B的RAM组成。
在数据传送前,必须把RST置为高电平,且把提供地址和命令信息的8位装入到移位寄存器。
在进行单字节传送或多字节传送时,开始的8位命令字节用于指定40B(前31B RAM和9B时钟寄存器)中哪个将被访问。
在开始的8个时钟周期把命令装入移位寄存器之后,另外的时钟在读操作时输出数据,在写操作时输入数据。
DS1302的封装引脚示意图和内部结构图分别见图1和图2。
其中,X1、X2接32.768kHz 晶振,GND为地,复位线驱动至高电平,启动所有的数据传送。
DS1302时钟数码管显示DS1302时钟芯片,大家都知道是什么来的。
不懂的百度下就知道了。
这个只是读取出时间,其它功能没有写出来,用了四位共阳数码管显示。
具体电路和仿真可以到中国电子DIY之家论坛搜索/*********************************** DS1302简单时间显示** 数码管显示************************************/#include#define uchar unsigned char#define uint unsigned int#define W P2 //位选#define D P0 //段选sbit IO=P1^0; //数据口sbit SCLK=P1^1; //控制数据时钟sbit RST=P1^2; //使能端、复位端/************按键引脚定义***********/sbit s1=P1^5; //按键加sbit s2=P1^6; //按键减sbit s3=P1^7; //按键选择char knum=0,snum,fnum;/***********写时分秒地址************/#define write_shi 0x84#define write_fen 0x82#define write_miao 0x80/***********读时分秒地址************/#define read_shi 0x85#define read_fen 0x83#define read_miao 0x81char shi,fen,miao; //读出数据存储变量uchard[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xd8,0x80,0x90}; //不带小数点uchardd[]={0x40,0x79,0x24,0x30,0x19,0x12,0x02,0x78,0x00,0x10}; //带小数点void delay(uint z) //延时函数,z的取值为这个函数的延时ms数,如delay(200);大约延时200ms.{ //delay(500);大约延时500ms.uint x,y;for(x=z;x>0;x--)for(y=110;y>0;y--);}uchar read_1302(uchar add) //读函数{uchar i,date;RST=0; //禁止读写数据for(i=0;i<8;i++){RST=1;SCLK=0;IO=add&0x01;add>>=1;SCLK=1;}for(i=0;i<8;i++){if(IO)date=date|0x80;elsedate=date|0x00;SCLK=1;date>>=1;SCLK=0;}RST=0;date=date/16*10+date%16; //进制转换16转10进制IO=0; //数据读完后,IO口必须为0,不然小时一直显示85 return date;}void write_1302(uchar add,uchar dat) //写函数{uchar i;RST=0; //禁止读写数据// SCLK=0;for(i=0;i<8;i++) //写地址{RST=1; //允许读写数据SCLK=0;IO=add&0x01;add>>=1;SCLK=1;}for(i=0;i<8;i++) //写数据{RST=1; //允许读写数据SCLK=0;IO=dat&0x01;dat>>=1;SCLK=1;}RST=0;}void init_1302() //初始化函数设置时间{write_1302(0x8e,0x00); //保护取消,可以进行读写操作write_1302(write_miao,0x56);write_1302(write_fen,0x49);write_1302(write_shi,0x14);write_1302(0x8e,0x80); //保护启动,不能进行读写操作}void display(uchar shi,uchar fen,uchar miao) //显示函数{if(knum==0){snum=30;fnum=30;}if(knum==1){fnum++;snum=30;}if(knum==2){snum++;fnum=30;}if(snum>=30){W=0x01; //位选D=d[shi/10]; //段选delay(5);D=0XFF; //消隐if(miao%2==0) //小数点闪烁{W=0x02;D=dd[shi%10];delay(5);D=0XFF; //消隐}else{W=0x02;D=d[shi%10];delay(5);D=0XFF; //消?}if(snum==60)snum=0;}if(fnum>=30){W=0x04;D=d[fen/10];delay(5);D=0XFF; //消隐W=0x08;D=d[fen%10];delay(5);D=0XFF; //消隐if(fnum==60)fnum=0;}}void read_sf(){shi=read_1302(read_shi);fen=read_1302(read_fen);miao=read_1302(read_miao);display(shi,fen,miao);}void keyscan() //按键扫描函数{if(s3==0) //选择按键按下{delay(10);if(s3==0){while(!s3)display(shi,fen,miao); //加上这句,按键按下就不会闪knum++; if(knum==1) //分闪烁{write_1302(0x8e,0x00); //保护取消write_1302(write_miao,0x80);}if(knum==3) //时钟启动{knum=0;write_1302(write_miao,0x00);write_1302(0x8e,0x80); //保护启动}}}if(knum==1) //分钟调节{if(s1==0) //加{delay(10);if(s1==0){while(!s1)display(shi,fen,miao); //加上这句,按键按下就不会闪fen++; fen=fen/10*16+fen%10; //转为16进制if(fen==0x60)fen=0x00;write_1302(write_fen,fen); //写入1302read_sf(); //读出时间,然后显示}}if(s2==0){delay(10);if(s2==0){while(!s2)display(shi,fen,miao); //加上这句,按键按下就不会闪fen--; fen=fen/10*16+fen%10; //转为16进制if(fen==-1)fen=0x59;write_1302(write_fen,fen);read_sf();}}}if(knum==2){if(s1==0){delay(10);if(s1==0){while(!s1)display(shi,fen,miao); //加上这句,按键按下就不会闪shi++; shi=shi/10*16+shi%10; //转为16进制if(shi==0x24)shi=0x00;write_1302(write_shi,shi);read_sf();}}if(s2==0){delay(10);if(s2==0){while(!s2)display(shi,fen,miao); //加上这句,按键按下就不会闪shi--;shi=shi/10*16+shi%10; //转为16进制if(shi==-1)shi=0x23;write_1302(write_shi,shi);read_sf();}}}}void main(){// init_1302();while(1){read_sf();keyscan();}}。
用ds1302制作一个精密的电子时钟感想:我看视频的时候讲的是DS12CR887这块芯片,两块毕竟是不一样的,所以,我只是看了他讲怎样看时序,之后的就没再看了。
我就拿着自己下载打印的DS1302数据手册,研习,研习,再研习。
还查了书上的,网上的,源程序。
但是,你别指望着谁会把所有的东西都给你写上去。
只能作为参考。
后来,我终于写出了一个程序,可是一编译,就漏洞百出。
最主要的有两点:for循环和BCD码。
不过还好,都得到了很好的解决。
解决方案:#include#include#define uchar unsigned char#define uint unsigned intuchar data table[]="2009-01-01 Mon.";uchar data table1[]=" 00:00:00";uchar code xingqi[]="Mon. Tue. Wed. Thu. Fri. Sat. Sun.";uchar num;uchar hour,min,sec,week,day,month,year;sbit ds1302_sclk=P1^4;sbit ds1302_io=P1^5;sbit ds1302_ce=P2^2;sbit acc0=ACC^0;sbit acc7=ACC^7;sbit lcdrs=P1^7; //端口定义sbit lcdrw=P1^6;sbit lcde=P2^4;sbit le=P3^ 6;sbit led en=P2^5;sbit dkle=P3^7;void delay(uint a);void write_byte(uchar dat) //写入一个字节{uchar i;ACC=dat;for(i=8;i>0;i--){ds1302_io=acc0;ds1302_sclk=1;ds1302_sclk=0;ACC=ACC>>1;}}uchar read_byte() //读出一个字节{uchar i;for(i=8;i>0;i--){ACC=ACC>>1;acc7=ds1302_io;ds1302_sclk=1;ds1302_sclk=0;}return(ACC);}void s_write(uchar add,uchar dat)//单字节写入子函数{ds1302_ce=0;ds1302_sclk=0;ds1302_ce=1;write_byte(add);write_byte(dat);ds1302_sclk=1;ds1302_ce=0;}uchar s_read(uchar add) //单字节读出子函数{uchar temp;ds1302_ce=0;ds1302_sclk=0;ds1302_ce=1;write_byte(add);temp=read_byte();ds1302_sclk=1;ds1302_ce=0;temp=(temp/0x0a)*10+temp%0x0a;return(temp);}void set_ds1302(uchar *pClock) //设置ds1302的时间{uchar i;uchar add=0x80;EA=0;s_write(0x8e,0x00);for(i=7;i>0;i--){s_write(add,*pClock);pClock++;add+=2;}s_write(0x8e,0x80);EA=1;}void read_ds1302(uchar Curtime[]) //读取ds1302的时间{uchar i;uchar add=0x81;EA=0;for(i=7;i>0;i--){Curtime[i]=s_read(add);add+=2;}EA=1;}void write_com(uchar com) //写命令子函数{lcde=0;lcdrw=0;lcdrs=0;delay(1);lcde=1;delay(1);P0=com;delay(1);lcde=0;}void write_data(uchar dat) //写数据子函数{lcde=0;lcdrw=0;lcdrs=1;delay(1);lcde=1;delay(1);P0=dat;delay(1);lcde=0;}void init(){month=1;day=1;year=9;lcde=0; //LCD1602初始化le=0;leden=0;write_com(0x38);delay(100);write_com(0x38);delay(50);write_com(0x38);delay(10);write_com(0x08);write_com(0x01);write_com(0x0c);write_com(0x80);for(num=0;num<15;num++) //在第一行显示“ 2000-00-00 Mon.”{write_data(table[num]);}write_com(0x80+0x40);for(num=0;num<10;num++) //在第二行末尾显示“00:00:00”{write_data(table1[num]);}}void write_time(uchar add,uchar dat) //写入时间子函数{uchar shi,ge;shi=dat/16;ge=dat%16;write_com(0x80+0x40+add);write_data(0x30+shi);write_data(0x30+ge);}void write_riqi(uchar add,uchar dat) //写入日期子函数{uchar shi,ge;shi=dat/16;ge=dat%16;write_com(0x80+add);write_data(0x30+shi);write_data(0x30+ge);}void write_xingqi(uchar dat) //写入星期子函数{write_com(0x80+0x0b);switch(dat){case 1: for(num=0;num<4;num++){write_data(xingqi[num]);};break;case 2: for(num=5;num<9;num++){write_data(xingqi[num]);};break;case 3: for(num=10;num<14;num++){write_data(xingqi[num]);};break;case 4: for(num=15;num<19;num++){write_data(xingqi[num]);};break;case 5: for(num=20;num<24;num++){write_data(xingqi[num]);};break;case 6: for(num=25;num<29;num++){write_data(xingqi[num]);};break;case 7: for(num=30;num<34;num++){write_data(xingqi[num]);};break;}}void main(){init();delay(5);s_write(0x8e,0x00); //控制写入WP=0 s_write(0x90,0xa5);s_write(0x80,0x00); //秒s_write(0x82,0x20); //分s_write(0x84,0x09); //时24时制s_write(0x86,0x27); //日s_write(0x88,0x08); //月s_write(0x8a,0x04); //星期s_write(0x8c,0x09); //年 */s_write(0x8e,0x80);//控制写入WP=1;P0=0xff;while(1){sec=s_read(0x81);write_time(8,sec);write_com(0x80+0x40+9);min=s_read(0x83);write_time(5,min);write_com(0x80+0x40+6);hour=s_read(0x85);write_time(2,hour);write_com(0x80+0x40+3); week=s_read(0x8b);write_xingqi(week);write_com(0x80+0x0d);day=s_read(0x87);write_riqi(8,day);write_com(0x80+9);month=s_read(0x89);write_riqi(5,month);write_com(0x80+6);year=s_read(0x8d);write_riqi(2,year);write_com(0x80+3);}}void delay(uint a) { //延时子函数uint i,j;for(j=a;j>0;j--)for(i=250;i>0;i--) ;}。
一、概述二、51单片机,TM1638芯片+DS1302驱动共阴数码管时钟,最后包括按键检测程序(是分开的。
)TM1638是带键盘扫描接口的LED(发光二极管显示器)驱动控制专用电路,内部集成有MCU 数字接口、数据锁存器、LED 高压驱动、键盘扫描等电路。
主要应用于冰箱、空调、家庭影院等产品的高段位显示屏驱动。
二、特性说明•采用功率CMOS 工艺•显示模式 10 段×8 位•键扫描(8×3bit)•辉度调节电路(占空比8 级可调)•串行接口(CLK,STB,DIO)•振荡方式:RC 振荡(450KHz+5%)•内置上电复位电路•采用SOP28封装三、、管脚定义:电路图数码管:程序代码:/*************** TM1638.H头文件*******************/#ifndef _TM1638_H#define _TM1638_H//引脚定义sbit DIO=P1^0;sbit CLK=P1^1;sbit STB=P1^2;void TM1638_Write(unsigned char DATA) //写数据函数{unsigned char i;for(i=0;i<8;i++){CLK=0;if(DATA&0X01)DIO=1;elseDIO=0;DATA>>=1;CLK=1;}}/*unsigned char TM1638_Read(void) //读数据函数{unsigned char i;unsigned char temp=0;DIO=1; //设置为输入for(i=0;i<8;i++){temp>>=1;CLK=0;if(DIO)temp|=0x80;CLK=1;}return temp;} */void Write_COM(unsigned char cmd) //发送命令字{STB=0;TM1638_Write(cmd);STB=1;}void Write_DATA(unsigned char add,unsigned char DA TA) //指定地址写入数据{Write_COM(0x44);STB=0;TM1638_Write(0xc0|add);TM1638_Write(DA TA);STB=1;}void init_TM1638(void){unsigned char i;Write_COM(0x8a);//亮度Write_COM(0x40); //写数据命令STB=0;TM1638_Write(0xc0); //写地址命令for(i=0;i<16;i++)TM1638_Write(0x00);STB=1;}#endif/***************************DS1302.H头文件***************************/#ifndef DS1302_H#define DS1302_H#define uchar unsigned char#define uint unsigned int#include"DELAY.h"sbit acc0=ACC^0; //移位时的第0位sbit acc7=ACC^7; //移位时用的第7位uchar second,minute,hour,day,month,year,week,count=0;uchar ReadValue,num,time;sbit SCLK=P2^0;sbit DATA=P2^1;sbit RST=P2^2;void Write1302(uchar dat){uchar i;SCLK=0; //拉低SCLK,为脉冲上升沿写入数据做好准备delay1(2); //稍微等待,使硬件做好准备for(i=0;i<8;i++) //连续写8个二进制位数据{DATA=dat&0x01; //取出dat的第0位数据写入1302delay(2); //稍微等待,使硬件做好准备SCLK=1; //上升沿写入数据delay1(2); //稍微等待,使硬件做好准备SCLK=0; //重新拉低SCLK,形成脉冲dat>>=1; //将dat的各数据位右移1位,准备写入下一个数据位}}void WriteSet1302(uchar Cmd,uchar dat){RST=0; //禁止数据传递SCLK=0; //确保写数居前SCLK被拉低RST=1; //启动数据传输delay1(2); //稍微等待,使硬件做好准备Write1302(Cmd); //写入命令字Write1302(dat); //写数据SCLK=1; //将时钟电平置于已知状态RST=0; //禁止数据传递}uchar Read1302(void){uchar i,dat;delay(2); //稍微等待,使硬件做好准备for(i=0;i<8;i++) //连续读8个二进制位数据{dat>>=1; //将dat的各数据位右移1位,因为先读出的是字节的最低位if(DATA==1) //如果读出的数据是1dat|=0x80; //将1取出,写在dat的最高位SCLK=1; //将SCLK置于高电平,为下降沿读出delay1(2); //稍微等待SCLK=0; //拉低SCLK,形成脉冲下降沿delay1(2); //稍微等待}return dat; //将读出的数据返回}uchar ReadSet1302(uchar Cmd){uchar dat;RST=0; //拉低RSTSCLK=0; //确保写数居前SCLK被拉低RST=1; //启动数据传输Write1302(Cmd); //写入命令字dat=Read1302(); //读出数据SCLK=1; //将时钟电平置于已知状态RST=0; //禁止数据传递return dat; //将读出的数据返回}void Init_DS1302(void){WriteSet1302(0x8E,0x00); //根据写状态寄存器命令字,写入不保护指令WriteSet1302(0x80,((0/10)<<4|(0%10))); //根据写秒寄存器命令字,写入秒的初始值WriteSet1302(0x82,((41/10)<<4|(41%10))); //根据写分寄存器命令字,写入分的初始值WriteSet1302(0x84,((15/10)<<4|(15%10))); //根据写小时寄存器命令字,写入小时的初始值WriteSet1302(0x86,((29/10)<<4|(24%10))); //根据写日寄存器命令字,写入日的初始值WriteSet1302(0x88,((2/10)<<4|(2%10))); //根据写月寄存器命令字,写入月的初始值WriteSet1302(0x8c,((10/10)<<4|(11%10))); //nianWriteSet1302(0x8a,((0/10)<<4|(0%10)));WriteSet1302(0x8E,0x80); //根据写状态寄存器命令字,写入保护指令}#endif/***************显示头文件*******************************/#include"TM1638.h"uchar data DisBuffer[8]={0,0,0,0,0,0,0,0}; /*显示缓存区*/ //各个数码管显示的值uchar code tab[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x77,0x7C,0x39,0x5E,0x79,0x71 ,0x40,0xef};void display1638(uchar hour,uchar minute,uchar second){uchar i;DisBuffer[0]=hour/10;DisBuffer[1]=hour%10;DisBuffer[3]=minute/10;DisBuffer[4]=minute%10;DisBuffer[6]=second/10;DisBuffer[7]=second%10;DisBuffer[2]=16;DisBuffer[5]=16;for(i=0;i<8;i++){Write_DATA(i*2,tab[DisBuffer[i]]);}}void DisplayHour(newval){DisBuffer[0]=newval/10;DisBuffer[1]=newval%10;for(i=0;i<2;i++){Write_DATA(i*2,tab[DisBuffer[i]]);}}#endif/**********************************************************///下面是处理程序头文件,调试功能的实现,但是本人接调时的来源是//是鼠标芯片,所以这里都写上,各位可以根据自己是按键还是其他的,做修改/***********************************************/#ifndef CHULI_H#define CHULI_H#define uchar unsigned char#define uint unsigned int#include"DISPLAY.h"#include"DS1302.h"void read_date(void){ReadValue = ReadSet1302(0x81);second=((ReadValue&0x70)>>4)*10 + (ReadV alue&0x0F);ReadValue = ReadSet1302(0x83);minute=((ReadValue&0x70)>>4)*10 + (ReadV alue&0x0F);ReadValue = ReadSet1302(0x85);hour=((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);ReadValue = ReadSet1302(0x87);day=((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);ReadValue = ReadSet1302(0x89);month=((ReadValue&0x70)>>4)*10 + (ReadV alue&0x0F);ReadValue = ReadSet1302(0x8d);year=((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);ReadValue=ReadSet1302(0x8b); //读星期week=ReadValue&0x07;display1638(hour,minute,second) ;}void turn_val(char newval,uchar flag,uchar newaddr,uchar s1num){newval=ReadSet1302(newaddr); //读取当前时间newval=((newval&0x70)>>4)*10+(newval&0x0f); //将bcd码转换成十进制if(flag) //判断是加一还是减一{newval++;switch(s1num){ case 1: if(newval>99) newval=0;DisplayYear(newval);break;case 2: if(newval>12) newval=1;DisplayMonth(newval);break;case 3: if(newval>31) newval=1;DisplayDay(newval);break;case 4: if(newval>6) newval=0;DisplayWeek(newval);break;case 5: if(newval>23) newval=0;DisplayHour(newval);break;case 6: if(newval>59) newval=0;DisplayMinute(newval);break;case 7: if(newval>59) newval=0;DisplaySecond(newval);break;default:break;}}else{newval--;switch(s1num){ case 1: if(newval==0) newval=99;DisplayYear(newval);break;case 2: if(newval==0) newval=12;DisplayMonth(newval);break;case 3: if(newval==0) newval=31;DisplayDay(newval);break;case 4: if(newval<0) newval=6;DisplayWeek(newval);break;case 5: if(newval<0) newval=23;DisplayHour(newval);break;case 6: if(newval<0) newval=59;DisplayMinute(newval);break;case 7: if(newval<0) newval=59;DisplaySecond(newval);break;default:break;}}WriteSet1302((newaddr-1),((newval/10)<<4)|(newval%10)); //将新数据写入寄存器}void write_flsh(uchar com,uchar dat){ Write_DATA(com,tab[16]);delay(100);Write_DATA(com,tab[dat]);}void sp2_mouse(void){uchar miao,z,flag=0;rd=0;miao=ReadSet1302(0x81);second=miao;WriteSet1302(0x80,miao|0x80);while(1){ led=0;////////////////////////////////////////* if((move_x<4)&&(flag==0)){write_flash(0x02,1) ;if((mouse_data[0]&0x01)&&(flag==1)){while(mouse_data[0]&0x01);while(1){ write_flash(0x02,1) ;z=move_x;if(move_x>z){ delayms(10);turn_val(year,1,0x8d,1);}if(z>move_x){delayms(10);turn_val(year,0,0x8d,1);}if(mouse_data[0]&0x01){while(mouse_data[0]&0x01);flag=1;move_x=3;z=move_x;break;}}}}///////////////////////////////////////////////////////if((move_x>=4)&&(move_x<6)&&(flag==0)){write_com(0x87);if(mouse_data[0]&0x01){while(mouse_data[0]&0x01);while(1){ z=move_x;write_com(0x87);if(move_x>z){ delayms(10);turn_val(month,1,0x89,2);}if(z>move_x){delayms(10);turn_val(month,0,0x89,2);}if(mouse_data[0]&0x01){while(mouse_data[0]&0x01);flag=1;move_x=5;z=move_x;break;}}}}/////////////////////////////////////////////////////////if((move_x>=6)&&(move_x<8)&&(flag==0)){write_com(0x8a);if(mouse_data[0]&0x01){while(mouse_data[0]&0x01);while(1){z=move_x;write_com(0x8a);if(move_x>z){ delayms(10);turn_val(day,1,0x87,3);}if(z>move_x){ delayms(10);turn_val(day,0,0x87,3);}if(mouse_data[0]&0x01){while(mouse_data[0]&0x01);flag=1;move_x=7;z=move_x;break;}}}}///////////////////////////////////////////////////////////if((move_x>=8)&&(move_x<10)&&(flag==0)){write_com(0x8e);if(mouse_data[0]&0x01){while(mouse_data[0]&0x01);while(1){z=move_x;write_com(0x8e);if(move_x>z){ delayms(10);turn_val(week,1,0x8b,4);}if(z>move_x){delayms(10);turn_val(week,0,0x8b,4);}if(mouse_data[0]&0x01){while(mouse_data[0]&0x01);flag=1;move_x=9;z=move_x;break;}}}} */////////////////////////////////////////////////////////////if((move_x>=10)&&(move_x<12)&&(flag==0)){write_flash(0x02,1) ;if(mouse_data[0]&0x01){while(mouse_data[0]&0x01);while(1){z=move_x;write_flash(0x02,1) ;if(move_x>z){ delayms(10);turn_val(hour,1,0x85,5);}if(z>move_x){ delayms(10);turn_val(hour,0,0x85,5);}if(mouse_data[0]&0x01){while(mouse_data[0]&0x01);flag=1;move_x=11;z=move_x;break;}}}}//////////////////////////////////////////////////////////////if((move_x>=12)&&(move_x<14)&&(flag==0)){write_com(0xc4) ;if(mouse_data[0]&0x01){while(mouse_data[0]&0x01);while(1){z=move_x;write_com(0xc4) ;if(move_x>z){ delayms(10);turn_val(minute,1,0x83,6); //写入分寄存器}if(z>move_x){delayms(10);turn_val(minute,0,0x83,6); //写入分寄存器}if(mouse_data[0]&0x01){while(mouse_data[0]&0x01);flag=1;move_x=13;z=move_x;break;}}}}////////////////////////////////////////////////////////////////if((move_x>=14)&&(flag==0)){write_com(0xc7);if(mouse_data[0]&0x01){while(mouse_data[0]&0x01);while(1){z=move_x;write_com(0xc7);if(move_x>z){ delayms(10);turn_val(second,1,0x81,7);}if(z>move_x){delayms(10);turn_val(second,0,0x81,7);}if(mouse_data[0]&0x01){while(mouse_data[0]&0x01);flag=1;move_x=15;z=move_x;break;}}}}///////////////////////////////////////////////////////////////if((mouse_data[0]&0x01)&&(z!=move_x)){flag=0;while(mouse_data[0]&0x01);}//////////////////////////////////////////////////////////////if((mouse_data[0]&0x01)&&(flag==1)&&(z==move_x)){flag=0;delayms(300);miao=ReadSet1302(0x81);second=miao;WriteSet1302(0x80,second&0x7f);write_com(0x0c) ;WriteSet1302(0x8E,0x80); //根据写状态寄存器命令字,写入不保护指令break;}}}#endif/*********鼠标芯片*****/#ifndef PS2_H#define PS2_H#include"DELAY.h"sbit mouse_SDA=P3^4;//数据线P3_5 计数器0输入端口sbit mouse_CLK=P3^3;//时钟线P3_3 外部中断1输入端口sbit led=P3^6;bit pp=0;bit ACK=0;uchar bdata mouse_byte; //接收字节bdata-->可寻址的片内RAMsbit mouse_byte_bit0=mouse_byte^0;//mouse_byte第0位sbit mouse_byte_bit1=mouse_byte^1;//mouse_byte第1位sbit mouse_byte_bit2=mouse_byte^2;//mouse_byte第2位sbit mouse_byte_bit3=mouse_byte^3;//mouse_byte第3位sbit mouse_byte_bit4=mouse_byte^4;//mouse_byte第4位sbit mouse_byte_bit5=mouse_byte^5;//mouse_byte第5位sbit mouse_byte_bit6=mouse_byte^6;//mouse_byte第6位sbit mouse_byte_bit7=mouse_byte^7;//mouse_byte第7位uchar mouse_buffer[11];//接收位数据缓冲区uchar mouse_buffer_bit=0;//mouse_buffer[mouse_buffer_bit]uchar mouse_data[4];//接收鼠标数据缓冲区,分别存放:功能信息字节,x位移量,y位移量uchar mouse_data_bit=0;//mouse_data[mouse_data_bit]uchar move_x;//存放横坐标uint move_y;//存放纵坐标uchar move_z;extern uchar move_x;/*********************************************************************** 发送数据************************************************************************/void Init_ter(void){EA=1; //开放中断EX1=1;//允许外部中断1PX1=1;//设置中断优先级设外部中断1为最高优先级别}void host_to_mouse(uchar cmd){uchar i;EX1=0;mouse_CLK=0;delay100;delay100;ACC=cmd;pp=~P; //获得奇偶校验位mouse_SDA=0;mouse_CLK=1;for(i=0;i<8;i++){while(mouse_CLK==1);mouse_SDA=cmd&0x01;cmd>>=1;while(mouse_CLK==0);}while(mouse_CLK==1);mouse_SDA=pp; //发送奇偶校验位while(mouse_CLK==0);while(mouse_CLK==1);mouse_SDA=1;while(mouse_CLK==0);while(mouse_CLK==1);ACK=mouse_SDA; //接收应答位while(mouse_CLK==0);EX1=1;}void Init_mouse(void){host_to_mouse(0xf4);delayms(50);Init_ter();delayms(50);host_to_mouse(0xf3);delayms(50);host_to_mouse(0xc8);delayms(50);host_to_mouse(0xf3);delayms(50);host_to_mouse(0x64);delayms(50);host_to_mouse(0xf3);delayms(50);host_to_mouse(0x50);delayms(50);host_to_mouse(0xf2);delayms(200);mouse_data[0]=0;mouse_data[1]=0;mouse_data[2]=0;mouse_data[3]=0;move_x=10;move_y=0;move_z=0;}/*********************************************奇校检**********************************************/uchar Checkout(void){ACC=mouse_byte;if(~P==mouse_buffer[9])return 1;elsereturn 0;}/********************************************************* 数据分析及处理**********************************************************/ void data_analyse(void){//将收到的11位信号中截取8位数据放进mouse_bytemouse_byte_bit0=mouse_buffer[1];mouse_byte_bit1=mouse_buffer[2];mouse_byte_bit2=mouse_buffer[3];mouse_byte_bit3=mouse_buffer[4];mouse_byte_bit4=mouse_buffer[5];mouse_byte_bit5=mouse_buffer[6];mouse_byte_bit6=mouse_buffer[7];mouse_byte_bit7=mouse_buffer[8];if(Checkout())//如果校验正确{if(mouse_data_bit<4)mouse_data[mouse_data_bit++]=mouse_byte;if(mouse_data_bit==4){mouse_data_bit=0;if(mouse_data[0]&0x10)//如果"X sign bit"为1,表示鼠标向右左移{move_x-=(256-mouse_data[1]);//x坐标减if(move_x<=1)move_x=17;}else{move_x+=mouse_data[1];//x坐标加if(move_x>=17)move_x=2;}if(mouse_data[0]&0x20){move_y-=(256-mouse_data[2]);//y坐标减}else{move_y+=mouse_data[2];//y坐标加}if(mouse_data[3]&0x08){move_z-=(16-(mouse_data[3]&0x0f));}else{mouse_data[3]=mouse_data[3]&0x0f;move_z+=mouse_data[3]; //Z坐标加}}}}/**************************************************外部中断1***************************************************/void ReceiveData(void) interrupt 2{ led=0;if(mouse_buffer_bit<=10){while(mouse_CLK==0);//等待设备拉高时钟线mouse_buffer[mouse_buffer_bit++]=mouse_SDA;//接收数据}if(mouse_buffer_bit==10){data_analyse();//数据分析及处理mouse_buffer_bit=0;}}#endif////////////////////////////////主函数部分//////////////////////////////////////////////////// #include<reg51.h>#include"TM1638.h"#include"DS1302.h"#include"DELAY.h"#include"CHULI.h"#include"DISPLAY.h"void main(){delayms(500);init_TM1638();delayms(50);Init_DS1302(); //将1302初始化delay(500);while(1){read_date();delayms(50);}}/**********************************************/再来一个按键测试的程序:这个是另外的,与上面的无关;#ifndef _TM1638_H#define _TM1638_H#include <REGX51.H>#define DATA_COMMAND 0X40#define DISP_COMMAND 0x80#define ADDR_COMMAND 0XC0//引脚定义sbit DIO=P1^0;sbit CLK=P1^1;sbit STB=P1^2;unsigned char code tab[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x77,0x7C,0x39,0x5E,0x79,0x71 ,0x40};void TM1638_Write(unsigned char DATA) //写数据函数{unsigned char i;for(i=0;i<8;i++){CLK=0;if(DATA&0X01)DIO=1;elseDIO=0;DATA>>=1;CLK=1;}}unsigned char TM1638_Read(void) //读数据函数{unsigned char i;unsigned char temp=0;DIO=1; //设置为输入for(i=0;i<8;i++){temp>>=1;CLK=0;if(DIO)temp|=0x80;CLK=1;}return temp;}void Write_COM(unsigned char cmd) //发送命令字{STB=0;TM1638_Write(cmd);STB=1;}unsigned char Read_key(void){unsigned char c[4],i,key_value=0;STB=0;TM1638_Write(0x42);for(i=0;i<4;i++)c[i]=TM1638_Read();STB=1; //4个字节数据合成一个字节for(i=0;i<4;i++)key_value|=c[i];for(i=0;i<4;i++)if(c[i]==key_value)break;return (i*8+key_value);}void Write_DATA(unsigned char add,unsigned char DA TA) //指定地址写入数据{Write_COM(0x44);STB=0;TM1638_Write(0xc0|add);TM1638_Write(DA TA);STB=1;}/*void Write_oneLED(unsigned char num,unsigned char flag) //单独控制一个LED函数,num 为需要控制的led序号,flag为0时熄灭,不为0时点亮{if(flag)Write_DATA(2*num+1,1);elseWrite_DATA(2*num+1,0);}void Write_allLED(unsigned char LED_flag) //控制全部LED函数,LED_flag表示各个LED状态{unsigned char i;for(i=0;i<8;i++){if(LED_flag&(1<<i))Write_DATA(2*i+1,3);elseWrite_DATA(2*i+1,0);}} */void init_TM1638(void){unsigned char i;Write_COM(0x8a);//亮度Write_COM(0x40);STB=0;TM1638_Write(0xc0);for(i=0;i<16;i++)TM1638_Write(0x00);STB=1;}#endif#include <at89x51.H>#include <tm1638.h>#include "555.h"unsigned char num[8]; //各个数码管显示的值unsigned char x=0xff;sbit key=P3^4;int main(void){init_TM1638();system_init();display(x);delay_ms(200);display1638();while(1){display1638();// detectkey();x=Read_key();display(~x);}}void display1638(){ uchar i;if(sec_flag|i){num[0]=hour/10;num[1]=hour%10;num[3]=minute/10;num[4]=minute%10;num[6]=second/10;num[7]=second%10;num[2]=16;num[5]=16;for(i=0;i<8;i++){Write_DATA(i*2,tab[num[i]]);}}}#ifndef _555_H#define _555_H#include<at89x51.h>#define uchar unsigned charvoid delay_ms(uchar);void display();void detectkey();void display1638();uchar code tap[10]={0xC0,/*0*/0xF9,/*1*/0xA4,/*2*/0xB0,/*3*/0x99,/*4*/0x92,/*5*/0x82,/*6*/0xF8,/*7*/0x80,/*8*/0x90,/*9*/};sbit key_hour=P3^5;sbit key_min=P3^6;uchar hour=12;uchar minute=0;uchar second=0;uchar flag=0;uchar sec_flag=0;/************************* 初始化程序**************************/ void system_init(){ TMOD=0x01;EA=1;ET0=1;EX0=1;IT0=1;TR0=1;TH0=(65536-50000)/256;TL0=(65536-50000)%256;}/************************* 定时器中断0中断处理程序**************************/ void int1_ISR() interrupt 1 {TH0=(65536-50000)/256;TL0=(65536-50000)%256;flag++;if(flag==20){sec_flag=1;second++;flag=0;}if(second==60){second=0;minute++;}if(minute==60){minute=0;hour++;hour%=24;}}/************************* 按键程序**************************/ void detectkey(){delay_ms(10);if(key_hour==0){hour++;hour=hour%24;while(!key_hour)display();}if(key_min==0){minute++;minute=minute%60;while(!key_min)display();}if(P3_7==0){hour=12;minute=0;second=0;while(!P3_5)display();}}/*************************显示程序**************************/void display(uchar i){P0=i;}/*************************延时处理程序**************************/void delay_ms(uchar no){uchar i,j;for(i=0;i<no;i++){for(j=0;j<164;j++);for(j=0;j<164;j++);}}#endif说明:按键值送P0接的LED显示。
一、概述二、51单片机,TM1638芯片+DS1302驱动共阴数码管时钟,最后包括按键检测程序(是分开的。
)TM1638是带键盘扫描接口的LED(发光二极管显示器)驱动控制专用电路,内部集成有MCU 数字接口、数据锁存器、LED 高压驱动、键盘扫描等电路。
主要应用于冰箱、空调、家庭影院等产品的高段位显示屏驱动。
二、特性说明•采用功率CMOS 工艺•显示模式 10 段×8 位•键扫描(8×3bit)•辉度调节电路(占空比8 级可调)•串行接口(CLK,STB,DIO)•振荡方式:RC 振荡(450KHz+5%)•内置上电复位电路•采用SOP28封装三、、管脚定义:电路图数码管:程序代码:/*************** TM1638.H头文件*******************/#ifndef _TM1638_H#define _TM1638_H//引脚定义sbit DIO=P1^0;sbit CLK=P1^1;sbit STB=P1^2;//写一个8Bit数据void TM1638_Write(unsigned char DATA) //写数据函数{unsigned char i;for(i=0;i<8;i++){CLK=0;if(DATA&0X01)DIO=1;elseDIO=0;DATA>>=1;CLK=1;}}/*unsigned char TM1638_Read(void) //读数据函数{unsigned char i;unsigned char temp=0;DIO=1; //设置为输入for(i=0;i<8;i++){temp>>=1;CLK=0;if(DIO)temp|=0x80;CLK=1;}return temp;} */void Write_COM(unsigned char cmd) //发送命令字{STB=0;TM1638_Write(cmd); //写命令STB=1;}void Write_DATA(unsigned char add,unsigned char DA TA) //指定地址写入数据{Write_COM(0x44);STB=0;TM1638_Write(0xc0|add); //地址高位为1:11** ****,写地址TM1638_Write(DA TA);STB=1;}void init_TM1638(void){unsigned char i;Write_COM(0x8a);//亮度Write_COM(0x40); //写数据命令,写数据到显示寄存器STB=0;TM1638_Write(0xc0); //写地址命令for(i=0;i<16;i++)TM1638_Write(0x00);STB=1;}#endif/***************************DS1302.H头文件***************************/#ifndef DS1302_H#define DS1302_H#define uchar unsigned char#define uint unsigned int#include"DELAY.h"sbit acc0=ACC^0; //移位时的第0位sbit acc7=ACC^7; //移位时用的第7位uchar second,minute,hour,day,month,year,week,count=0;uchar ReadValue,num,time;sbit SCLK=P2^0;sbit DATA=P2^1;sbit RST=P2^2;void Write1302(uchar dat){uchar i;SCLK=0; //拉低SCLK,为脉冲上升沿写入数据做好准备delay1(2); //稍微等待,使硬件做好准备for(i=0;i<8;i++) //连续写8个二进制位数据{DATA=dat&0x01; //取出dat的第0位数据写入1302delay(2); //稍微等待,使硬件做好准备SCLK=1; //上升沿写入数据delay1(2); //稍微等待,使硬件做好准备SCLK=0; //重新拉低SCLK,形成脉冲dat>>=1; //将dat的各数据位右移1位,准备写入下一个数据位}}void WriteSet1302(uchar Cmd,uchar dat){RST=0; //禁止数据传递SCLK=0; //确保写数居前SCLK被拉低RST=1; //启动数据传输delay1(2); //稍微等待,使硬件做好准备Write1302(Cmd); //写入命令字Write1302(dat); //写数据SCLK=1; //将时钟电平置于已知状态RST=0; //禁止数据传递}uchar Read1302(void){uchar i,dat;delay(2); //稍微等待,使硬件做好准备for(i=0;i<8;i++) //连续读8个二进制位数据{dat>>=1; //将dat的各数据位右移1位,因为先读出的是字节的最低位if(DATA==1) //如果读出的数据是1dat|=0x80; //将1取出,写在dat的最高位SCLK=1; //将SCLK置于高电平,为下降沿读出delay1(2); //稍微等待SCLK=0; //拉低SCLK,形成脉冲下降沿delay1(2); //稍微等待}return dat; //将读出的数据返回}uchar ReadSet1302(uchar Cmd){uchar dat;RST=0; //拉低RSTSCLK=0; //确保写数居前SCLK被拉低RST=1; //启动数据传输Write1302(Cmd); //写入命令字dat=Read1302(); //读出数据SCLK=1; //将时钟电平置于已知状态RST=0; //禁止数据传递return dat; //将读出的数据返回}void Init_DS1302(void){WriteSet1302(0x8E,0x00); //根据写状态寄存器命令字,写入不保护指令WriteSet1302(0x80,((0/10)<<4|(0%10))); //根据写秒寄存器命令字,写入秒的初始值WriteSet1302(0x82,((41/10)<<4|(41%10))); //根据写分寄存器命令字,写入分的初始值WriteSet1302(0x84,((15/10)<<4|(15%10))); //根据写小时寄存器命令字,写入小时的初始值WriteSet1302(0x86,((29/10)<<4|(24%10))); //根据写日寄存器命令字,写入日的初始值WriteSet1302(0x88,((2/10)<<4|(2%10))); //根据写月寄存器命令字,写入月的初始值WriteSet1302(0x8c,((10/10)<<4|(11%10))); //nianWriteSet1302(0x8a,((0/10)<<4|(0%10)));WriteSet1302(0x8E,0x80); //根据写状态寄存器命令字,写入保护指令}#endif/***************显示头文件*******************************/#include"TM1638.h"uchar data DisBuffer[8]={0,0,0,0,0,0,0,0}; /*显示缓存区*/ //各个数码管显示的值uchar code tab[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x77,0x7C,0x39,0x5E,0x79,0x71 ,0x40,0xef};void display1638(uchar hour,uchar minute,uchar second){uchar i;DisBuffer[0]=hour/10;DisBuffer[1]=hour%10;DisBuffer[3]=minute/10;DisBuffer[4]=minute%10;DisBuffer[6]=second/10;DisBuffer[7]=second%10;DisBuffer[2]=16;DisBuffer[5]=16;for(i=0;i<8;i++){Write_DATA(i*2,tab[DisBuffer[i]]);}}void DisplayHour(newval){DisBuffer[0]=newval/10;DisBuffer[1]=newval%10;for(i=0;i<2;i++){Write_DATA(i*2,tab[DisBuffer[i]]);}}#endif/**********************************************************///下面是处理程序头文件,调试功能的实现,但是本人接调时的来源是//是鼠标芯片,所以这里都写上,各位可以根据自己是按键还是其他的,做修改/***********************************************/#ifndef CHULI_H#define CHULI_H#define uchar unsigned char#define uint unsigned int#include"DISPLAY.h"#include"DS1302.h"void read_date(void){ReadValue = ReadSet1302(0x81);second=((ReadValue&0x70)>>4)*10 + (ReadV alue&0x0F);ReadValue = ReadSet1302(0x83);minute=((ReadValue&0x70)>>4)*10 + (ReadV alue&0x0F);ReadValue = ReadSet1302(0x85);hour=((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);ReadValue = ReadSet1302(0x87);day=((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);ReadValue = ReadSet1302(0x89);month=((ReadValue&0x70)>>4)*10 + (ReadV alue&0x0F);ReadValue = ReadSet1302(0x8d);year=((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);ReadValue=ReadSet1302(0x8b); //读星期week=ReadValue&0x07;display1638(hour,minute,second) ;}void turn_val(char newval,uchar flag,uchar newaddr,uchar s1num){newval=ReadSet1302(newaddr); //读取当前时间newval=((newval&0x70)>>4)*10+(newval&0x0f); //将bcd码转换成十进制if(flag) //判断是加一还是减一{newval++;switch(s1num){ case 1: if(newval>99) newval=0;DisplayYear(newval);break;case 2: if(newval>12) newval=1;DisplayMonth(newval);break;case 3: if(newval>31) newval=1;DisplayDay(newval);break;case 4: if(newval>6) newval=0;DisplayWeek(newval);break;case 5: if(newval>23) newval=0;DisplayHour(newval);break;case 6: if(newval>59) newval=0;DisplayMinute(newval);break;case 7: if(newval>59) newval=0;DisplaySecond(newval);break;default:break;}}else{newval--;switch(s1num){ case 1: if(newval==0) newval=99;DisplayYear(newval);break;case 2: if(newval==0) newval=12;DisplayMonth(newval);break;case 3: if(newval==0) newval=31;DisplayDay(newval);break;case 4: if(newval<0) newval=6;DisplayWeek(newval);break;case 5: if(newval<0) newval=23;DisplayHour(newval);break;case 6: if(newval<0) newval=59;DisplayMinute(newval);break;case 7: if(newval<0) newval=59;DisplaySecond(newval);break;default:break;}}WriteSet1302((newaddr-1),((newval/10)<<4)|(newval%10)); //将新数据写入寄存器}void write_flsh(uchar com,uchar dat){ Write_DATA(com,tab[16]);delay(100);Write_DATA(com,tab[dat]);}void sp2_mouse(void){uchar miao,z,flag=0;rd=0;miao=ReadSet1302(0x81);second=miao;WriteSet1302(0x80,miao|0x80);while(1){ led=0;////////////////////////////////////////* if((move_x<4)&&(flag==0)){write_flash(0x02,1) ;if((mouse_data[0]&0x01)&&(flag==1)){while(mouse_data[0]&0x01);while(1){ write_flash(0x02,1) ;z=move_x;if(move_x>z){ delayms(10);turn_val(year,1,0x8d,1);}if(z>move_x){delayms(10);turn_val(year,0,0x8d,1);}if(mouse_data[0]&0x01){while(mouse_data[0]&0x01);flag=1;move_x=3;z=move_x;break;}}}}///////////////////////////////////////////////////////if((move_x>=4)&&(move_x<6)&&(flag==0)){write_com(0x87);if(mouse_data[0]&0x01){while(mouse_data[0]&0x01);while(1){ z=move_x;write_com(0x87);if(move_x>z){ delayms(10);turn_val(month,1,0x89,2);}if(z>move_x){delayms(10);turn_val(month,0,0x89,2);}if(mouse_data[0]&0x01){while(mouse_data[0]&0x01);flag=1;move_x=5;z=move_x;break;}}}}/////////////////////////////////////////////////////////if((move_x>=6)&&(move_x<8)&&(flag==0)){write_com(0x8a);if(mouse_data[0]&0x01){while(mouse_data[0]&0x01);while(1){z=move_x;write_com(0x8a);if(move_x>z){ delayms(10);turn_val(day,1,0x87,3);}if(z>move_x){ delayms(10);turn_val(day,0,0x87,3);}if(mouse_data[0]&0x01){while(mouse_data[0]&0x01);flag=1;move_x=7;z=move_x;break;}}}}///////////////////////////////////////////////////////////if((move_x>=8)&&(move_x<10)&&(flag==0)){write_com(0x8e);if(mouse_data[0]&0x01){while(mouse_data[0]&0x01);while(1){z=move_x;write_com(0x8e);if(move_x>z){ delayms(10);turn_val(week,1,0x8b,4);}if(z>move_x){delayms(10);turn_val(week,0,0x8b,4);}if(mouse_data[0]&0x01){while(mouse_data[0]&0x01);flag=1;move_x=9;z=move_x;break;}}}} */////////////////////////////////////////////////////////////if((move_x>=10)&&(move_x<12)&&(flag==0)){write_flash(0x02,1) ;if(mouse_data[0]&0x01){while(mouse_data[0]&0x01);while(1){z=move_x;write_flash(0x02,1) ;if(move_x>z){ delayms(10);turn_val(hour,1,0x85,5);}if(z>move_x){ delayms(10);turn_val(hour,0,0x85,5);}if(mouse_data[0]&0x01){while(mouse_data[0]&0x01);flag=1;move_x=11;z=move_x;break;}}}}//////////////////////////////////////////////////////////////if((move_x>=12)&&(move_x<14)&&(flag==0)){write_com(0xc4) ;if(mouse_data[0]&0x01){while(mouse_data[0]&0x01);while(1){z=move_x;write_com(0xc4) ;if(move_x>z){ delayms(10);turn_val(minute,1,0x83,6); //写入分寄存器}if(z>move_x){delayms(10);turn_val(minute,0,0x83,6); //写入分寄存器}if(mouse_data[0]&0x01){while(mouse_data[0]&0x01);flag=1;move_x=13;z=move_x;break;}}}}////////////////////////////////////////////////////////////////if((move_x>=14)&&(flag==0)){write_com(0xc7);if(mouse_data[0]&0x01){while(mouse_data[0]&0x01);while(1){z=move_x;write_com(0xc7);if(move_x>z){ delayms(10);turn_val(second,1,0x81,7);}if(z>move_x){delayms(10);turn_val(second,0,0x81,7);}if(mouse_data[0]&0x01){while(mouse_data[0]&0x01);flag=1;move_x=15;z=move_x;break;}}}}///////////////////////////////////////////////////////////////if((mouse_data[0]&0x01)&&(z!=move_x)){flag=0;while(mouse_data[0]&0x01);}//////////////////////////////////////////////////////////////if((mouse_data[0]&0x01)&&(flag==1)&&(z==move_x)){flag=0;delayms(300);miao=ReadSet1302(0x81);second=miao;WriteSet1302(0x80,second&0x7f);write_com(0x0c) ;WriteSet1302(0x8E,0x80); //根据写状态寄存器命令字,写入不保护指令break;}}}#endif/*********鼠标芯片*****/#ifndef PS2_H#define PS2_H#include"DELAY.h"sbit mouse_SDA=P3^4;//数据线P3_5 计数器0输入端口sbit mouse_CLK=P3^3;//时钟线P3_3 外部中断1输入端口sbit led=P3^6;bit pp=0;bit ACK=0;uchar bdata mouse_byte; //接收字节bdata-->可寻址的片内RAMsbit mouse_byte_bit0=mouse_byte^0;//mouse_byte第0位sbit mouse_byte_bit1=mouse_byte^1;//mouse_byte第1位sbit mouse_byte_bit2=mouse_byte^2;//mouse_byte第2位sbit mouse_byte_bit3=mouse_byte^3;//mouse_byte第3位sbit mouse_byte_bit4=mouse_byte^4;//mouse_byte第4位sbit mouse_byte_bit5=mouse_byte^5;//mouse_byte第5位sbit mouse_byte_bit6=mouse_byte^6;//mouse_byte第6位sbit mouse_byte_bit7=mouse_byte^7;//mouse_byte第7位uchar mouse_buffer[11];//接收位数据缓冲区uchar mouse_buffer_bit=0;//mouse_buffer[mouse_buffer_bit]uchar mouse_data[4];//接收鼠标数据缓冲区,分别存放:功能信息字节,x位移量,y位移量uchar mouse_data_bit=0;//mouse_data[mouse_data_bit]uchar move_x;//存放横坐标uint move_y;//存放纵坐标uchar move_z;extern uchar move_x;/*********************************************************************** 发送数据************************************************************************/void Init_ter(void){EA=1; //开放中断EX1=1;//允许外部中断1PX1=1;//设置中断优先级设外部中断1为最高优先级别}void host_to_mouse(uchar cmd){uchar i;EX1=0;mouse_CLK=0;delay100;delay100;ACC=cmd;pp=~P; //获得奇偶校验位mouse_SDA=0;mouse_CLK=1;for(i=0;i<8;i++){while(mouse_CLK==1);mouse_SDA=cmd&0x01;cmd>>=1;while(mouse_CLK==0);}while(mouse_CLK==1);mouse_SDA=pp; //发送奇偶校验位while(mouse_CLK==0);while(mouse_CLK==1);mouse_SDA=1;while(mouse_CLK==0);while(mouse_CLK==1);ACK=mouse_SDA; //接收应答位while(mouse_CLK==0);EX1=1;}void Init_mouse(void){host_to_mouse(0xf4);delayms(50);Init_ter();delayms(50);host_to_mouse(0xf3);delayms(50);host_to_mouse(0xc8);delayms(50);host_to_mouse(0xf3);delayms(50);host_to_mouse(0x64);delayms(50);host_to_mouse(0xf3);delayms(50);host_to_mouse(0x50);delayms(50);host_to_mouse(0xf2);delayms(200);mouse_data[0]=0;mouse_data[1]=0;mouse_data[2]=0;mouse_data[3]=0;move_x=10;move_y=0;move_z=0;}/*********************************************奇校检**********************************************/uchar Checkout(void){ACC=mouse_byte;if(~P==mouse_buffer[9])return 1;elsereturn 0;}/********************************************************* 数据分析及处理**********************************************************/ void data_analyse(void){//将收到的11位信号中截取8位数据放进mouse_bytemouse_byte_bit0=mouse_buffer[1];mouse_byte_bit1=mouse_buffer[2];mouse_byte_bit2=mouse_buffer[3];mouse_byte_bit3=mouse_buffer[4];mouse_byte_bit4=mouse_buffer[5];mouse_byte_bit5=mouse_buffer[6];mouse_byte_bit6=mouse_buffer[7];mouse_byte_bit7=mouse_buffer[8];if(Checkout())//如果校验正确{if(mouse_data_bit<4)mouse_data[mouse_data_bit++]=mouse_byte;if(mouse_data_bit==4){mouse_data_bit=0;if(mouse_data[0]&0x10)//如果"X sign bit"为1,表示鼠标向右左移{move_x-=(256-mouse_data[1]);//x坐标减if(move_x<=1)move_x=17;}else{move_x+=mouse_data[1];//x坐标加if(move_x>=17)move_x=2;}if(mouse_data[0]&0x20){move_y-=(256-mouse_data[2]);//y坐标减}else{move_y+=mouse_data[2];//y坐标加}if(mouse_data[3]&0x08){move_z-=(16-(mouse_data[3]&0x0f));}else{mouse_data[3]=mouse_data[3]&0x0f;move_z+=mouse_data[3]; //Z坐标加}}}}/**************************************************外部中断1***************************************************/void ReceiveData(void) interrupt 2{ led=0;if(mouse_buffer_bit<=10){while(mouse_CLK==0);//等待设备拉高时钟线mouse_buffer[mouse_buffer_bit++]=mouse_SDA;//接收数据}if(mouse_buffer_bit==10){data_analyse();//数据分析及处理mouse_buffer_bit=0;}}#endif////////////////////////////////主函数部分//////////////////////////////////////////////////// #include<reg51.h>#include"TM1638.h"#include"DS1302.h"#include"DELAY.h"#include"CHULI.h"#include"DISPLAY.h"void main(){delayms(500);init_TM1638();delayms(50);Init_DS1302(); //将1302初始化delay(500);while(1){read_date();delayms(50);}}/**********************************************/再来一个按键测试的程序:这个是另外的,与上面的无关;#ifndef _TM1638_H#define _TM1638_H#include <REGX51.H>#define DATA_COMMAND 0X40#define DISP_COMMAND 0x80#define ADDR_COMMAND 0XC0//引脚定义sbit DIO=P1^0;sbit CLK=P1^1;sbit STB=P1^2;unsigned char code tab[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x77,0x7C,0x39,0x5E,0x79,0x71 ,0x40};void TM1638_Write(unsigned char DATA) //写数据函数{unsigned char i;for(i=0;i<8;i++){CLK=0;if(DATA&0X01)DIO=1;elseDIO=0;DATA>>=1;CLK=1;}}unsigned char TM1638_Read(void) //读数据函数{unsigned char i;unsigned char temp=0;DIO=1; //设置为输入for(i=0;i<8;i++){temp>>=1;CLK=0;if(DIO)temp|=0x80;CLK=1;}return temp;}void Write_COM(unsigned char cmd) //发送命令字{STB=0;TM1638_Write(cmd);STB=1;}unsigned char Read_key(void){unsigned char c[4],i,key_value=0;STB=0;TM1638_Write(0x42); //读取键盘值for(i=0;i<4;i++)c[i]=TM1638_Read();STB=1; //4个字节数据合成一个字节for(i=0;i<4;i++)key_value|=c[i];for(i=0;i<4;i++)if(c[i]==key_value)break;return (i*8+key_value);}void Write_DATA(unsigned char add,unsigned char DA TA) //指定地址写入数据{Write_COM(0x44);STB=0;TM1638_Write(0xc0|add);TM1638_Write(DA TA);STB=1;}/*void Write_oneLED(unsigned char num,unsigned char flag) //单独控制一个LED函数,num 为需要控制的led序号,flag为0时熄灭,不为0时点亮{if(flag)Write_DATA(2*num+1,1);elseWrite_DATA(2*num+1,0);}void Write_allLED(unsigned char LED_flag) //控制全部LED函数,LED_flag表示各个LED状态{unsigned char i;for(i=0;i<8;i++){if(LED_flag&(1<<i))Write_DATA(2*i+1,3);elseWrite_DATA(2*i+1,0);}} */void init_TM1638(void){unsigned char i;Write_COM(0x8a);//亮度Write_COM(0x40);STB=0;TM1638_Write(0xc0);for(i=0;i<16;i++)TM1638_Write(0x00);STB=1;}#endif#include <at89x51.H>#include <tm1638.h>#include "555.h"unsigned char num[8]; //各个数码管显示的值unsigned char x=0xff;sbit key=P3^4;int main(void){init_TM1638();system_init();display(x);delay_ms(200);display1638();while(1){display1638();// detectkey();x=Read_key();display(~x);}}void display1638(){ uchar i;if(sec_flag|i){num[0]=hour/10;num[1]=hour%10;num[3]=minute/10;num[4]=minute%10;num[6]=second/10;num[7]=second%10;num[2]=16;num[5]=16;for(i=0;i<8;i++){Write_DATA(i*2,tab[num[i]]);}}}#ifndef _555_H#define _555_H#include<at89x51.h>#define uchar unsigned charvoid delay_ms(uchar);void display();void detectkey();void display1638();uchar code tap[10]={0xC0,/*0*/0xF9,/*1*/0xA4,/*2*/0xB0,/*3*/0x99,/*4*/0x92,/*5*/0x82,/*6*/0xF8,/*7*/0x80,/*8*/0x90,/*9*/};sbit key_hour=P3^5;sbit key_min=P3^6;uchar hour=12;uchar minute=0;uchar second=0;uchar flag=0;uchar sec_flag=0;/************************* 初始化程序**************************/ void system_init(){ TMOD=0x01;EA=1;ET0=1;EX0=1;IT0=1;TR0=1;TH0=(65536-50000)/256;TL0=(65536-50000)%256;}/************************* 定时器中断0中断处理程序**************************/ void int1_ISR() interrupt 1 {TH0=(65536-50000)/256;TL0=(65536-50000)%256;flag++;if(flag==20){sec_flag=1;second++;flag=0;}if(second==60){second=0;minute++;}if(minute==60){minute=0;hour++;hour%=24;}}/************************* 按键程序**************************/ void detectkey(){delay_ms(10);if(key_hour==0){hour++;hour=hour%24;while(!key_hour)display();}if(key_min==0){minute++;minute=minute%60;while(!key_min)display();}if(P3_7==0){hour=12;minute=0;second=0;while(!P3_5)display();}/*************************显示程序**************************/void display(uchar i){P0=i;}/*************************延时处理程序**************************/void delay_ms(uchar no){uchar i,j;for(i=0;i<no;i++){for(j=0;j<164;j++);for(j=0;j<164;j++);}}#endif说明:按键值送P0接的LED显示。