找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 14847|回复: 23
打印 上一主题 下一主题
收起左侧

单片机数码管时钟电路图+源码

  [复制链接]
跳转到指定楼层
楼主
用STC89c52单片机,12M晶振。计时用T2定时器,16位自动重装模式  基本功能如下: 可以显示年份、月、日、时间,有闹钟功能,有倒计时功能。 上电默认显示时间,可通过按键切换显示年份、日期、闹钟、倒计时,显示一定时间后自动返回到时间显示。 在相应的显示状态下按设置键进行相应的设置。如在时间显示时按设置键可调整时间。其余类推倒计时最多可以倒数99小时59分59秒,设置完倒计时时间后进入倒数状态,闪烁显示倒数时间,中途可按键退出,倒数结束后铃响1分钟返回时间显示。 闹钟可选择开或关,闹铃响1分钟停止。

电路原理图如下:


制作出来的实物图如下:


单片机源程序如下:
  1. #include <reg52.h>

  2. #define uchar unsigned char
  3. #define uint unsigned int

  4. #define DispOFF 10;        //显示关
  5. #define POINT 21;        //显示小点
  6. #define F 22;
  7. #define H 23;
  8. #define M 24;
  9. #define N 25;
  10. #define O 26;

  11. sbit buzzer=P3^7;        //蜂鸣器控制脚

  12. uchar T2Count;
  13. uint T0Count;
  14. uchar key,key_new,key_old,KeyPressTime;
  15. uchar status;
  16. uchar month,day,hour,min,sec,AlarmHr,AlarmMin;
  17. uchar LastDay;
  18. uchar AlmTime,AlmCount,DispTime;
  19. uchar CountHr,CountMin,CountSec,CountSetSta=0;
  20. uint year;
  21. bit TimeAdj,AlarmAdj,AlarmSta;
  22. bit adjust,DigiBit;
  23. //数码管显示代码
  24. uchar code LedCode[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xff,
  25.                       0x40,0x79,0x24,0x30,0x19,0x12,0x02,0x78,0x00,0x10,0x7f,
  26.                                           0x8e,0x89,0xc8,0xab,0xa3
  27.                      };
  28. uchar Disp[4];

  29. void LedScan(void);
  30. void KeyScan(void);
  31. void years(void);
  32. void date(void);
  33. void timer(void);
  34. void alarmClock(void);
  35. void CountDown(void);
  36. void ring(void);
  37. uchar DaysCount(void);

  38. void Init(void)
  39. {
  40. TH2=0x3c;TL2=0xb0;
  41. RCAP2H=0x3c;RCAP2L=0xb0;
  42. EA=1;ET2=1;
  43. TR2=1;
  44. TMOD=0x01;
  45. //TH0=0x3c;
  46. //TL0=0xb0;
  47. ET0=1;
  48. P1=0xff;
  49. year=2011;
  50. month=1;
  51. day=1;
  52. hour=0;
  53. min=0;
  54. status=2;
  55. buzzer=1;
  56. }
  57. /************主函数*************/
  58. void main(void)
  59. {
  60. Init();
  61. while(1)
  62.    {
  63.     KeyScan();
  64.     LastDay=DaysCount();
  65.         switch(status)        //显示状态                               
  66.              {
  67.                   case 0:years();break;                        //显示年
  68.                   case 1:date();break;                        //显示日期
  69.                   case 2:timer();break;                        //显示时间
  70.           case 3:alarmClock();break;        //显示闹钟时间
  71.                   case 4:CountDown();break;                //显示倒计时
  72.          }
  73.     LedScan();       
  74.     ring();
  75.    }
  76. }

  77. /***************定时器T0中断函数,用于倒计时**************/
  78. void timer0(void) interrupt 1 using 2
  79. {TH0=0x3c;
  80. TL0=0xb0;
  81. T0Count++;
  82. if(CountHr||CountMin||CountSec)
  83.         {if(T0Count==20)
  84.                 {CountSec--;T0Count=0;}
  85.          if(CountSec>=60)
  86.                 {CountSec=59;CountMin--;}
  87.          if(CountMin>=60)
  88.                 {CountMin=59;CountHr--;}
  89.         }
  90. if(T0Count==1200)
  91.         {TR0=0;
  92.          T0Count=0;
  93.         }
  94. }
  95. /**************定时器T2中断函数,用于计时**************/
  96. void timer2(void) interrupt 5 using 1
  97. {
  98. TF2=0;
  99. if(++T2Count==20)
  100.    {sec++;T2Count=0;}
  101. if(!TimeAdj)        //时间调整时,暂停计时
  102.         {if(sec==60)
  103.                    {min++;sec=0;}
  104.          if(min==60)
  105.                    {hour++;min=0;}
  106.          if(hour==24)
  107.                    {day++;hour=0;}
  108.          if(day>LastDay)
  109.                    {month++;day=1;}
  110.          if(month>12)
  111.             {year++;month=1;}
  112.         }
  113. }

  114. void delay(uchar x)
  115. {
  116. uchar k;
  117. while(x--)
  118.       for(k=0;k<123;k++);
  119. }
  120. /***********数码管扫描显示函数***************/
  121. void LedScan(void)
  122. {
  123. uchar i;
  124. uchar temp=0x08;
  125. for(i=0;i<4;i++)
  126.     {
  127.      P0=LedCode[Disp[i]];        //送段码
  128.      P2=~temp;temp>>=1;                //LED显示位控制
  129.      delay(3);                                //延时
  130.          P2=0xff;                                //关显示
  131.     }
  132. }
  133. /**********按键扫描程序***************/
  134. void KeyScan(void)
  135. {
  136. if((P1&0x0f)!=0x0f)                //如果按下按键
  137.    {if(KeyPressTime>0)                //延时
  138.           {
  139.            switch(~(P1|0xf0))        //判断键值
  140.              {
  141.               case 0x01:key_new=1;break;
  142.               case 0x02:key_new=2;break;
  143.               case 0x04:key_new=3;break;
  144.                           case 0x08:key_new=4;break;
  145.                          }
  146.           }
  147.         KeyPressTime++;                        //按键时间加1
  148.    }
  149. else                                                //如果没有按键按下
  150.    {key_new=0;                                //键值清零
  151.     KeyPressTime=0;                        //按键时间清零
  152.    }
  153. if(key_new!=key_old)                //如果前后两次键值不同
  154.     {key=key_new;                        //键值等于本次键值
  155.         }
  156. else                                                //如果前后两次键值相同(按住按键未释放)
  157.    {key=0;                                        //键值清零
  158.     if(KeyPressTime>100)        //按键时间大于100,差不多1秒(作长按键处理)
  159.           {KeyPressTime-=30;        //按键时间减30,当累加到100再次动作,相当于300毫秒按键一次,
  160.            key=key_new;                        //得到本次键值
  161.           }
  162.    }
  163. key_old=key_new;                   //记住本次键值
  164. }
  165. /***********计算本月有多少天**************/
  166. uchar DaysCount(void)                                                       
  167. {
  168. if(month==4||month==6||month==9||month==11)                //4、6、9、11月为30天
  169.    return 30;
  170. else if(month!=2)                                                                //1、3、5、7、8、10、12月为31天
  171.         return 31;
  172. if(month==2)
  173.   {if((year%4==0&&year%100!=0)||(year%400==0))
  174.       return 29;                                                                //闰年2月为29天
  175.    else
  176.       return 28;                                                                //非闰年2月为28天
  177.   }
  178. }
  179. /**************年函数**************/
  180. void years(void)
  181. {
  182. if(adjust)                //设置,调整年
  183.    {
  184.         switch(key)        //处理按键
  185.                 {case 1:{
  186.                              year++;                //年加1
  187.                                  break;
  188.                                 }
  189.                  case 2:{
  190.                                  year--;                //年减1
  191.                  break;
  192.                                 }
  193.                  case 3:{
  194.                                  adjust=0;                //退出设置
  195.                                  DispTime=0;
  196.                                  break;
  197.                                  }
  198.             }
  199.    }
  200. else
  201.    {
  202.     if(key==2) status++;                //显示状态加1,进入日期显示
  203.         if(key==3) adjust=1;                //进入设置
  204.         if(++DispTime==200)                        //显示时间加1,系统默认显示时间,通过按键切换其他显示一段时间后自动返回时间显示
  205.                 {status=2;                                //利用程序循环执行一次的时间作延时,每循环一次DispTime+1,加到200后退出返回时间显示
  206.                   DispTime=0;                        //DispTime清零
  207.                 }
  208.    }
  209. Disp[0]=year/1000;                                //年份千位
  210. Disp[1]=year/100%10;                        //年份百位
  211. Disp[2]=year/10%10;                        //年份十位
  212. Disp[3]=year%10;                                //年份个位
  213. if(T2Count<=10)
  214.    {if(adjust)                                        //如果调整年份,显示闪烁
  215.            Disp[0]=Disp[1]=Disp[2]=Disp[3]=DispOFF;                                 
  216.    }
  217. }
  218. /***********日期函数***************/
  219. void date(void)
  220. {
  221. if(adjust)        //调整日期
  222.    {
  223.         switch(key)
  224.             {case 1:{
  225.                                  if(DigiBit==0) month++;        //月加1
  226.                                  else day++;                                //日加1
  227.                  if(month>12) month=1;                //月大于12,月份等于1
  228.                                  if(day>LastDay) day=1;                //日大于本月最后一日,日等于1
  229.                                  break;
  230.                                 }
  231.                  case 2:{
  232.                                  if(DigiBit==0) month--;        //月减1
  233.                                  else day--;                                //日减1
  234.                                  if(month==0) month=12;                //月=0,月份=12
  235.                                  if(day==0) day=LastDay;        //日=0,日等于本月最后一天
  236.                  break;
  237.                                 }
  238.                  case 3:{
  239.                                  DigiBit=~DigiBit;                        //月、日设置选择切换
  240.                                  if(DigiBit==0)                                //DigiBit=0 选择月 DigiBit=1 选择日
  241.                                           {adjust=0;                               
  242.                                          DispTime=0;
  243.                                         }
  244.                                  break;
  245.                                 }
  246.                 }                         
  247.    }
  248. else
  249.    {
  250.         if(key==1) {status--;DispTime=0;}                //显示年,显示时间清零重新计算
  251.     if(key==2) status++;                                        //显示时间
  252.         if(key==3) adjust=1;                                        //进入设置
  253.         if(++DispTime==200)                                                //显示时间到,返回时间显示
  254.                 {status=2;
  255.                   DispTime=0;
  256.                 }
  257.    }
  258. Disp[0]=month/10;
  259. Disp[1]=month%10;
  260. Disp[2]=day/10;
  261. Disp[3]=day%10+11;
  262. if(T2Count<=10)
  263.    {if(adjust)
  264.           {
  265.            if(!DigiBit)                        //如果调整日,日显示闪烁
  266.              {
  267.                   Disp[0]=DispOFF;
  268.                   Disp[1]=DispOFF;
  269.                  }
  270.            else                                        //如果调整月,月显示闪烁
  271.                  {
  272.                   Disp[2]=DispOFF;
  273.                   Disp[3]=POINT;
  274.                  }
  275.           }                                         
  276.    }
  277. }
  278. /**************时间函数****************/
  279. void timer(void)
  280. {
  281. if(TimeAdj)        //调整时间
  282.    {
  283.         switch(key)
  284.                 {case 1:{                        //up/加 按键
  285.                                  if(DigiBit==0) hour++;        //根据按键选择时间、分钟加调整
  286.                                  else min++;
  287.                  if(hour==24) hour=0;
  288.                                  if(min==60) min=0;
  289.                                  break;
  290.                                 }
  291.                  case 2:{                        //down 减 按键
  292.                                  if(DigiBit==0) hour--;        //时间、分钟减调整
  293.                                  else min--;
  294.                                  if(hour>=24) hour=23;
  295.                                  if(min>=60) min=59;
  296.                  break;
  297.                                 }
  298.                  case 3:{
  299.                                  DigiBit=~DigiBit;                //DigiBit=0 小时,DigiBit=1 分钟
  300.                                  if(DigiBit==0)                 //时间设置完后,秒清零,定时器重新计时
  301.                                          {sec=0;
  302.                                          TR2=0;
  303.                                          TH2=0x3c;TL2=0xb0;
  304.                                          T2Count=0;
  305.                                          TR2=1;
  306.                                          TimeAdj=0;
  307.                                         }
  308.                                  break;
  309.                                 }
  310.                    }
  311.    }
  312. else
  313.    {
  314.         if(key==1) {status--;DispTime=0;}
  315.     if(key==2) {status++;DispTime=80;}//进入闹钟显示,显示时间初始值为80
  316.         if(key==3) TimeAdj=1;
  317.    }
  318. Disp[0]=hour/10;
  319. Disp[1]=hour%10;
  320. Disp[2]=min/10+11;
  321. Disp[3]=min%10+11;
  322. if(T2Count<=10)
  323.    {if(TimeAdj)
  324.           {
  325.            if(!DigiBit)
  326.                  {
  327.                   Disp[0]=DispOFF;
  328.                   Disp[1]=DispOFF;
  329.                  }
  330.            else
  331.                  {
  332.                   Disp[2]=POINT;
  333.                   Disp[3]=POINT;
  334.                  }
  335.           }
  336.         else
  337.           {
  338.            Disp[2]=min/10;
  339.            Disp[3]=min%10;       
  340.           }
  341.    }
  342. }
  343. /*************闹钟函数***************/
  344. void alarmClock(void)
  345. {Disp[0]=AlarmHr/10;
  346. Disp[1]=AlarmHr%10;
  347. Disp[2]=AlarmMin/10+11;
  348. Disp[3]=AlarmMin%10+11;
  349. if(DispTime<80)//显示时间<80,显示闹钟开关状态,显示时间>=80,显示闹钟时间
  350.         {if(AlarmSta)
  351.                 {Disp[0]=DispOFF;
  352.                  Disp[1]=DispOFF;
  353.                  Disp[2]=O;
  354.                  Disp[3]=N;
  355.                 }
  356.          else
  357.                  {Disp[0]=DispOFF;
  358.                  Disp[1]=O;
  359.                  Disp[2]=F;
  360.                  Disp[3]=F;
  361.                 }
  362.         }
  363. if(AlarmAdj)//设置闹钟时间
  364.    {
  365.         switch(key)
  366.                 {case 1:{
  367.                                  if(DigiBit==0) AlarmHr++;
  368.                                  else AlarmMin++;
  369.                  if(AlarmHr==24) AlarmHr=0;
  370.                                  if(AlarmMin==60) AlarmMin=0;
  371.                                  break;
  372.                                 }
  373.                  case 2:{
  374.                                  if(DigiBit==0) AlarmHr--;
  375.                                  else AlarmMin--;
  376.                                  if(AlarmHr>=24) AlarmHr=23;
  377.                                  if(AlarmMin>=60) AlarmMin=59;
  378.                  break;
  379.                                 }
  380.                  case 3:{
  381.                                  DigiBit=~DigiBit;
  382.                                  if(DigiBit==0)
  383.                                          {AlarmAdj=0;
  384.                                          DispTime=80;
  385.                                         }
  386.                                  break;
  387.                                 }
  388.                 }
  389.     if(T2Count<=10)
  390.           {
  391.            if(!DigiBit)
  392.                  {
  393.                   Disp[0]=DispOFF;
  394.                   Disp[1]=DispOFF;
  395.                  }
  396.            else
  397.               {
  398.                    Disp[2]=POINT;
  399.                    Disp[3]=POINT;
  400.                   }
  401.       }
  402.    }
  403. else
  404.    {
  405.         if(key==1) status--;
  406.     if(key==2)
  407.             {status++;
  408.                  DispTime=0;
  409.                 }
  410.         if(key==3) AlarmAdj=1;
  411.         if(key==4)//闹钟开关按键
  412.                 {if(DispTime<80)                //初次按下,显示上次设置状态
  413.                         AlarmSta=~AlarmSta;        //再按可改变设置
  414.                  DispTime=0;//每按一次,显示时间清零,显示闹钟开关状态
  415.                 }
  416.         DispTime++;
  417.         if(DispTime==255)
  418.                 {status=2;
  419.                  DispTime=0;
  420.                 }
  421.    }

  422. }
  423. /**************倒计时函数*****************/
  424. void CountDown(void)
  425. {
  426. if(adjust)//设置倒数时间
  427.    {
  428.         switch(CountSetSta)
  429.                 {case 0:{//设置倒数小时
  430.                                  if(key==1) CountHr++;
  431.                                  if(key==2) CountHr--;
  432.                                  if(key==3) CountSetSta++;
  433.                                  if(CountHr==100) CountHr=0;
  434.                                  if(CountHr>100) CountHr=99;
  435.                                  Disp[0]=H;
  436.                                  Disp[1]=DispOFF;
  437.                                  Disp[2]=CountHr/10;
  438.                                  Disp[3]=CountHr%10;
  439.                                  break;
  440.                                 }
  441.                  case 1:{//设置倒数分钟
  442.                                  if(key==1) CountMin++;
  443.                                  if(key==2) CountMin--;
  444.                                  if(key==3) CountSetSta++;
  445.                                  if(CountMin==60) CountMin=0;
  446.                                  if(CountMin>60) CountMin=59;
  447.                                  Disp[0]=M;
  448.                                  Disp[1]=DispOFF;
  449.                                  Disp[2]=CountMin/10;
  450.                                  Disp[3]=CountMin%10;
  451.                                  break;
  452.                                 }
  453.                  case 2:{//设置倒数秒
  454.                                  if(key==1) CountSec++;
  455.                                  if(key==2) CountSec--;
  456.                                  if(key==3) //设置键
  457.                                          {if(CountHr||CountMin||CountSec)//设置完成后,若倒数的时、分、秒不为零,倒计时开始
  458.                                                 {TH0=0x3c; TL0=0xb0;
  459.                                                  T0Count=0;
  460.                                                   TR0=1;
  461.                                                 }
  462.                                          CountSetSta=0;
  463.                                          adjust=0;
  464.                                          DispTime=0;
  465.                                         }
  466.                                  if(CountSec==60) CountSec=0;
  467.                                  if(CountSec>60) CountSec=59;
  468.                                  Disp[0]=5;
  469.                                  Disp[1]=DispOFF;
  470.                                  Disp[2]=CountSec/10;
  471.                                  Disp[3]=CountSec%10;
  472.                                  break;
  473.                                 }
  474.                 }
  475.    }
  476. else
  477.    {
  478.         if(key==1)                //进入闹钟显示
  479.                 {status--;
  480.                  DispTime=80;
  481.                 }
  482.         if(key==3)                //设置倒数时间
  483.                 {
  484.                  TR0=0;
  485.                   CountHr=CountMin=CountSec=0;
  486.                  adjust=1;
  487.                   }
  488.         if(key==4)                //停止倒计时
  489.                 {TR0=0;
  490. ……………………

  491. …………限于本文篇幅 余下代码请从51黑下载附件…………
复制代码

所有资料51hei提供下载:
单片机数码管时钟.rar (29.23 KB, 下载次数: 298)



评分

参与人数 1黑币 +50 收起 理由
admin + 50 共享资料的黑币奖励!

查看全部评分

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏11 分享淘帖 顶1 踩
回复

使用道具 举报

沙发
ID:441230 发表于 2018-12-6 21:36 | 只看该作者
挺好的
回复

使用道具 举报

板凳
ID:388130 发表于 2019-4-12 16:36 | 只看该作者
很好
回复

使用道具 举报

地板
ID:399949 发表于 2019-4-15 09:23 | 只看该作者
新人拿来练手,感谢楼主
回复

使用道具 举报

5#
ID:505337 发表于 2019-4-15 22:48 来自手机 | 只看该作者
怎么样
回复

使用道具 举报

6#
ID:388099 发表于 2019-4-16 13:04 | 只看该作者
正在学习单片机,感谢分享。
回复

使用道具 举报

7#
ID:300463 发表于 2019-4-16 15:43 | 只看该作者
新人拿来练手,感谢楼主
回复

使用道具 举报

8#
ID:505337 发表于 2019-4-16 21:53 来自手机 | 只看该作者
怎么样
回复

使用道具 举报

9#
ID:568565 发表于 2019-6-21 09:09 | 只看该作者
很好的资料
回复

使用道具 举报

10#
ID:568565 发表于 2019-6-22 10:46 来自手机 | 只看该作者
非常好的资料
回复

使用道具 举报

11#
ID:435101 发表于 2019-10-28 16:56 | 只看该作者
资料试过        很好!可是为何时间与分之间的点不能显示????
回复

使用道具 举报

12#
ID:435101 发表于 2019-10-28 16:56 | 只看该作者
资料试过        很好!可是为何时间与分之间的点不能显示????
回复

使用道具 举报

13#
ID:637741 发表于 2019-11-24 20:44 来自手机 | 只看该作者
请问四个按钮分别什么作用
回复

使用道具 举报

14#
ID:658691 发表于 2019-12-10 10:51 来自手机 | 只看该作者
开关按键的详细操作说明能发一份吗?
回复

使用道具 举报

15#
ID:659682 发表于 2019-12-10 12:53 来自手机 | 只看该作者
资料非常好,如果用八联管怎么设置,请求高手帮助
回复

使用道具 举报

16#
ID:659463 发表于 2019-12-10 18:47 来自手机 | 只看该作者
新人刚学,课堂实验,来参考一下,很不错,谢谢了
回复

使用道具 举报

17#
ID:659263 发表于 2019-12-14 11:06 | 只看该作者
怎么没法显示?
回复

使用道具 举报

18#
ID:659263 发表于 2019-12-14 11:40 | 只看该作者
在仿真的时候用哪个型号的单片机?
回复

使用道具 举报

19#
ID:359777 发表于 2020-6-27 20:14 | 只看该作者
很全面的资料,谢谢楼主分享
回复

使用道具 举报

20#
ID:476623 发表于 2020-8-14 15:19 | 只看该作者
下载学学看
楼主辛苦了
回复

使用道具 举报

21#
ID:245820 发表于 2020-9-9 15:37 | 只看该作者
值得学习,楼主水平很高哦
回复

使用道具 举报

22#
ID:85480 发表于 2021-10-26 13:09 | 只看该作者
楼主威武,正好在搞这个。非常感谢分享
回复

使用道具 举报

23#
ID:590050 发表于 2021-10-26 13:45 | 只看该作者
高手,动手能力强
回复

使用道具 举报

24#
ID:315554 发表于 2021-10-26 21:49 | 只看该作者
谢谢分享,看图是共阳数码管吧,
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表