51单片机利用锁存器控制数码管显示年月日时分秒
2022-06-28 来源:eefocus
数码管模块中的两片74hc573,一片锁存段码,一片锁存位码,这样才能驱动8位数码管。74hc573是锁存器,用于数码管显示时通常是采用段选、片选共用同一组并口的驱动方式。
驱动数码管需要两个信号,一个是段选信号,另一个是片选信号。段选信号是固定的8个(对于普通7段数码管),而片选信号数量是与数码管位数相同的。
对于8位数码管的动态扫描来说,片选信号要8根线,这样仅仅驱动数码管就占用了16个IO口,非常浪费。
原理
使用573锁存器后,只占用10个IO口,其中2个用于控制锁存器使能,另外8个用于输出信号。先关闭控制片选信号的573芯片的锁存功能,然后单片机输出片选信号。随后再开启锁存,此时无论573的输入端如何变化,输出端都是不变的,也就是原来输入的信号被锁住了。然后再关闭控制段选的573的锁存功能,输出段选信号再锁存,这样就巧妙地实现了数据线的复用,让一组IO口既输出段选又输出片选。
由于数码管数量有限,时分秒与年月日将隔两秒分别显示。
#include #include char code table[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90}; sbit duan=P3^7; sbit wei=P3^6; void delay(int t) { int x,y; for(x=t;x>0;x--) for(y=10;y>0;y--); } void nop() { _nop_(); _nop_(); } //这几个变量是全局变量,主要用在主函数中 //不会影响到disp函数中的几个变量 int abc,time,num,sec,min,hour; /************************************************* *该函数的功能作用是在开发箱的数码管显示时分秒 *开发箱上面的数码管从左往右是第0位到第7位 *在选择第几位的时候就给P1赋值2的第几位次方 *比如,显示在数码管的第3位,就给P1赋值2的3次方也就是8这个数值 ***********************************************32***/ void disp(int sec, int min, int hour) { duan=0; P1=table[hour/10];//显示时间的十位 duan=1; duan=0; wei=0; P1=1;//显示在数码管的第0位。2的0次方等于1 wei=1; wei=0; delay(10); duan=0; P1=table[hour%10];//显示时间的个位 duan=1; duan=0; wei=0; P1=2;//显示在数码管的第1位。2的1次方等于2 wei=1; wei=0; delay(10); P1=table[min/10];//显示分钟的十位 duan=1; duan=0; P1=4;//显示在数码管的第2位。2的2次方等于4 wei=1; wei=0; delay(10); P1=table[min%10];//显示分钟的个位 duan=1; duan=0; P1=8;//显示在数码管的第3位。2的3次方等于8 wei=1; wei=0; delay(10); P1=table[sec/10];//显示秒钟的十位 duan=1; duan=0; P1=16;//显示在数码管的第4位。2的4次方等于16 wei=1; wei=0; delay(10); P1=table[sec%10];//显示秒钟的个位 duan=1; duan=0; P1=32;//显示在数码管的第5位。2的5次方等于32 wei=1; wei=0; delay(10); }//100 int year,month,date; void disp2() { duan=0; P1=table[year/1000];//显示年的千位 duan=1; duan=0; wei=0; P1=1;//显示在数码管的第0位。2的0次方等于1 wei=1; wei=0; delay(10); duan=0; P1=table[year%1000/100];//百位 duan=1; duan=0; wei=0; P1=2;//显示在数码管的第1位。2的1次方等于2 wei=1; wei=0; delay(10); P1=table[year%100/10];//十位 duan=1; duan=0; P1=4;//显示在数码管的第2位。2的2次方等于4 wei=1; wei=0; delay(10); P1=table[year%10];//个位 duan=1; duan=0; P1=8;//显示在数码管的第3位。2的3次方等于8 wei=1; wei=0; delay(10); P1=table[month/10];//显示月的十位 duan=1; duan=0; P1=16;//显示在数码管的第4位。2的4次方等于16 wei=1; wei=0; delay(10); P1=table[month%10];//显示月的个位 duan=1; duan=0; P1=32;//显示在数码管的第5位。2的5次方等于32 wei=1; wei=0; delay(10); P1=table[date/10];//显示日期的十位 duan=1; duan=0; P1=64;//显示在数码管的第6位。2的6次方等于64 wei=1; wei=0; delay(10); P1=table[date%10];//显示日期的个位 duan=1; duan=0; P1=128;//显示在数码管的第7位。2的7次方等于128 wei=1; wei=0; delay(10); } int show_flag = 0,show_time = 0; void main (void) { // /*定时器0初始化,定时时间50毫秒*/ TMOD=0x01;//定时器方式寄存器 TR0=1;//T0定时器/计数器的运行控制位 ET0=1;//中断允许寄存器中T0定时器/计数器的允许 TH0=(65536-50000)/256; TL0=(65536-50000)%256; EA=1;//中断控制的 总允许 /*********/ //时间初始化 year = 2021; month = 5; date = 24; hour = 10; min = 30; sec = 50; while(1) { if(sec==60) { sec=0; min++; if(min==60) { min=0; hour++; if(hour==24) { hour=0; date++; if((month==4 || month==6 || month == 9 || month == 11) && date==31) { month++; date = 1; } else if(month == 2) { //判断年是否为闰年,以此来判断date是28+1进1还是29+1进一 } else if(month==1 || month==3 || month == 5 || month == 7|| month == 8 || month == 10 || month == 12) && date==32) { month++; date = 1; } } } } //每隔两秒切换一次显示 if(show_flag == 0) disp(sec,min,hour);//显示时分秒 else disp2();//显示年月日 } } //定时器0的中断服务函数,不需要主动调用 void time0() interrupt 1 { TH0=(65536-50000)/256; TL0=(65536-50000)%256; time++; //定时一次50毫秒,20次后是1秒,秒数+1 if(time==20) { time=0; show_time++; sec++; //每隔两秒改变show_flag的值,如果要修改切换的时间,修改下面的2为其他整数就好 if(show_time%2 ==0) { show_flag = !show_flag; } } }