赞
踩
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
使用定时器/计数器实现电子钟,用LED数码管显示时、分、秒,24小时制,数码管上电初始显示为“12.00.00”,到24小时清零,然后反复,晶振11.0592MHz。理论误差小于0.1秒/天。
扩展要求:简单的可调电子钟。增加“时增加”、“分增加”2个按键,按下“时增加”按键,时显示加1,加满24归零,按下“分增加”按键时,分显示加1,加满60归零。
开启定时器中断,在定时器中断函数中设置时间变量,用于在main函数中计算小时, 分钟,秒。这里我采用的是定时器0的工作方式一,因为从定时,计数器产生中断请求到响应中断,需要3~8个机器周期。定时中断子程序中的数据人栈和重装定时,计数器的初值还需要占用数个机器周期。此外,从中断入口转到中断子程序也要占用一定的 机器周期。所以要在定时器中断中进行误差补偿,我开发板中用的是11.0592M的晶振, 那么一个机器周期为(1/11.0592M)*12,定时50ms为(50*10^-3)/机器周期=46080。可以 将TH0和TL0从产生溢出到被重新赋值的已有的计数值读出,并补偿到计数值初值中去,可以消除定时/计数器的定时误差。
先在定时器中断中禁止所有中断请求,关闭T0,即EA=0,TR0=0,将TL0中已计数 值写入修正变量fixtime,并加上修正操作所需的机器周期,经过仿真调试大概为10 个机器周期,即0x0A,所以fixtime=TL0+0x0A,再将fixtime赋给TL0,因为 (65536-46080)%256=0,所以新的TL0=0+fixtime,因为(65536-46080)/256=76=0x4C,且在 修正TL0时可能产生进位,要补偿到TH0,所以TH0=0x4C+(char)CY,CY为PSW寄存器中的进位标志位,之后再开启所有中断请求,开启T0,即EA=1,TR0=1。这样就完成了整个定时器误差补偿的过程。
利用数码管的动态扫描方式,将计算得出的时间分别给到给数码管显示数组中的常量表达式中,让数码管动态显示时间。
利用两个按键改变小时和分钟的数值,那么按键应进行消抖处理,且不能用while语句 进行按键释放处理,那样可能会导致数码管闪动。可以先定义一个有返回值的按键扫描 函数Key_Scan( ),让它返回按键值1或2,无按键按下则返回0。再定义一个按键处理 函数KEY_Handle( ),在函数中进行位运算,key_value用于记录按键 值,key_up用于记 录按键释放,key_down用于记录哪个按键按下,key_old用于记录上次的按键值,此函数可以实现“记忆”功能,即如果按键一直按着,也不会出现多次触发的现象,也解决了用while语句检测按键释放而导致数码管闪动的问题。再将此函数放入定时器1的中断处理函数中,进行每50ms一次的按键扫描,定时器1同样也进行误差补偿处理。
代码如下:
- #include <reg52.h>
- #include <intrins.h>
- #define uchar unsigned char
- #define uint unsigned int
-
- sbit dula = P2^6;
- sbit wela = P2^7;
- sbit key1 = P3^4;
- sbit key2 = P3^5;
-
- uchar fixtime;
-
- uint count_miao,count_fen0,count_fen1,count_shi,num_miao,num_fen,num_shi;
-
- uint ge,shi,bai,qian,wan,shiwan;
-
- uchar key_value,key_up,key_down,key_old;
-
- float number,uwTick,uwTick_KEY;
-
- uchar table[] =
- {
- 0x3f,0x06,0x5b,0x4f,
- 0x66,0x6d,0x7d,0x07,
- 0x7f,0x6f,0x77,0x7c,
- 0x39,0x5e,0x79,0x71
- };
-
-
- uchar table_dot[]=
- {
- 0xbf,0x86,0xdb,0xcf,
- 0xe6,0xed,0xfd,0x87,
- 0xff,0xef,0xf7,0xfc,
- 0xb9,0xde,0xf9,0xf1
- };
-
-
- void delay(unsigned int x)
- {
- unsigned int i,j;
- for(i=1;i>0;i--)
- for(j=x;j>0;j--);
- }
-
-
- void clean()
- {
- wela = 1;
- P0 = 0xff;
- wela = 0;
-
- dula = 1;
- P0 = 0x00;
- dula = 0;
- }
-
-
- void dula_open()
- {
- dula = 1;
- dula = 0;
- P0 = 0xff;
- }
-
- void wela_open()
- {
- wela = 1;
- wela = 0;
- delay(1);
- clean();
- }
-
- void display(uint shiwan,uint wan,uint qian,uint bai,uint shi,uint ge)
- {
- P0 = table[shi];
- dula_open();
-
- P0 = 0xef;
- wela_open();
-
- P0 = table[ge];
- dula_open();
-
- P0 = 0xdf;
- wela_open();
-
- P0 = table[qian];
- dula_open();
-
- P0 = 0xfb;
- wela_open();
-
- P0 = table_dot[bai];
- dula_open();
-
- P0 = 0xf7;
- wela_open();
-
- P0 = table[shiwan];
- dula_open();
-
- P0 = 0xfe;
- wela_open();
-
-
- P0 = table_dot[wan];
- dula_open();
-
- P0 = 0xfd;
- wela_open();
- }
-
-
- uchar key_scan()
- {
- uchar key = 0;
- if(key1 == 0)
- {
- return key = 1;
- }
-
- if(key2 == 0)
- {
- return key = 2;
- }
-
- return key;
- }
-
-
-
- void key_handle()
- {
- key_value = key_scan();
- key_down = key_value & (key_value ^ key_old);
- key_up = ~key_value & (key_value ^ key_old);
- key_old = key_value;
-
- if(key_down == 1)
- {
- num_shi++;
- if(num_shi == 24)num_shi = 0;
-
- }
-
- if(key_down == 2)
- {
- if(num_fen == 59)
- {
- num_fen = 0;
- num_shi++;
- if(num_shi == 24)num_shi=0;
- }
- else
- num_fen++;
- }
- }
-
-
-
- void T0_Handle_Program()
- {
- if(count_miao == 20)
- {
- count_miao = 0;
- num_miao++;
- if(num_miao == 60)num_miao = 0;
- }
-
-
- if(count_fen0 == 1200)
- {
- count_fen0 = 0;
- num_fen++;
- if(num_fen == 60)
- {
- num_fen=0;
- num_shi++;
- if(num_shi == 24)num_shi=0;
- }
- if(count_fen1 == 72000)
- {
- num_fen=0;
- }
- }
-
- if(count_shi == 72000)
- {
- count_shi = 0;
- num_shi++;
- if(num_shi == 24)num_shi = 0;
- }
-
- }
-
- void main()
- {
- TMOD = 0x11;
- TH0 = (65536-46080)/256;
- TL0 = (65536-46080)%256;
- TH1 = (65536-46080)/256;
- TL1 = (65536-46080)%256;
-
- EA = 1;
- ET0 = 1;
- ET1 = 1;
- TR0 = 1;
- TR1 = 1;
-
- num_shi = 12;
- while(1)
- {
-
- shiwan = num_shi/10;
- wan = num_shi%10;
- qian = num_fen/10;
- bai = num_fen%10;
- shi = num_miao/10;
- ge = num_miao%10;
-
- display(shiwan,wan,qian,bai,shi,ge);
-
- }
-
- }
-
-
- void T0_Handle() interrupt 1
- {
- EA = 0;
- TR0 = 0;
- fixtime = TL0+0x0A;
- TL0 = fixtime;
- TH0 = 0x4C+(char)CY;
- EA = 1;
- TR0 = 1;
- count_fen0++;
- count_fen1++;
- count_shi++;
- count_miao++;
-
- T0_Handle_Program();
- }
-
- void T1_Handle() interrupt 3
- {
- EA = 0;
- TR1 = 0;
- fixtime = TL1+0x0A;
- TL1 = fixtime;
- TH1 = 0x4C+(char)CY;
- EA = 1;
- TR1 = 1;
- key_handle();
-
- }
误差:
可以看到在调试中,1分钟内的误差为0,理论误差满足设计要求。
效果:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。