|
- /*
- 基于C51系列的共阴数码管实现的数字时钟系统74595+74154+15个数码管
- Proteus 的仿真结果未必和实体运行结果一致,没有部分特殊功能寄存器而无法实现仿真。
- 仿真文件由Proteus 7.7 SP2所生成,若无法打开,请升级到更高的版本。
- 请一定要点击复制代码再粘贴到Keil4中编译,否则编译时可能会出现其他问题。
- 本源码需要头文件 stc12c5a60s2.h 若不存在 请访问STC官网或打开STC烧录软件获取即可。
- 版本修订历史:
- (2018-02-12) V1.1
- 新增蜂鸣器整点报时功能,7:00~21:00报时,其余时间不报。
- 上电初始年由2000年改为2018年,可在源码中自行修改
- 可调年月日时分秒星期 (不含自动计算星期的函数)
- 修正了日期调到2月31日等无效日期仍然可以正常走时的bug。
- 修正了年月日时分秒星期的调整顺序。
- 单片机型号:STC12C5A**S2 其中**是容量的意思,没有过多要求。
- 晶振频率:24Mhz By:LscmunaixMG 2018-02-12
- */
- #include "stc12c5a60s2.h"
- #include "intrins.h"
- #define ui unsigned int
- #define uc unsigned char
- uc code nbr[16]={ //共阴数码管段码数据,严禁修改否则会显示乱码。
- 0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71
- };
- sbit SRCLK = P2^0; //74595 串行数据时钟输入
- sbit SER = P2^1; //74595 串行数据输入
- sbit LATCH = P2^2; //74595 锁存信号输入
- sbit A3=P2^3; //74154译码输入3
- sbit A2=P2^4; //74154译码输入2
- sbit A1=P2^5; //74154译码输入1
- sbit A0=P2^6; //74154译码输入0
- sbit EN=P2^7; //74154 低电平使能
- sbit K0=P3^3; //按键0,按下后进入时间调节模式,调节完毕后恢复正常走时功能。
- sbit K1=P3^4; //按键1,在时间调节模式下对调节的日期时间加1,长按连续加。
- sbit LED=P3^2; //秒闪烁LED,可并联两个LED作为冒号。
- sbit beep=P3^5; //有源蜂鸣器
- unsigned char bd=0; //蜂鸣器时间计数
- ui y; //定义变量年
- uc m,d,h,i,s,w; //定义变量月、日、时、分、秒、周
- uc ms5; //5毫秒定时器中断计数 中断200次计数即为1秒
- uc adt; //调时标志位 0走时 1调年 2调月 3调日 4调星期 5调时 6调分 7调秒
- bit lj; //调时闪烁标志,0点亮1熄灭部分日期时间的显示,每隔数毫秒进行切换。
- uc ld; //调时按键按下时间计数,按键放开或叠加日期时间则清零
- uc sld; //调试按键按下时间计数超过此值连续叠加日期时间,按键放开清零
- void InitTimer0(void){ //初始化5毫秒定时器,根据晶振频率修改TH0和TL0的值。
- TMOD = 0x01;
- TH0 = 0xEC;
- TL0 = 0x78;
- EA = 1;
- ET0 = 1;
- TR0 = 1;
- }
- bit if_leap_year(ui y){ //平闰年检测,闰年返回1,平年返回0
- //闰年是4的倍数且不是100的倍数或者是400的倍数,否则是平年。
- if((y%4 == 0 && y%100 != 0) || y%400 == 0){
- return 1; //返回1表示闰年
- } else { //否则就是平年
- return 0; //返回0表示平年
- }
- }
- uc get_mon_day_nbr(ui y,uc m){ //通过年月获取该月有多少天
- if(m == 1 || m == 3 || m == 5 || m == 7 || m == 8 || m == 10 || m == 12) { //大月则31天
- return 31;
- }
- if(m == 4 || m == 6 || m == 9 || m == 11){ //小月则30天
- return 30;
- }
- if(m == 2){ //2月
- if(if_leap_year(y) == 1){ //闰年29天
- return 29;
- } else { //平年28天
- return 28;
- }
- }
- return 0;
- }
- bit dt_is_ok(ui y,uc m,uc d,uc w,uc h,uc i,uc s){ //检测设置的日期时间格式是否有效 1有效0无效
- if(w > 7 || w < 1) return 0; //星期大于7或小于1 返回0
- if(y > 9999 || m > 12 || m < 1 || d < 1) return 0; //年大于9999 或 月大于12 或 月小于1 或日小于1 返回0
- if(d > get_mon_day_nbr(y,m)) return 0; //通过年月获取当月天数 大于该值 返回0
- if(h > 23 || i > 59 || s > 59) return 0; //时大于23 或 分大于59 或秒大于59 返回0
- return 1; //检测有效 返回1
- }
- bit set_time(ui yy,uc mm,uc dd,uc ww,uc hh,uc ii,uc ss){ //设置日期时间
- if(dt_is_ok(yy,mm,dd,ww,hh,ii,ss) == 1){ //检查日期时间格式有效
- y=yy;m=mm;d=dd;w=ww; //设置年月日周
- h=hh;i=ii;s=ss; //设置时分秒
- return 1; //设置成功 返回1
- } else { //格式无效 返回0
- return 0;
- }
- }
- void add_time(){ //时间步进1秒
- s++; //秒加1
- if(s > 59){ //秒超过59
- s=0; //秒清零
- i++; //分加1
- if(i > 59){ //分超过59
- i=0; //分清零
- h++; //时加1
- if(h > 23){ //时超过23
- h=0; //时清零
- d++; //日加1
- w++; //星期加1
- if(w > 7){ //星期超过7
- w=1; //星期等于1
- }
- if(d > get_mon_day_nbr(y,m)){ //日超过当前年月的天数
- d=1; //日清1
- m++; //月加1
- if(m > 12){ //月加到12以上
- m=1; //月清1
- y++; //年加1
- if(y > 9999){ //年超过9999
- y=0; //年清零
- }
- }
- }
- }
- }
- }
- }
- void add_time2(){ //时间步进1天
- if(w > 7){ //星期超过7
- w=1; //星期等于1
- }
-
- if(d > get_mon_day_nbr(y,m)){ //日超过当前年月的天数
- d=1; //日清1
- m++; //月加1
- }
- if(m > 12){ //月加到12以上
- m=1; //月清1
- y++; //年加1
- }
- if(y > 9999){ //年超过9999
- y=0; //年清零
- }
-
- }
- void Delay1ms() //@12MHz
- {
- unsigned char i, j;
- _nop_();
- _nop_();
- i = 12;
- j = 168;
- do
- {
- while (--j);
- } while (--i);
- }
- void SendByte(uc dat)
- {
- uc i;
-
- for(i=0;i<8;i++)
- {
- SRCLK=0; //先将串行时钟输入端SRCLK置成低电平
- SER=dat&0x80; //每次只取一位
- dat<<=1; //每次只取一位进行左移
- SRCLK=1; //数据在串行时钟输入端SRCLK的上升沿输入到移位寄存器中
- }
-
- }
- void Out595(void)
- {
- LATCH=0;//锁存
- _nop_();//空指令
- LATCH=1;//LATCH上升沿并行数据输出
- }
- void out_y(bit o){
- A0=0;A1=0;A2=0;A3=0;SendByte(nbr[y/1000%10]);Out595();EN=!o;Delay1ms();EN=1; //年的千位
- A0=0;A1=0;A2=0;A3=1;SendByte(nbr[y/100%10]);Out595();EN=!o;Delay1ms();EN=1; //年的百位
- A0=0;A1=0;A2=1;A3=0;SendByte(nbr[y/10%10]);Out595();EN=!o;Delay1ms();EN=1; //年的十位
- A0=0;A1=0;A2=1;A3=1;SendByte(nbr[y%10]);Out595();EN=!o;Delay1ms();EN=1; //年的个位
- }
- void out_m(bit o){
- A0=0;A1=1;A2=0;A3=0;SendByte(nbr[m/10]);Out595();EN=!o;Delay1ms();EN=1; //月的十位
- A0=0;A1=1;A2=0;A3=1;SendByte(nbr[m%10]);Out595();EN=!o;Delay1ms();EN=1; //月的个位
- }
- void out_d(bit o){
- A0=0;A1=1;A2=1;A3=0;SendByte(nbr[d/10]);Out595();EN=!o;Delay1ms();EN=1; //日的十位
- A0=0;A1=1;A2=1;A3=1;SendByte(nbr[d%10]);Out595();EN=!o;Delay1ms();EN=1; //日的个位
- }
- void out_w(bit o){
- A0=1;A1=0;A2=0;A3=0;SendByte(nbr[w%10]);Out595();EN=!o;Delay1ms();EN=1; //星期
- }
- void out_h(bit o){
- A0=1;A1=0;A2=0;A3=1;SendByte(nbr[h/10]);Out595();EN=!o;Delay1ms();EN=1; //时的十位
- A0=1;A1=0;A2=1;A3=0;SendByte(nbr[h%10]);Out595();EN=!o;Delay1ms();EN=1; //时的个位
- }
- void out_i(bit o){
- A0=1;A1=0;A2=1;A3=1;SendByte(nbr[i/10]);Out595();EN=!o;Delay1ms();EN=1; //分的十位
- A0=1;A1=1;A2=0;A3=0;SendByte(nbr[i%10]);Out595();EN=!o;Delay1ms();EN=1; //分的个位
- }
- void out_s(bit o){
- A0=1;A1=1;A2=0;A3=1;SendByte(nbr[s/10]);Out595();EN=!o;Delay1ms();EN=1; //秒的十位
- A0=1;A1=1;A2=1;A3=0;SendByte(nbr[s%10]);Out595();EN=!o;Delay1ms();EN=1; //秒的个位
- }
- void out_nbr(bit o_y,bit o_m,bit o_d,bit o_w,bit o_h,bit o_i,bit o_s){ //输出时间到数码管
- out_y(o_y); //输出年
- out_m(o_m); //输出月
- out_d(o_d); //输出日
- out_w(o_w); //输出星期
- out_h(o_h); //输出时
- out_i(o_i); //输出分
- out_s(o_s); //输出秒
- Delay1ms(); //延时1毫秒
- }
- void out_nbrs(){ //输出时间到数码管 包含调时闪烁
- if(adt == 0){ //正常走时
- out_nbr(1,1,1,1,1,1,1); //输出所有时间
- } else { //调时模式
- switch(adt){
- case 1:out_nbr(lj,1,1,1,1,1,1);break; //年闪烁
- case 2:out_nbr(1,lj,1,1,1,1,1);break; //月闪烁
- case 3:out_nbr(1,1,lj,1,1,1,1);break; //日闪烁
- case 4:out_nbr(1,1,1,1,lj,1,1);break; //时闪烁
- case 5:out_nbr(1,1,1,1,1,lj,1);break; //分闪烁
- case 6:out_nbr(1,1,1,1,1,1,lj);break; //秒闪烁
- case 7:out_nbr(1,1,1,lj,1,1,1);break; //周闪烁
- default:
- adt=0;
- while(!dt_is_ok(y,m,d,w,h,i,s)){ //无效时间一直循环,有效为止
- add_time2(); //时间步进1天
- out_nbr(1,1,1,1,1,1,1);
- }
- EA=1;
- break; //退出调时模式
- }
- }
- }
- void set_time_key(){
- switch(adt){
- case 1: //调年
- y++; //年加1
- if(y > 9999)y=0; //年超过9999则清0
- break;
- case 2: //调月
- m++; //月加1
- if(m > 12)m=1; //月超过12则清1
- break;
- case 3: //调日
- d++; //日加1
- if(d > get_mon_day_nbr(y,m))d=1; //日超过当月天数则清1
- break;
- case 4: //调时
- h++; //时加1
- if(h > 23) h=0; //时超过23则清0
- break;
- case 5: //调分
- i++;//分加1
- if(i > 59) i=0; //分超过59则清0
- break;
- case 6: //调秒
- s++;//秒加1
- if(s > 59) s=0; //秒超过59则清0
- break;
- case 7: //调星期
- w++; //星期加1
- if(w > 7) w=1; //星期超过7则清1
- break;
-
- default:break;
- }
- }
- void main(){ //硬件上电首先进入此函数
- CLK_DIV = 0x01;
- adt=0;
- set_time(2018,1,1,1,0,0,0); //设置日期时间
- // AUXR = AUXR|0x80;
- InitTimer0();
-
- while(1){ //进入死循环
- out_nbrs();
- if(K0 == 0){
- out_nbrs();
- if(K0 == 0){
- adt++;
- bd=0;
- while(K0 == 0){
- if(bd<5) {bd++;beep=0;} else {beep=1;}
- out_nbrs();
- } //按键放开
- beep=1;bd=0;
- }
- }
- if(K1 == 0 && adt != 0){
- out_nbrs();
- if(K1 == 0){
- set_time_key();
- sld=50;
- bd=0;
- while(K1 == 0){
- if(bd<5) {bd++;beep=0;} else {beep=1;}
- ld++;
- out_nbrs();
- if(ld > sld){
- sld=25;
- ld=0;
- beep=0;
- set_time_key();
- out_nbrs();out_nbrs();
- beep=1;
- } //if
- } //while
- ld=0;
- bd=0;beep=1; //解除蜂鸣器鸣叫
- }
- }
-
- }
- }
- void Timer0Interrupt(void) interrupt 1{ //5毫秒定时器中断
- //重置TH0与TL0的值,根据晶振频率修改TH0和TL0的值。
- TH0 = 0xEC;
- TL0 = 0x78;
- ms5++; //5毫秒中断计数加1
- if(ms5%40 == 0 && adt != 0)lj=~lj;//每200毫秒切换一次数码管亮灭状态(调时模式有效)
- //5毫秒中断计数加到200 200*5=1000毫秒 1秒触发1次
- if(ms5%100 == 0 && adt == 0) { //正常走时模式下,每半秒切换一次闪灯亮灭状态
- LED=~LED;
- } else {
- if(adt != 0) LED = 1; //调时模式始终熄灭LED
- }
- if(ms5 >= 200){
-
- ms5=0; //5毫秒计数清零
- if(adt ==0) { //只有正常走时状态就会加秒。
- add_time(); //时间步进1秒
- if(i == 0 && s == 0){ //分秒等于0 整点报时
- switch(h){ //7点到21点整报时 蜂鸣器鸣叫1秒 其余时间不报
- case 7:beep=0;break;
- case 8:beep=0;break;
- case 9:beep=0;break;
- case 10:beep=0;break;
- case 11:beep=0;break;
- case 12:beep=0;break;
- case 13:beep=0;break;
- case 14:beep=0;break;
- case 15:beep=0;break;
- case 16:beep=0;break;
- case 17:beep=0;break;
- case 18:beep=0;break;
- case 19:beep=0;break;
- case 20:beep=0;break;
- case 21:beep=0;break;
- default:beep=1;break;
- }
- } else {
- beep=1;
- }
- }
- }
-
- }
复制代码
|
|