找回密码
 立即注册

QQ登录

只需一步,快速开始

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

基于51单片机的多功能万年历(定时器实现)仿真程序

[复制链接]
跳转到指定楼层
楼主
要求:在LCD1602上实现年月日,时间的显示;一个闹钟蜂鸣器提醒功能;一个倒计时功能
附件:keil程序+proteus 8.13 仿真
仿真原理图如下(proteus仿真工程文件可到本帖附件中下载)

单片机源程序如下:
  1. #include <reg52.h>
  2. #include "LCD1602.h" //LCD显示文件

  3. #define uchar unsigned char
  4. #define uint  unsigned int
  5. #define ulong  unsigned long

  6. sbit BEEP=P1^0;//蜂鸣器
  7. sbit K1=P2^3;//设置时间按键
  8. sbit K2=P2^4;//+
  9. sbit K3=P2^5;//-
  10. sbit K4=P2^6;//设置闹钟按键
  11. sbit K5=P2^7;//倒计时按键

  12. int  year=2025;
  13. char month=3,day=17,h=8,min=29,s=50;//正常走时年月日时分秒
  14. char nh=23,nmin=30,ns=0;//闹钟 时分秒
  15. char dmin=1,ds=0;//倒计时 分秒

  16. uchar run;//平年闰年标志 0为平年,1为闰年
  17. uchar count,tiaoJ;//中断计数器与调节计数器
  18. uchar daymax;//每月最大天数
  19. uchar mode;//模式
  20. uchar count1;//作为倒计时进入 开始 退出标志
  21. bit stop;//倒计时停止标志位

  22. void delay(uint x)//延时函数
  23. {
  24.     uchar i,j;
  25.     for(i=0;i++;i<x)
  26.         for(j=0;j++;j<256);
  27. }


  28. void travel_time()//走时函数,包括平年闰年的计算
  29. {
  30.     if((year/4)==0 && (year)/100!=0 || (year)/400==0 )//闰年:能被4整除且不能被100整除,或能被400整除。
  31.     {
  32.         run=1;
  33.     }
  34.     else
  35.     {
  36.         run=0;
  37.     }
  38.     switch(month)
  39.     {
  40.         case 1 : daymax=31;  break;
  41.         case 2 : if(run==1) {daymax=29;}else {daymax=28;} break;
  42.         case 3 : daymax=31;  break;
  43.         case 4 : daymax=30;  break;
  44.         case 5 : daymax=31;  break;
  45.         case 6 : daymax=30;  break;
  46.         case 7 : daymax=31;  break;
  47.         case 8 : daymax=31;  break;
  48.         case 9 : daymax=30;  break;
  49.         case 10 :daymax=31;  break;
  50.         case 11 :daymax=30;  break;
  51.         case 12 :daymax=31;  break;
  52.     }
  53.     if(s==60)//走时限制
  54.     {
  55.         s=0;
  56.         min++;
  57.         if(min==60)
  58.         {
  59.             h++;
  60.             if(h==24)
  61.             {
  62.                 h=0;
  63.                 day++;
  64.                 if(day>daymax)
  65.                 {
  66.                    day=1;
  67.                    month++;
  68.                    if(month==13)
  69.                    {
  70.                        month=1;
  71.                        year++;
  72.                    }
  73.                 }
  74.             }
  75.         }
  76.     }
  77.     //规范非零值
  78.     if(s<0)
  79.     {
  80.         s=59;
  81.     }
  82.     if(min<0)
  83.     {
  84.         min=59;
  85.     }
  86.     if(h<0)
  87.     {
  88.         h=23;
  89.     }
  90.     if(day<0)
  91.     {
  92.       day=daymax;
  93.     }
  94.     if(month<0)
  95.     {
  96.         month=12;
  97.     }
  98.     if(year<0)
  99.     {
  100.         year=2025;
  101.     }
  102. }

  103. void Countdown_time()//倒计时走时
  104. {
  105.     if(ds<0)
  106.     {
  107.         if(dmin!=0 && ds<0)
  108.                 {
  109.             if(stop==0)
  110.             {
  111.                 ds=59;
  112.                 LCD_ShowChar(2,12,' ');
  113.                 dmin--;   
  114.             }
  115.                         if(dmin<0 && stop==1)
  116.                         {
  117.                 dmin=0;
  118.                         }
  119.                 }
  120.         }
  121. }


  122. void keyscanf()
  123. {
  124.     if(K1==0)
  125.     {
  126.         delay(5);//消抖
  127.         if(K1==0)
  128.         {
  129.            switch(mode)
  130.            {
  131.                case 0 :{TR0=0;count=0;tiaoJ++;}break;
  132.                default:{tiaoJ++;}break;
  133.            }
  134.         }
  135.         while(K1==0);//松手检测
  136.     }
  137.     if(K2==0)
  138.     {
  139.         delay(5);//消抖
  140.         if(K2==0)
  141.         {
  142.            if(mode==0)//正常走时模式
  143.            {
  144.                 switch(tiaoJ)
  145.                 {
  146.                     case 1 : s++;if(s>59)s=0; break;
  147.                     case 2 : min++;if(min>59)min=0;break;
  148.                     case 3 : h++; if(h>23)h=0;break;
  149.                     case 4 : day++;if(day>daymax)day=1; break;
  150.                     case 5 : month++;if(month>12)month=1;break;
  151.                     case 6 : year++; break;
  152.                 }
  153.             }
  154.            if(mode==1)//闹钟设置模式
  155.            {
  156.                switch(tiaoJ)
  157.                 {
  158.                     case 1 : ns++;if(ns>59)ns=0; break;
  159.                     case 2 : nmin++;if(nmin>59)nmin=0;break;
  160.                     case 3 : nh++; if(nh>23)nh=0;break;
  161.                 }
  162.            }
  163.            if(mode==2)//倒计时设置模式
  164.            {
  165.                switch(tiaoJ)
  166.                 {
  167.                     case 1 : ds++;if(ds>59)ds=0; break;
  168.                     case 2 : dmin++;if(dmin>59)dmin=0;break;
  169.                 }
  170.            }
  171.         }
  172.         while(K2==0);//松手检测
  173.     }
  174.     if(K3==0)
  175.     {
  176.         delay(5);//消抖
  177.         if(K3==0)
  178.         {
  179.            if(mode==0)//正常走时模式
  180.            {
  181.                switch(tiaoJ)
  182.                {
  183.                    case 1 : s--;if(s<0)s=59; break;
  184.                    case 2 : min--;if(min<0)min=59; break;
  185.                    case 3 : h--;if(h<0)h=23; break;
  186.                    case 4 : day--;if(day<0)day=daymax; break;
  187.                    case 5 : month--;if(month<0)month=12; break;
  188.                    case 6 : year--;if(year<0)year=2025; break;
  189.                }
  190.            }
  191.            if(mode==1)//闹钟设置模式
  192.            {
  193.                switch(tiaoJ)
  194.                {
  195.                    case 1 : ns--;if(ns<0)ns=59; break;
  196.                    case 2 : nmin--;if(nmin<0)nmin=59; break;
  197.                    case 3 : nh--;if(nh<0)nh=23; break;
  198.                }
  199.            }
  200.            if(mode==2)//闹钟设置模式
  201.            {
  202.                switch(tiaoJ)
  203.                {
  204.                    case 1 : ds--;if(ds<0)ds=59; break;
  205.                    case 2 : dmin--;if(dmin<0)dmin=59; break;
  206.                }
  207.            }
  208.         }
  209.         while(K3==0);//松手检测
  210.     }
  211.     if(K4==0)
  212.     {
  213.         delay(5);//消抖
  214.         if(K4==0)
  215.         {
  216.            mode=!mode;
  217.            BEEP=1;
  218.            tiaoJ=0;
  219.         }
  220.         while(K4==0);//松手检测
  221.     }
  222.     if(K5==0)
  223.     {
  224.         delay(5);//消抖
  225.         if(K5==0)
  226.         {
  227.            count1++;
  228.            tiaoJ=0;
  229.            count=0;
  230.            switch(count1)
  231.            {
  232.                case 1 : mode=2;TR0=0;dmin=1;ds=0;break;//进入
  233.                case 2 : TR0=1;break;                   //开始
  234.                case 3 : mode=0;count=0;stop=0;count1=0;break;//退出
  235.            }
  236.         }
  237.         while(K5==0);//松手检测
  238.     }
  239. }

  240. void Sans_Pd()//闪烁位置判断,与调节时间标志清除
  241. {
  242.     if(nmin==min && nh==h && mode==0)//闹钟判断
  243.     {
  244.         BEEP=0;//蜂鸣器鸣叫,不管就是一分钟后自动关闭,提前关闭按K4进入设置改时间
  245.     }
  246.     else
  247.     {
  248.         BEEP=1;
  249.     }
  250.     if(mode==0)
  251.     {
  252.         switch(tiaoJ)//闪烁位置设置
  253.         {
  254.             case 1 : LCD_ShowString(2,10,"  ");delay(2000); break;
  255.             case 2 : LCD_ShowString(2,7,"  ");delay(2000); break;
  256.             case 3 : LCD_ShowString(2,4,"  ");delay(2000); break;
  257.             case 4 : LCD_ShowString(1,11,"  ");delay(2000); break;
  258.             case 5 : LCD_ShowString(1,8,"  ");delay(2000);break;
  259.             case 6 : LCD_ShowString(1,3,"    ");delay(2000); break;
  260.         }
  261.         if(tiaoJ==7)
  262.         {
  263.             tiaoJ=0;
  264.             TR0=1;//打开定时器
  265.         }
  266.     }
  267.     if(mode==1)//闹钟设置时间时闪烁条件
  268.     {
  269.         switch(tiaoJ)//闪烁位置设置
  270.         {
  271.             case 1 : LCD_ShowString(2,10,"  ");delay(2000); break;
  272.             case 2 : LCD_ShowString(2,7,"  ");delay(2000); break;
  273.             case 3 : LCD_ShowString(2,4,"  ");delay(2000); break;
  274.         }
  275.         if(tiaoJ==4)
  276.         {
  277.             tiaoJ=1;
  278.         }
  279.     }
  280.     if(mode==2)//倒计时设置时间时闪烁条件
  281.     {
  282.         switch(tiaoJ)//闪烁位置设置
  283.         {
  284.             case 1 : LCD_ShowString(2,10,"  ");delay(2000); break;
  285.             case 2 : LCD_ShowString(2,7,"  ");delay(2000); break;
  286.         }
  287.         if(tiaoJ==3)
  288.         {
  289.             tiaoJ=1;
  290.         }  
  291.     }
  292. }

  293. void LCD_GUI1()//万年历时间显示函数
  294. {
  295.     //第一行,年月日
  296.     LCD_ShowSignedNum(1,3,year,4);
  297.     LCD_ShowChar(1,7,'/');
  298.     LCD_ShowSignedNum(1,8,month,2);
  299.     LCD_ShowChar(1,10,'/');
  300.     LCD_ShowSignedNum(1,11,day,2);
  301.     LCD_ShowString(1,13,"    ");
  302.     //第二行,时分秒
  303.     LCD_ShowSignedNum(2,4,h,2);
  304.     LCD_ShowChar(2,6,':');
  305.     LCD_ShowSignedNum(2,7,min,2);
  306.     LCD_ShowChar(2,9,':');
  307.     LCD_ShowSignedNum(2,10,s,2);
  308.    
  309. }


  310. void LCD_GUI2()//闹钟模式下的显示函数
  311. {
  312.     //第一行,年月日
  313.     LCD_ShowString(1,3,"Alarm mode:");
  314.     //第二行,时分秒 nh,nmin,ns;
  315.     LCD_ShowSignedNum(2,4,nh,2);
  316.     LCD_ShowChar(2,6,':');
  317.     LCD_ShowSignedNum(2,7,nmin,2);
  318.     LCD_ShowChar(2,9,':');
  319.     LCD_ShowSignedNum(2,10,ns,2);
  320. }

  321. void LCD_GUI3()//闹钟模式下的显示函数
  322. {
  323.     //第一行,年月日
  324.     LCD_ShowString(1,3,"Countdown mode:");
  325.     //第二行,时分秒 nh,nmin,ns;
  326.     LCD_ShowString(2,4,"   ");
  327.     LCD_ShowSignedNum(2,7,dmin,2);
  328.     LCD_ShowChar(2,9,':');
  329.     LCD_ShowSignedNum(2,10,ds,2);
  330. }
  331. void Timer0_Init()//定时器0初始化
  332. {
  333.         TMOD=0x01;
  334.         //50ms进中断
  335.         TH0=(65535-50000)/256;
  336.         TL0=(65535-50000)%256;
  337.         TR0=1;
  338.         EA=1;
  339.         ET0=1;
  340. }

  341. void main()
  342. {        
  343.     LCD_Init();//让LCD1602准备工作起来
  344.     Timer0_Init();//打开中断,使能时钟,设置隔多久进一次中断 服务函数
  345.     BEEP=1;//蜂鸣器不叫
  346.         while(1)
  347.         {         
  348.         keyscanf();//按键扫描
  349.         Sans_Pd();//闪烁判定
  350.         //万年历模式下
  351.         switch(mode)
  352.         {
  353.             case 0 : {travel_time();LCD_GUI1();delay(2000);}break;
  354.             case 1 : {LCD_GUI2();}break;
  355.             case 2 : {Countdown_time();LCD_GUI3();}break;
  356.         }
  357.     }
  358. }

  359. void Timer0_Routine() interrupt 1 //定时器0,中断服务函数
  360. {
  361.     count++;
  362.     if(count==20)//1s
  363.     {
  364.         count=0;
  365.         if(mode==0)//正常走时
  366.             s++;
  367.         if(mode==2)//倒计时
  368.             if(dmin!=0 || ds!=0)
  369.                 ds--;
  370.             else
  371.             {
  372.                 stop=1;
  373.             }
  374.     }
  375. }
复制代码

下载: C51_数字电子钟.7z (224.42 KB, 下载次数: 0)

评分

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

查看全部评分

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

使用道具 举报

沙发
ID:60656 发表于 2025-4-4 17:34 | 只看该作者
楼主,  8.13版显示汉字乱码你是怎么设置正常的
回复

使用道具 举报

板凳
ID:1147156 发表于 2025-4-5 16:39 | 只看该作者
keil怎么让中文和英文字体分别设置?
回复

使用道具 举报

地板
ID:3802 发表于 2025-4-6 07:19 | 只看该作者

keil怎么让中文和英文字体分别设置?
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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