一、实训目的意义及任务要求
1.1目的意义
在如今,单片机的使用领域已十分广泛,它在智能仪器仪表、实时工控、通讯设备、导航系统、家用电器等均有很广泛的应用。
单片机又称单片微控制器,它不是完成某一个逻辑功能的芯片,而是把一个计算机系统集成到一个芯片上。单片机作为一门专业学科,对学生的要求也较高,要求对C语言有较好的掌握,还要与单片机的硬件工作原理相结合,也是理论与实践相结合的一大体现。多功能电脑时钟有效地检验了单片机中对数码管,蜂鸣器,LED灯的控制,同时提高了学生的工程系统设计能力。通过此次单片机系统综合训练,不仅要让学生认识了解它,而且增强学生学科积极性。
2.2任务要求
通过对硬件和软件的设计要求设计的电脑时钟完成以下功能: 1.基本功能
①实时显示当前时间(4位数码管显示,2位显示小时,2位显示分钟,第2位小数点0.5秒亮,0.5秒灭)。 ②能用一按键依次切换显示年及月日。 ③能修改当前时钟。
④具有秒表功能,显示秒和百分秒。 2. 扩展功能
①单片机与PC机的通讯(可选);②可设定初值的倒计时功能(可选) ③闹钟及报时功能(可选); ④显示星期(可选)。 3. 设计参数
显示时间时,4位数码管显示,2位显示小时,2位显示分钟,第2位小数点0.5秒亮,0.5秒灭;蜂鸣器报时时间以每生学号最末位确定。
- 1 - - 1 -XXXXX大学《单片机系统综合训练》课程设计报告 二.实习任务的方案
2.1 任务进度
①布置任务、分析任务、学习单片机的C51功能程序设计(3天) ②方案设计、使用Protel设计和绘制硬件原理图(1.5天) ③程序设计和调试(4.5天)
④设计验收、撰写报告(1天)
2.2 系统分析
根据系统功能要求,可将系统组成结构分成四大部分:
①DS1302时钟芯片读数据写数据模块; ②数码管显示模块; ③按键设置调节时间模块; ④秒表功能模块。
硬件电路接线图如附录一,本系统采用DS1302时钟芯片,四位数码管用来显示年月日,星期,时分,以及秒和百分秒。其中年月日,时分秒和星期采用DS1302的数据显示,秒表采用单片机定时中断实现。本系统共用到四个按键,且均为对地按键,分别用于显示切换,修改切换,修改加一,修改减一,秒表启动暂停和数据清零。
2.3 器件选择
选用STCC51芯片,频率为11.0592MHz,由于系统要求显示年月日小时和分钟,采用四位LED数码管显示即可。按键是用来设置时间或闹钟时间或启动秒表等功能的,设置三个按键:显示切换模式键(key3)、修改数据键(key0)、加一键(key1)、减一键(key2)。
常见的LED显示具有清晰明亮的特点。是显示接口也是绝大多数单片机应用系统必备的部件之一。
发光二极管组成的显示器是单片机应用产品中最常用的廉价输出设备。它由
- 2 - - 2 -XXXXX大学《单片机系统综合训练》课程设计报告 若干个发光二极管按一定的规律排列而成。当某一个发光二极管导通时,相应的一个点或一笔画被点亮,控制不同组合的二极管导通,就能显出各种字符。
常用的7段显示器的结构如图所示,发光二极管的阳极连在一起的称为共阳极显示器,阴极连在一起的成为共阴显示器。1位显示器由8个发光二极管组成,其中7个发光二极管a~g控制7个笔画的亮或暗,另一个控制一个小数点的亮和暗,这种笔画的七段显示器能显示的字符较少,字符的形状有些失真,但失控简单,使用方便。
- 3 - - 3 -XXXXX大学《单片机系统综合训练》课程设计报告 三、系统硬件设计
3.1 单片机的最小系统
单片机功能系统图见附录 1,。单片机最小系统由STCC51单片机、复位电路、晶振电路组成。如图3.1所示
图3.1 单片机最小系统图
3.2 数码管、按键及DS1302时钟芯片电路的设计
在电子钟的输入部分,设置相应的置数功能,通过外部设备的输入,如按键,实现时间的切换。除此之外,调整日期等时间也需要按键进行输入。在选用输入端口时,将P0引脚与按键相连进行输入。K1、K2、K3、K4分别表示设置切换键、数值加一键、数值减一、显示月和日键。
- 4 - - 4 -XXXXX大学《单片机系统综合训练》课程设计报告
系统仿真电路图
系统仿真电路图
DS1302与单片机连线图
3.3 其他附属电路设计
按键设计,电频转换芯片的硬件电路如下图所示:
- 5 - - 5 -XXXXX大学《单片机系统综合训练》课程设计报告 RS232串口通信及电源电路等设计,如图3.3所示
图3.3 附属电路设计图
- 6 - - 6 -XXXXX大学《单片机系统综合训练》课程设计报告 四、软件设计
4.1 主程序设计
使用定时器0来定时,定时5ms,运用定时器的中断来实现这些功能,显示是用的数码管的动态扫描,每5ms扫描一位数码管,20ms循环一次。设置一些标志位,实时时间显示的标志位,星期显示的标志位,闹铃时间显示的标志位,秒表显示的标志位,在不同的模式下,我们要使该模式下的标志位有效,从而进行此模式的显示,通过按键进行不同的操作。每个标志位有效时,数码管显示的内容就不一样。
闹钟的实现是用一个子函数,每5ms调用一次函数,并把北京时间与设定的闹铃时间比较,如果相等就使蜂鸣器有效。闹铃时间的长短可以用一个变量对秒计数,当计数值小于我们设定的值时,就是蜂鸣器有效,当大于等于设定的值时就关闭蜂鸣器。
整点报时或半点报时很好实现,在中断函数里,当分钟等于60时,蜂鸣器对应鸣叫相应点数,并且小时要自增1,当分钟等于30时,蜂鸣器鸣一次,分钟自增1,要使蜂鸣器有效,可用一个变量对秒计数,当秒等于我们设定的值时,就关闭蜂鸣器。
4.2 系统操作功能设计
根据系统功能描述,可以分为:北京时间功能、整点报时、闹铃功能、日期显示及秒表功能功能。
我们通过对K_Mode键按下的次数计数,用Mode计数,Mode的次数就代表了不同的模式,每个模式都有与之相对应的指示灯,每个模式的功能如下:
Mode 0:按键每按下时显示北京时间模式,此时,四个指示灯全灭,显示格式为:小时.分钟(如:07.35,为7点35分),按K_UP或者K_DN键对系统没影响,每到整点或半点时时,要进行相应点数的间隔蜂鸣报时(半点短鸣一次)。
Mode 1:按键按下一次时,进入修改北京时间的小时模式,四个指示灯依次为“亮灭灭灭”,按K_UP或者K_DN键对小时进行修改。
- 7 - - 7 -XXXXX大学《单片机系统综合训练》课程设计报告 Mode 2:按键按下两次时,进入修改北京时间的分钟模式,四个指示灯依次为“灭亮灭灭”,按K_UP或者K_DN键对分钟进行修改。
Mode 3:按键按下三次时,进入修改闹铃时间的小时模式,四个指示灯依次为“灭灭亮灭”,按K_UP或者K_DN键对闹铃小时进行修改。
Mode 4:按键按下四次时,进入修改闹铃时间的分钟模式,四个指示灯依次为灭灭灭亮,按K_UP或者K_DN键对闹铃分钟进行修改。
Mode 5:按键按下五次时,进入年显示模式,四个指示灯依次为“亮亮灭灭”,显示格式为:四位年(如20.12为当前年份为公元2012年),在此种模式下,按K_UP或者K_DN键对系统没影响。
Mode 6:按键按下六次时,进入月日显示模式,四个指示灯依次为“亮灭亮灭”,显示格式为:月日(如07.05为当前日期为7月5日),在此种模式下,按K_UP或者K_DN键对系统没影响。
Mode 7:按键按下七次时,进入秒表模式,四个指示灯依次为“亮灭灭亮”,显示格式为:秒百分秒(如05.90为当前秒表计时到5秒900毫秒),在此种模式下,K_UP键设为用来启动/暂停秒表、K_DN键设为用来对秒表进行清零。
Mode 8:按键按下八次时,进入闹钟选择模式,四个指示灯依次为“亮亮亮灭”,显示格式为:CL01/00,\"CL.00\"表示贪睡闹铃功能关闭,\"CL.01\"表示贪睡闹铃功能开启,按UP或DN键可在00或01间循环选择;在贪睡闹铃功能关闭时,可按任意键停止当前闹钟,或不按键,则闹钟1分钟,以后再不响。在贪睡闹铃功能开启时,如按下除UP键外的任意键,停止当前闹钟,如不按键,则闹钟1分钟;当过5分钟后,闹钟又会重新响起,如此循环,只有按下UP键时,才能停止闹钟以后再不响。在此种模式下,K_UP键设为用来启动/暂停秒表、K_DN键设为用来对秒表进行清零。
Mode 9:按键按下九次时,进入整点报时选择模式,四个指示灯依次为“亮亮亮亮”,显示格式为:BS01/00,\"BS.00\"表示整点报时功能关闭,01表示报时功能开启,按UP或DN键可在00或01间循环选择。
- 8 - - 8 -XXXXX大学《单片机系统综合训练》课程设计报告 4.3主程序void main()
图4.1 主程序功能流程图
4.4主程序设计
主程序采用定时器0对程序进行扫描执行。分别执行DS1302芯片初始化子程序,写数据子程序,将最初的值写入芯片中,采用while循环循环执行键盘扫描子程序。 main() {
TMOD=0x01; //使用模式1,16位定时器 TH0=(65536-10000)/256; //给定初值 TL0=(65536-10000)%256; EA=1; //总中断打开 ET0=1; //定时器中断打开
- 9 - - 9 -XXXXX大学《单片机系统综合训练》课程设计报告 TR0=1; //定时器开关打开 Ds1302_Init(); Ds1302_Write_Time(); while(1) {
keyscan(); if(Btread==0) { Btread=1;
Ds1302_Read_Time(); }
display(); }
4.5 DS1302子程序设计
- 10 - - 10 -XXXXX大学《单片机系统综合训练》课程设计报告 此子程序分为初始化程序,读数据程序,写数据程序,一些数据程序为例; void Ds1302_Write_Byte(unsigned char addr, unsigned char d) {
CE=0;_nop_(); SCLK=0; _nop_(); CE=1; _nop_(); Write1302(addr); Write1302(d); CE=0; _nop_(); IO=1; SCLK=1; }
- 11 - - 11 -XXXXX大学《单片机系统综合训练》课程设计报告 4.6时间调整子程序
- 12 - - 12 -XXXXX大学《单片机系统综合训练》课程设计报告
时间调整子程序采用的是对key1按的次数不同来进行对年月日时分及星期的设置。
void zongshi(void) {
if(!key)
{
if(btx==0) { if(!key) {
btx=1;k++; } } }else{btx=0;}} k=1时,调整年份,key1为加,key2为减
void keyscan() k=2时,调整月份,key1为加,key2为减
{ k=3时,调整日份,key1为加,key2为减
display(); k=4时,调整星期,key1为加,key2为减 if(!key) {
if(btx==0) { if(!key) { btx=1; k++; } }
- 13 - - 13 -XXXXX大学《单片机系统综合训练》课程设计报告 4.7 按键切换子程序
void tiaoshidisplay() {
if(z==15) { z=0; switch(k) {
case 1:bt1=~bt1;break; //年 case 2:bt2=~bt2;bt1=0;break; //月
case 3:bt3=~bt3;bt1=0;break; //日 case 4:bt1=~bt1;bt3=0;break; //周 case 5:bt2=~bt2;bt1=0;break; //时 case 6:bt3=~bt3;bt2=0;break; //分 default:bt3=0;break; } } }
14 14XXXXX大学《单片机系统综合训练》课程设计报告 五、调试及性能分析
5.1软件测试
电子成年历是多功能的数字型,可以看当前日期(阴、阳历),时间,还有温度的仪器。电子成年历功能很多,所以对于它的程序也较为复杂,所以在编写程序和调试时出现了相对较多的问题。最后经过多次的模块子程序的修改,一步一步的完成,最终解决了软件。在软件的调试过程中主要遇到的问题如下:
1. 时钟不准,走一段时间后误差较大
原因:该问题主要是晶振芯片的频率不真确引起的。晶振的频率理论值为12MHZ,由于存在误差,导致了单片机时间走一段时间后便出现了误差。
2.烧入程序后,LED数码管显示闪动,而且亮度不均匀。
解决:首先对调用的延时进行逐渐修改,可以解决显示闪动问题。其次,由于本作品使作动态扫描方式显示的数字,动态扫描很快,人的肉眼是无法看出,但是调用的显示程序时,如果不在反回时屏蔽掉最后的附值,则会出现很亮的现象,所以在显示的后面加了屏蔽子令,最后解决了此问题。
3.修改时间、日期时没有农历没有自动对应上。
解决:把不相关的程序暂时屏蔽,地农历的子程序调试,发现在调用农历自动更新时,对十进制和十六进制处理不好,所以会造成错乱。最后把相应的十进制进行修改,使得可以与十六进制对应,最后解决了此问题.
5.2测试结果分析与结论
(1).在测试中遇到发光二极管、LED数码管为不显示时,首先使用试测仪对电路进行测试,观察是否存在漏焊,虚焊,或者元件损坏.
(2).LED 数码管显示不正常,还有亮度不够,首先使用试测仪对电路进行测试,观察电路是否存在短路现象。查看烧写的程序是否正确无误,对程序进行认真修改。
(3).DS1302 与微处理器进行数据交换时,首先由微处理器向电路发送命
15 15XXXXX大学《单片机系统综合训练》课程设计报告 令字节,命令字节最高位MSB(D7)必须为逻辑1,如果D7=0,则禁止写DS1302,即写保护;D6=0,指定时钟数据,D6=1,指定RAM 数据;D5~D1 指定输入或输出的特定寄存器;最低位LSB(D0)为逻辑0,指定写操作(输入), D0=1,指定读操作(输出)。
在DS1302 的时钟日历或RAM 进行数据传送时,DS1302 必须首先发送命令字节。若进行单字节传送,8 位命令字节传送结束之后,在下2 个SCLK 周期的上升沿输入数据字节,或在下8 个SCLK 周期的下降沿输出数据字节。
DS1302 与RAM 相关的寄存器分为两类:一类是单个RAM 单元,共31 个,每个单元组态为一个8 位的字节,其命令控制字为C0H~FDH,其中奇数为读操作,偶数为写操作;再一类为突发方式下的RAM 寄存器,在此方式下可一次性读、写所有的RAM 的31 个字节。
要特别说明的是备用电源B1,可以用电池或者超级电容器(0.1F 以上)。虽然DS1302 在主电源掉电后的耗电很小,但是,如果要长时间保证时钟正常,最好选用小型充电电池。可以用老式电脑主板上的3.6V 充电电池。如果断电时间较短(几小时或几天)时,就可以用漏电较小的普通电解电容器代替。100 μF 就可以保证1 小时的正常走时。DS1302 在第一次加电后,必须进行初始化操作。初始化后就可以按正常方法调整时间。
5.3 测试结论
经过多次的反复测试与分析,可以对电路的原理及功能更加熟悉,同时提高了设计能力与及对电路的分析能力.同时在软件的编程方面得到更到的提高,对编程能力得到加强.同时对所学的知识得到很大的提高与巩固
16 16XXXXX大学《单片机系统综合训练》课程设计报告 六、心得体会
在该部分实习中,我有几点收获:
1、 整合程序时,并非把各个模块链接起来就行,往往需要把某些模块拆开,重新嵌入整合程序中,方能实现它的功能,说明程序的调用和嵌套要灵活,不能生搬硬套。
2、 中断的应用。在程序中,T0和T1两个定时器我均用到了,而源程序模块都用T0,没用T1,中断优先级一样,所以在整合后,需要修改中断优先级,而我简单的把两个中断优先级定为1和2,程序当然无法运行了,后来经学长指导才明白,优先级是有顺序的,单片机共五个中断源,都有自然的优先级,不能随便设置,后来将T1的优先级改为3,程序可以执行。
3、该部分实习,使我对软件的设计有了进一步的认识,编写程序也有迹可循,对单片机有了更深的理解,而且将C语言用到了单片机上,有了一次新的尝试,以前学到的单片机的知识在实习中均得到了实践,对我以后的从事相应的工作奠定了一个基础。
17 17XXXXX大学《单片机系统综合训练》课程设计报告 参考文献
[1] 李广弟等 单片机基础 北京航空航天出版社, 2007
[2] 楼然苗等 51 系列单片机设计实例 北京航空航天出版社, 2008 [3] 张毅刚.单片机原理及应用.北京:高等教育出版社,200
18 18XXXXX大学《单片机系统综合训练》课程设计报告
附录一
附录二
程序如下:
#include #define uchar unsigned char #define uint unsigned int #define Write_Protect 0x8e //写保护 #define OutPut P0 //显示输出 //sbit DU=P2^6; //数码管段选 //sbit WE=P2^7; //数码管位选 sbit CE=P3^3; //复位端口定义在P0.2引脚 sbit IO=P2^4; //数据输出端定义在P0.4引脚 sbit SCLK=P3^2; //时钟输出端口定义在P0.3引脚 sbit key=P3^4; //时间调节控制键 sbit key1=P3^5; //每按一次位加一 sbit key2=P3^6; //每按一次位减一 sbit key3=P3^7; //显示切换 uchar code Wei[]={0xfe,0xfd,0xfb,0xf7,0xfd};// 位选数据0xef,0xdf,0xbf,0x7f uchar code Duan[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f}; //0--9共阴代码 code uchar Waddr[]={0x8c,0x88,0x86,0x84,0x82,0x80,0x8a}; //寄存器写地址 code uchar Raddr[]={0x8d,0x,0x87,0x85,0x83,0x81,0x8b}; // 寄存器读地址 uchar timeset[]={0x01,0x02,0x03,0x04,0x05,0x00,0x01}; /*设置初始时间*/ uchar time_buf[7]; /*存读到的时间*/ uchar time_disp[7]; uchar dispdat[5]; /*存储显示值的*/ uchar Btdis=0,k=0,z; bit btx,btx1,btx2,btx3,bt1,bt2,bt3; bit Btread; uint flag1; /*================================================== 函数功能:延时n 毫秒 入口参数:n ====================================================*/ void Write1302(uchar dat); void delaynms(uchar n) { uchar i,j; for(i=n;i>0;i--) for(j=125;j>0;j--); 19 } /*============================================= 函数功能:根据命令字,向1302写一个字节数据 入口参数:Cmd,存储命令字;dat,存储待写的数据 ==============================================*/ void Ds1302_Write_Byte(unsigned char addr, unsigned char d) { CE=0;_nop_(); SCLK=0; _nop_(); CE=1;_nop_(); Write1302(addr); Write1302(d); CE=0; _nop_(); IO=1; SCLK=1; } //从DS1302读出一字节数据 uchar Ds1302_Read_Byte(unsigned char addr) { unsigned char i; unsigned char temp; CE=1; addr = addr | 0x01; for (i = 0; i < 8; i ++) { if (addr & 0x01) { IO=1; } else {IO=0; } SCLK=1; SCLK=0; addr = addr >> 1; } //输出数据:temp for (i = 0; i < 8; i ++) { temp = temp >> 1; if (IO) { temp |= 0x80; } else { temp &= 0x7F; } SCLK=1; SCLK=0; } CE=0; //停止DS1302总线 return temp; 20 } /*=================================================== 函数功能:向1302日历时钟芯片写入一个字节的数据 入口参数:dat ====================================================*/ void Write1302(uchar dat) { uchar i; //SCLK=0; CE=1; for(i=0;i<8;i++) { IO=dat&0x01; SCLK=0; SCLK=1; dat=dat>>1; } } /*===================================================== 函数功能:根据命令字,从1302读取一个字节的数据 入口参数:Cmd 返回参数:dat ======================================================*/ uchar Readset1302(uchar Cmd) { uchar dat; CE=0; SCLK=0; CE=1; Write1302(Cmd); SCLK=1; CE=0; return dat; } void bcdpro(void) { unsigned char i,tmp; for(i=0;i<7;i++) //BCD处理 { tmp=timeset[i]/10; //timeset[]={0x01,0x02,0x03,0x04,0x05,0x06,0x01} time_buf[i]=timeset[i]%10; //time_buf[7] time_buf[i]=time_buf[i]+tmp*16; } 21 } /*================================================ 向DS1302写入时钟数据 ===================================================*/ void Ds1302_Write_Time(void) {unsigned int i; uchar flag; flag=Readset1302(0x81); if(flag&0x80) //判断时钟芯片是否停止,为1时时钟停止 { //掉电保存 bcdpro(); for(i=0;i<7;i++) { Ds1302_Write_Byte(Waddr[i],time_buf[i]); } Ds1302_Write_Byte(0x8e,0x80); //打开写保护 } } /*=============================================== 从DS1302读出时钟数据 =================================================*/ void Ds1302_Read_Time(void) { unsigned char i,tmp; for(i=0;i<7;i++) {time_buf[i]=Ds1302_Read_Byte(Raddr[i]); } for(i=0;i<7;i++) //BCD处理 { tmp=time_buf[i]/16; time_buf[i]=time_buf[i]%16; time_disp[i]=time_buf[i]+tmp*10; } } /*====================================================== DS1302初始化 ===================================================*/ void Ds1302_Init(void) { CE=0; //RST脚置低 SCLK=0; //SCK脚置低 Ds1302_Write_Byte(0x80,0x00); } /*================================================== ==函数名: 时分秒显示子程序 ==函数功能:将从DS1302读到的数据在8位共阴数码管上显示 22 ==返回参数: ===================================================*/ void display() { uchar i; if(Btdis==0) { if(bt2==0) { dispdat[0]=Duan[time_disp[3]/10]; //时 dispdat[1]=Duan[time_disp[3]%10];} else {dispdat[0]=0x00; dispdat[1]=0x00; } //dispdat[2]=0x40; //\"-\" if(bt3==0) { dispdat[2]=Duan[time_disp[4]/10]; //分 dispdat[3]=Duan[time_disp[4]%10]; } else { dispdat[2]=0x00; dispdat[3]=0x00; } //dispdat[5]=0x40; if(flag1<25) dispdat[4]=0x80; else dispdat[4]=0x00; } if(Btdis==3) { dispdat[0]=Duan[time_disp[5]/10]; //秒 dispdat[1]=Duan[time_disp[5]%10]; dispdat[2]=0x40; dispdat[3]=0x40; } if(Btdis==1) { if(bt1==0) { 23 dispdat[0]=Duan[time_disp[0]/10]; //年 dispdat[1]=Duan[time_disp[0]%10]; } else { dispdat[0]=0x00; dispdat[1]=0x00; } //dispdat[2]=0x40; //\"-\" if(bt2==0) { dispdat[2]=Duan[time_disp[1]/10]; //月 dispdat[3]=Duan[time_disp[1]%10]; } else { dispdat[2]=0x00; dispdat[3]=0x00; } dispdat[4]=0x00; } if(Btdis==2) { //dispdat[0]=0x40; if(bt1==0) { dispdat[3]=Duan[time_disp[6]%10]; //周 } else { dispdat[3]=0x00; } dispdat[2]=0x40; if(bt3==0) { dispdat[0]=Duan[time_disp[2]/10]; //日 dispdat[1]=Duan[time_disp[2]%10]; } else { dispdat[0]=0x00; dispdat[1]=0x00; } 24 if(dispdat[3]==7) { dispdat[3]=0x7f; } } if(Btdis==4) { } for(i=0;i<5;i++) { OutPut=dispdat[i]; P1=Wei[i]; delaynms(1); OutPut=0x00; } } /*================================================== ==函数名: 按键 ==函数功能:显示模式,调时模式 ==返回参数: ===================================================*/ void zongshi(void) { if(!key) { if(btx==0) { if(!key) { btx=1; k++; } } } else 25 {btx=0;} } void keyscan() { display(); if(!key) { if(btx==0) { if(!key) { btx=1; k++; } } /*================================================= k=1时,调整年份,key1为加,key2为减 ==================================================*/ while(k==1) { Btdis=1; display(); zongshi(); if(!key1) { if(btx1==0) { if(!key1) { btx1=1; if(time_disp[0]<99) { time_disp[0]++; } else {time_disp[0]=0;} } } } else {btx1=0; } if(!key2) { if(btx2==0) 26 { if(!key2) { btx2=1; if(time_disp[0]>0) {time_disp[0]--;} else {time_disp[0]=99;} } } } else {btx2=0;} } /*================================================= k=2时,调整月份,key1为加,key2为减 ==================================================*/ while(k==2) { Btdis=1; display(); zongshi(); if(!key1) {if(btx1==0) { if(!key1) {btx1=1; if(time_disp[1]<12) { time_disp[1]++; if(time_disp[1]==2) {if(time_disp[0]%4==0) { if(time_disp[2]>29) {time_disp[2]=29;} }else if(time_disp[2]>28) {time_disp[2]=28;} } } else { time_disp[1]=1;} } } 27 }else { btx1=0; } if(!key2) { if(btx2==0) {if(!key2) { btx2=1; if(time_disp[1]>1) { time_disp[1]--; if(time_disp[1]==2) {if(time_disp[0]%4==0) { if(time_disp[2]>29) {time_disp[2]=29;} }else if(time_disp[2]>28) { time_disp[2]=28; } } }else { time_disp[1]=12; } } } }else { btx2=0; } } /*================================================= k=3时,调整天,key1为加,key2为减 ==================================================*/ while(k==3) { Btdis=2; display(); zongshi(); if(!key1) { if(btx1==0) { if(!key1) { btx1=1; if(time_disp[1]==2) { 28 if(time_disp[0]%4==0) { if(time_disp[2]<29) { time_disp[2]++; } else { time_disp[2]=1; } } else if(time_disp[2]<28) { time_disp[2]++; } else time_disp[2]=1; } else if(time_disp[1]<8) { if(time_disp[1]%2==0) //小于8月的月份除以2的余数为0则为小月 { if(time_disp[2]<30) { time_disp[2]++; } else { time_disp[2]=1; } } else if(time_disp[1]%2==1) //小于8月的月份除以2的余数为1则为大月 { if(time_disp[2]<31) { time_disp[2]++; } else { time_disp[2]=1; } } } else if(time_disp[1]>7) { if(time_disp[1]%2==0) { if(time_disp[2]<31) { time_disp[2]++; } else { time_disp[2]=1; } } else if(time_disp[1]%2==1) 29 { if(time_disp[2]<30) { time_disp[2]++;} else { time_disp[2]=1; } } } } } } else { btx1=0; } if(!key2) { if(btx2==0) { if(!key2) {btx2=1; if(time_disp[1]==2) {if(time_disp[0]%4==0) {if(time_disp[2]>1) { time_disp[2]--; } else { time_disp[2]=29; } } else if(time_disp[2]>1) { time_disp[2]--; } else { time_disp[2]=28; } } else if(time_disp[1]<8) {if(time_disp[1]%2==0) {if(time_disp[2]>1) { time_disp[2]--; } else { time_disp[2]=30; } } else if(time_disp[1]%2==1) { if(time_disp[2]>1) {time_disp[2]--;} else { time_disp[2]=31; } } }else if(time_disp[1]>7) 30 {if(time_disp[1]%2==0) {if(time_disp[2]>1) {time_disp[2]--; }else { time_disp[2]=31; } }else if(time_disp[1]%2==1) {if(time_disp[2]>1) {time_disp[2]--; }else { time_disp[2]=30; } } } } } }else { btx2=0; } } /*================================================= k=4时,调整星期,key1为加,key2为减 ==================================================*/ while(k==4) { Btdis=2; display(); zongshi(); if(!key1) { if(btx1==0) { if(!key1) { btx1=1; if(time_disp[6]<=6) {time_disp[6]++; }else { time_disp[6]=1; } } } }else { btx1=0;} if(!key2) {if(btx2==0) {if(!key2) 31 { btx2=1; if(time_disp[6]>1) { --time_disp[6]; } else { time_disp[6]=7; } } } } else { btx2=0;} } /*================================================= k=5时,调整小时,key1为加,key2为减 ==================================================*/ while(k==5) { Btdis=0; display(); zongshi(); if(!key1) {if(btx1==0) {if(!key1) {btx1=1; if(time_disp[3]<23) {time_disp[3]++; } else { time_disp[3]=0; } } } } else { btx1=0; } if(!key2) {if(btx2==0) {if(!key2) {btx2=1; if(time_disp[3]>0) { time_disp[3]--; } else { time_disp[3]=23; } } } } 32 else { btx2=0; } } /*================================================= k=6时,调整分钟,key1为加,key2为减 ==================================================*/ while(k==6) { Btdis=0; display(); zongshi(); if(!key1) {if(btx1==0) {if(!key1) {btx1=1; if(time_disp[4]<59) {time_disp[4]++; } else { time_disp[4]=0; } } } } else { btx1=0; } if(!key2) { if(btx2==0) { if(!key2) {btx2=1; if(time_disp[4]>0) {time_disp[4]--; } else { time_disp[4]=59; } } } } else { btx2=0; } } /*====================================================== k=7把调整后的数据转换成16进制写入1302 =======================================================*/ while(k==7) { 33 uchar i; for(i=0;i<7;i++) { timeset[i]=time_disp[i]; } //将调整后的时候写入DS1302 bcdpro(); for(i=0;i<7;i++) { Ds1302_Write_Byte(Waddr[i],time_buf[i]); } Ds1302_Write_Byte(0x8e,0x80); //打开写保护 k=0; } }else { btx=0; } /*====================================================== key3为显示切换键,形成时分秒与年月日以及星期之前的切换 =======================================================*/ if(!key3) { if(btx3==0) { if(!key3) {btx3=1; if(Btdis<3) {Btdis++; } else { Btdis=0; } } } } else { btx3=0; } } /*====================================================== key3为显示切换键,形成时分秒与年月日以及星期之前的切换 =======================================================*/ void tiaoshidisplay() { if(z==15) { z=0; switch(k) { case 1:bt1=~bt1;break; //年 case 2:bt2=~bt2;bt1=0;break; //月 case 3:bt3=~bt3;bt1=0;break; //日 case 4:bt1=~bt1;bt3=0;break; //周 case 5:bt2=~bt2;bt1=0;break; //时 34 case 6:bt3=~bt3;bt2=0;break; //分 default:bt3=0;break; } } } ==函数名: 定时器1子程序 ==函数功能:1S读一次时间 ==返回参数: void Timer0() interrupt 1 using 1 { uchar t; TH0=(65536-20000)/256; //给定初值 TL0=(65536-20000)%256; flag1++; if(flag1==50) flag1=0; if(t<49) {t++; z++; tiaoshidisplay(); }else { t=0; Btread=0; } } /*函数名: 主函数 main() { TMOD=0x01; //使用模式1,16位定时器 TH0=(65536-20000)/256; //给定初值 TL0=(65536-20000)%256; EA=1; //总中断打开 ET0=1; //定时器中断打开 TR0=1; //定时器开关打开 Ds1302_Init(); Ds1302_Write_Time();while(1) { keyscan(); if(Btread==0) { Btread=1; Ds1302_Read_Time(); } display(); } 35 因篇幅问题不能全部显示,请点此查看更多更全内容
Copyright © 2019- igat.cn 版权所有 赣ICP备2024042791号-1
违法及侵权请联系:TEL:199 1889 7713 E-MAIL:2724546146@qq.com
本站由北京市万商天勤律师事务所王兴未律师提供法律服务