找回密码
 立即注册

QQ登录

只需一步,快速开始

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

用普中开发板做的51单片机的智能时钟具有闹钟功能(DS1302+DS18B20+LCD1602)

  [复制链接]
跳转到指定楼层
楼主
本贴针对学完单片机并且有读懂代码的非新手同学。本人目前放寒假,这个是本人在上个学期的单片机课上要求做的综合实验,现在重新修改了下增加了菜单目前测试毫无问题可以完美使用。有志向做闹钟的同学可以参考一下,原码上由本人写的大量注释可以方便看懂。
使用了LCD1602、DS1302、DS18B20用来测试温度、内部含闹钟系统但本人没有做EEPROM有需要的同学可以自行添加。

单片机源程序如下:
  1. #include<reg52.h>
  2. #include<key.h>
  3. #include<LCD1602.h>
  4. #include<DS1302.h>
  5. #include<music.h>
  6. #include<DS18B20.H>

  7. #define normal 0//正常显示时钟界面
  8. #define settime 1//设定时钟界面
  9. #define setalarm 2//设定闹钟界面
  10. #define displayalarm 3//显示闹钟界面
  11. #define normal_12 4//显示十二小时制界面
  12. #define caidan 5

  13. unsigned char system=normal;//我一开始就把界面切换为正常显示时钟界面

  14. extern unsigned char i,k;

  15. extern unsigned int code song[3][300];

  16. unsigned char code *week[8]={"NO ","Mon ","Tue ","Wed ","Thu ","Fri ","Sat ","Sun "};

  17. unsigned char code *clockzifu[4]={"ON ","OFF ","REP ","NRE "};

  18. struct Time timeset={0x18,0x01,0x16,0x14,0x30,0x50,0x03};

  19. //第一个闹钟
  20. //第二个闹钟
  21. //第三个闹钟
  22. //第四个闹钟
  23. //第五个闹钟
  24. struct alarmtime xdata clock[5]={{1,16,14,31,0,1,0,1},{1,8,14,32,3,0,0,0},{1,7,18,49,1,1,1,0},{0,0,0,0,0,0,1,0},{1,25,0,0,0,0,1,2}};

  25. unsigned char alarmnum;//闹钟

  26. unsigned char a;

  27. unsigned char flag=0;

  28. unsigned char xinghao=0;

  29. unsigned char tentoBCD(unsigned char dat)//十进制转换为BCD码函数
  30. {
  31.         unsigned char dat1,dat2;
  32.         dat1=dat/10;
  33.         dat2=dat%10;
  34.         dat2=dat2+dat1*16;
  35.         return dat2;
  36. }

  37. unsigned char BCDtoten(unsigned char dat)//BCD码转为十进制函数
  38. {
  39.         unsigned char dat1,dat2;
  40.         dat1=dat/16;
  41.         dat2=dat%16;
  42.         dat2=dat2+dat1*10;
  43.         return dat2;
  44. }

  45. void DS18B20deal(int temp)//DS18B20数据处理函数 显示温度更新温度         
  46. {
  47.     //先判断温度值是否大于0或小于0等于0
  48.            float tp;//保存的数据可能带小数  
  49.         if(temp<0)//当温度值为负数
  50.           {
  51.                 LCD1602_writechar(9,1,0x2D);//ASCII码中的-符号
  52.                 temp=temp-1;//因为读取的温度是实际温度的补码,所以减1,再取反求出原码
  53.                 temp=~temp;//还原读取的数据
  54.                 tp=temp;//保存到变量里面
  55.                 temp=tp*0.0625*100+0.5;//强制转换成一个整形的数据.留两个小数点就*100,+0.5是四舍五入,因为C语言浮点数转换为整型的时候把小数点后面的数自动去掉,不管是否大于0.5,而+0.5之后大于0.5的就是进1了,小于0.5的就算加上0.5,还是在小数点后面。       
  56.           }
  57.         else//当温度值为正数
  58.           {                       
  59.                 LCD1602_writechar(9,1,0x20);//ASCII码中的空格
  60.                 tp=temp;//因为数据处理有小数点所以将温度赋给一个浮点型变量。如果温度是正的那么,那么正数的原码就是补码它本身
  61.                 temp=tp*0.0625*100+0.5;//留两个小数点就*100,+0.5是四舍五入,因为C语言浮点数转换为整型的时候把小数点。后面的数自动去掉,不管是否大于0.5,而+0.5之后大于0.5的就是进1了,小于0.5的就算加上0.5,还是在小数点后面。       
  62.         }
  63.         LCD1602_writechar(10,1,temp/10000+'0');//温度百位
  64.         LCD1602_writechar(11,1,temp%10000/1000+'0');//温度十位
  65.         LCD1602_writechar(12,1,temp%1000/100+'0');//温度个位
  66.     LCD1602_writechar(13,1,0x2E);//ASCII码小数点
  67.         LCD1602_writechar(14,1,temp%100/10+'0');//小数点后一位
  68.         LCD1602_writechar(15,1,temp%10+'0');//小数点后两位
  69. }

  70. void updatetime()//更新时钟上的时间
  71. {
  72.         unsigned char time[9];//存储变量
  73.         DS1302_gettime(×et);//读取时间
  74.         time[0]=BCDtoten(timeset.hour)/10+'0';//小时的十位
  75.         time[1]=BCDtoten(timeset.hour)%10+'0';//小时的个位
  76.         time[2]=':';
  77.         time[3]=BCDtoten(timeset.min)/10+'0';//分的十位
  78.         time[4]=BCDtoten(timeset.min)%10+'0';//分的个位
  79.         time[5]=':';
  80.         time[6]=BCDtoten(timeset.sec)/10+'0';//秒的十位
  81.         time[7]=BCDtoten(timeset.sec)%10+'0';//秒的个位
  82.         time[8]='\0';//字符串结束标志

  83.         LCD1602_writestr(0,1,time);//在LCD上面打印时间
  84. }

  85. void updatetime_12()//更新十二小时制界面的时间
  86. {
  87.         unsigned char time[9];
  88.         DS1302_gettime(×et);//读取时间
  89.         time[0]= BCDtoten(timeset.hour)%12/10+'0';//小时的十位
  90.         time[1]= BCDtoten(timeset.hour)%12%10+'0';//小时的个位
  91.         time[2]=':';
  92.         time[3]= BCDtoten(timeset.min)/10+'0';//分的十位
  93.         time[4]= BCDtoten(timeset.min)%10+'0';//分的个位
  94.         time[5]=':';
  95.         time[6]= BCDtoten(timeset.sec)/10+'0';//秒的十位
  96.         time[7]= BCDtoten(timeset.sec)%10+'0';//秒的个位
  97.         time[8]='\0';//字符串结束标志                                                                                                                                                                                                               
  98.         LCD1602_writestr(3,1,"TIME:");//打印出TIME的字符串
  99.         LCD1602_writestr(8,1,time);//在第二行第四列显示时间
  100.         if(BCDtoten(timeset.hour)>12)//要是小时大于12时
  101.         {
  102.           LCD1602_writestr(0,1,"PM");//则显示PM
  103.         }
  104.         else//小时不大于12
  105.         {
  106.           LCD1602_writestr(0,1,"AM");//则显示AM
  107.         }  
  108. }

  109. void updatedate()//更新日历
  110. {
  111.         unsigned char date[12];
  112.         date[0]= '2';
  113.         date[1]= '0';
  114.         date[2]= BCDtoten(timeset.year)/10%10+'0';//年的十位
  115.         date[3]= BCDtoten(timeset.year)%10+'0';//年的个位
  116.         date[4]='.';
  117.         date[5]= BCDtoten(timeset.mon)/10+'0';//月的十位
  118.         date[6]= BCDtoten(timeset.mon)%10+'0';//月的个位
  119.         date[7]='.';
  120.         date[8]= BCDtoten(timeset.day)/10+'0';//日的十位
  121.         date[9]= BCDtoten(timeset.day)%10+'0';//日的个位
  122.         date[10]='\0';
  123.         LCD1602_writestr(0,0,date);//显示年月日
  124.         LCD1602_writestr(11,0,week[timeset.week]);//显示星期
  125. }

  126. void updatealarm()//更新闹钟设定值
  127. {
  128.         unsigned char str0[14];
  129.         unsigned char str1[2];

  130.         str0[0]=alarmnum+'0';
  131.         str0[1]=' ';
  132.         str0[2]=clock[alarmnum].mon/10+'0';//月份十位
  133.         str0[3]=clock[alarmnum].mon%10+'0';//月份个位
  134.         str0[4]='-';
  135.         str0[5]=clock[alarmnum].day/10+'0';//日期十位
  136.         str0[6]=clock[alarmnum].day%10+'0';//日期个位
  137.         str0[7]=' ';
  138.         str0[8]=clock[alarmnum].hour/10+'0';//小时十位
  139.         str0[9]=clock[alarmnum].hour%10+'0';//小时个位
  140.         str0[10]=':';
  141.         str0[11]=clock[alarmnum].min/10+'0';//分钟十位
  142.         str0[12]=clock[alarmnum].min%10+'0';//分钟个位
  143.         str0[13]='\0';

  144.         LCD1602_writestr(0,1,str0);

  145.         str1[0]=clock[alarmnum].music+'0';//铃声
  146.         str1[1]='\0';

  147.         LCD1602_writestr(0,0,"U");
  148.         LCD1602_writestr(1,0,str1);//显示铃声
  149.         LCD1602_writestr(3,0,clockzifu[clock[alarmnum].alarmre+2]);//显示重不重复
  150.         LCD1602_writestr(7,0,week[clock[alarmnum].week]);//显示星期
  151.         LCD1602_writestr(11,0,clockzifu[clock[alarmnum].alarmon]);//显示开关       
  152. }

  153. void anjian4();

  154. void anjian1()
  155. {
  156.   if(system==normal)
  157.   {
  158.     system=caidan;
  159.         xinghao=0;
  160.         LCD1602_clear();
  161.         LCD1602_writechar(0,0,'*');
  162.         LCD1602_writestr(1,0,"12");
  163.         LCD1602_writestr(1,1,"alarm");
  164.         LCD1602_writestr(8,0,"setclock");
  165.         LCD1602_writestr(8,1,"setalarm");
  166.   }
  167.   else if(system==caidan&&xinghao==0)
  168.   {
  169.     system=normal_12;//切换到12小时制
  170.         LCD1602_clear();//清屏
  171.         updatetime_12();//显示12小时制的时间
  172.         updatedate();//显示日期
  173.   }
  174.   else if(system==caidan&&xinghao==1)
  175.   {
  176.     system=displayalarm;//切换到闹钟显示
  177.     LCD1602_clear();//清屏
  178.         updatealarm();//显示闹钟界面
  179.   }
  180.   else if(system==caidan&&xinghao==2)
  181.   {
  182.     system=settime;//进入设置时间界面
  183.         LCD1602_clear();
  184.         updatetime();//刷新时间
  185.     updatedate();//刷新日期
  186.     DS18B20deal(DS18B20readtemp());//DS18B20数据处理函数 同时输出温度
  187.     flag=0;//光标索引设置到秒钟上
  188.     anjian4();//显示光标位置
  189.     LCD1602_openguangbiao();//LCD1602打开光标显示
  190.   }
  191.   else if(system==caidan&&xinghao==3)
  192.   {
  193.     system=setalarm;//进入设置闹钟
  194.         LCD1602_clear();//清屏
  195.         updatealarm();//显示闹钟界面
  196.     flag=0;//光标索引设置到多闹钟选择处上
  197.     anjian4();//显示光标位置
  198.     LCD1602_openguangbiao();//LCD1602打开光标显示
  199.   }
  200.   else if(system==settime)
  201.   {
  202.     system=normal;//切换回正常显示时钟的界面,显示日历时钟、温度。
  203.         DS1302_settime(×et);//把设定时间写入实时时钟
  204.         LCD1602_closeguangbiao();//LCD1602关闭光标显示
  205.     LCD1602_clear();//LCD1602清屏
  206.     updatetime();//刷新时间
  207.         updatedate();//立即刷新日期
  208.         DS18B20deal(DS18B20readtemp());//DS18B20数据处理函数 显示温度
  209.   }
  210.   else if(system==setalarm)
  211.   {
  212.      system=displayalarm;//返回到闹钟显示
  213.          LCD1602_closeguangbiao();//LCD1602关闭光标显示
  214.          LCD1602_clear();//清屏
  215.          updatealarm();//刷新闹钟界面
  216.   }
  217. }

  218. void anjian4()
  219. {
  220.   if(system==caidan)
  221.   {
  222.     system=normal;
  223.         LCD1602_clear();//清屏
  224.         updatetime();//显示时钟时间
  225.         updatedate();//显示日期
  226.         DS18B20deal(DS18B20readtemp());//DS18B20数据处理函数
  227.   }
  228.   else if(system==normal_12)
  229.   {
  230.     system=normal;//返回时钟显示界面
  231.         LCD1602_clear();//清屏
  232.         updatetime();//显示时钟时间
  233.         updatedate();//显示日期
  234.         DS18B20deal(DS18B20readtemp());//DS18B20数据处理函数
  235.   }
  236.   else if(system==displayalarm)
  237.   {
  238.     system=caidan;
  239.         xinghao=1;
  240.         LCD1602_clear();
  241.         LCD1602_writechar(0,1,'*');
  242.         LCD1602_writestr(1,0,"12");
  243.         LCD1602_writestr(1,1,"alarm");
  244.         LCD1602_writestr(8,0,"setclock");
  245.         LCD1602_writestr(8,1,"setalarm");
  246.   }
  247.   else if(system==settime)//当前系统状态位于设置时间时 定义光标的位置
  248.   {
  249.         switch(flag)//保存的设置位
  250.      {
  251.        case 0:LCD1602_setcur(7,1);flag=1;break;//定位于秒钟个位处
  252.        case 1:LCD1602_setcur(4,1);flag=2;break;//定位于分钟处
  253.        case 2:LCD1602_setcur(1,1);flag=3;break;//定位于小时处
  254.        case 3:LCD1602_setcur(11,0);flag=4;break;//定位于星期处
  255.        case 4:LCD1602_setcur(9,0);flag=5;break;//定位于日处
  256.        case 5:LCD1602_setcur(6,0);flag=6;break;//定位于月处
  257.        default:LCD1602_setcur(3,0);flag=0;break;//定位于年处
  258.      }
  259.   }
  260.   else if(system==setalarm)//当前系统状态位于设置闹钟时 定义光标的位置
  261.      {
  262.         switch(flag)//保存的设置位
  263.         {
  264.             case 0:LCD1602_setcur(0,1);flag=1;break;//定位于多闹钟选择处
  265.                         case 1:LCD1602_setcur(3,1);flag=2;break;//定位于闹钟月份处
  266.                         case 2:LCD1602_setcur(6,1);flag=3;break;//定位于闹钟日处
  267.                         case 3:LCD1602_setcur(9,1);flag=4;break;//定位于闹钟分钟处
  268.                         case 4:LCD1602_setcur(12,1);flag=5;break;//定位于闹钟小时处
  269.                         case 5:LCD1602_setcur(1,0);flag=6;break;//定位于闹钟铃声选择处
  270.                         case 6:LCD1602_setcur(3,0);flag=7;break;//定位于闹钟重复与不重复选择处
  271.                         case 7:LCD1602_setcur(7,0);flag=8;break;//定位于闹钟星期选择处
  272.             default:LCD1602_setcur(11,0);flag=0;break;//定位于闹钟开关处
  273.         }
  274.      }
  275. }

  276. void zengjia()//增加
  277. {
  278.     if(system==caidan)
  279.         {
  280.           if(xinghao==0)
  281.           {
  282.             LCD1602_clear();
  283.             LCD1602_writechar(0,1,'*');
  284.             LCD1602_writestr(1,0,"12");
  285.             LCD1602_writestr(1,1,"alarm");
  286.             LCD1602_writestr(8,0,"setclock");
  287.             LCD1602_writestr(8,1,"setalarm");
  288.                 xinghao=1;
  289.           }
  290.           else if(xinghao==1)
  291.           {
  292.                   LCD1602_clear();
  293.             LCD1602_writechar(7,0,'*');
  294.             LCD1602_writestr(1,0,"12");
  295.             LCD1602_writestr(1,1,"alarm");
  296.             LCD1602_writestr(8,0,"setclock");
  297.             LCD1602_writestr(8,1,"setalarm");
  298.                 xinghao=2;
  299.           }
  300.           else if(xinghao==2)
  301.           {
  302.             LCD1602_clear();
  303.             LCD1602_writechar(7,1,'*');
  304.             LCD1602_writestr(1,0,"12");
  305.             LCD1602_writestr(1,1,"alarm");
  306.             LCD1602_writestr(8,0,"setclock");
  307.             LCD1602_writestr(8,1,"setalarm");
  308.                 xinghao=3;
  309.           }
  310.           else if(xinghao==3)
  311.           {
  312.             LCD1602_clear();
  313.             LCD1602_writechar(0,0,'*');
  314.             LCD1602_writestr(1,0,"12");
  315.             LCD1602_writestr(1,1,"alarm");
  316.             LCD1602_writestr(8,0,"setclock");
  317.             LCD1602_writestr(8,1,"setalarm");
  318.                 xinghao=0;
  319.           }
  320.         }
  321.         else if(system==settime)//当设置日历时间的界面时
  322.     {
  323.                 switch(flag)//检查光标位置
  324.         {                               
  325.                         case 1: a=BCDtoten(timeset.sec);//把BCD码转为十进制 因为DS1302里时钟程序读写时都是BCD码 转为10进制更好处理
  326.                                         if(a<59)
  327.                                         {
  328.                                           a++;
  329.                                         }  
  330.                                         else
  331.                                         {
  332.                                           a=0;//限制设置秒钟不超过59秒,超过则回到0
  333.                                         }
  334.                                         timeset.sec=tentoBCD(a);//把十进制转为BCD码 因为DS1302时钟程序读写时都是BCD码 将加完的东西重新赋值给sec
  335.                                         LCD1602_writechar(6,1,(timeset.sec>>4)+'0');//秒的十位
  336.                                         LCD1602_writechar(7,1,(timeset.sec&0x0f)+'0');//秒的个位
  337.                                         LCD1602_setcur(7,1);//光标保持原位
  338.                                         break;

  339.                         case 2:        a=BCDtoten(timeset.min);//把BCD码转为十进制
  340.                                         if(a<59)
  341.                                         {
  342.                                           a++;
  343.                                         }  
  344.                                         else
  345.                                         {
  346.                                           a=0;//限制设置分钟不超过59分,超过则回到0
  347.                                         }
  348.                                         timeset.min=tentoBCD(a);//把十进制转为BCD码
  349.                                         LCD1602_writechar(3,1,(timeset.min>>4)+'0');//分的十位
  350.                                         LCD1602_writechar(4,1,(timeset.min&0x0f)+'0');//分的个位
  351.                                         LCD1602_setcur(4,1);//光标保持原位
  352.                                         break;

  353.                         case 3:        a=BCDtoten(timeset.hour);//把BCD码转为十进制
  354.                                         if(a<23)
  355.                                         {
  356.                                           a++;
  357.                                         }  
  358.                                         else
  359.                                         {
  360.                                           a=0;//限制设置小时不超过23时,超过则回到0
  361.                                         }
  362.                                         timeset.hour=tentoBCD(a);//把十进制转为BCD码
  363.                                         LCD1602_writechar(0,1,(timeset.hour>>4)+'0');//小时的十位
  364.                                         LCD1602_writechar(1,1,(timeset.hour&0x0f)+'0');//小时的个位
  365.                                         LCD1602_setcur(1,1);//光标保持原位
  366.                                         break;

  367.                         case 4: if(timeset.week<7)//限制不超过星期日,如果超过则回到周一
  368.                                         {
  369.                                           timeset.week++;
  370.                                         }  
  371.                                         else
  372.                                         {
  373.                                           timeset.week=1;//回到星期一
  374.                                         }
  375.                                         LCD1602_writestr(11,0,week[timeset.week]);//
  376.                                         LCD1602_setcur(11,0);//光标保持原位
  377.                                         break;

  378.                         case 5:        a=BCDtoten(timeset.day);//把BCD码转为十进制
  379.                                         if(a<31)
  380.                                         {
  381.                                           a++;
  382.                                         }  
  383.                                         else
  384.                                         {
  385.                                           a=1;//限制设置日期不超过31日,超过则回到1
  386.                                         }
  387.                                         timeset.day=tentoBCD(a);//把十进制转为BCD码
  388.                                         LCD1602_writechar(8,0,(timeset.day>>4)+'0');//日的十位
  389.                                         LCD1602_writechar(9,0,(timeset.day&0x0f)+'0');//日的个位
  390.                                         LCD1602_setcur(9,0);//光标保持原位
  391.                                         break;

  392.                         case 6:        a=BCDtoten(timeset.mon);//把BCD码转为十进制
  393.                                         if(a<12)
  394.                                         {
  395.                                           a++;
  396.                                         }  
  397.                                         else
  398.                                         {
  399.                                           a=1;//限制设置月份不超过12月,超过则回到1
  400.                                         }
  401.                                         timeset.mon=tentoBCD(a);//把十进制转为BCD码
  402.                                         LCD1602_writechar(5,0,(timeset.mon>>4)+'0');//月的十位
  403.                                         LCD1602_writechar(6,0,(timeset.mon&0x0f)+'0');//月的个位
  404.                                         LCD1602_setcur(6,0);//光标保持原位
  405.                                         break;

  406.                         case 0:        a=BCDtoten(timeset.year);//把BCD码转为十进制
  407.                                         if(a<99)
  408.                                         {
  409.                                           a++;                                          
  410.                                         }  
  411.                                         else
  412.                                         {
  413.                                           a=0;//限制设置年不超过99年,超过则回到0
  414.                                         }
  415.                                         timeset.year=tentoBCD(a);//把十进制转为BCD码
  416.                                         LCD1602_writechar(2,0,(timeset.year>>4)+'0');//年的十位
  417.                                         LCD1602_writechar(3,0,(timeset.year&0x0f)+'0');//年的个位
  418.                                         LCD1602_setcur(3,0);//光标保持原位
  419.                                         break;
  420.                 }       
  421.         }
  422.         else if(system==setalarm)//当设置闹钟的时候
  423.         {
  424.                 switch(flag)//检查光标位置
  425.         {
  426.                         case 1: if(alarmnum<4)//换闹钟
  427.                                 {
  428.                                           alarmnum++;
  429.                                 }  
  430.                                         else
  431.                                         {
  432.                                           alarmnum=0;
  433.                                         }
  434.                                         updatealarm();//更新闹钟设定值
  435.                                         LCD1602_setcur(0,1);//光标保持原位
  436.                                         break;
  437.                         case 2:        if(clock[alarmnum].mon<12)
  438.                                 {
  439.                                           clock[alarmnum].mon++;
  440.                                 }  
  441.                                         else
  442.                                         {
  443.                                           clock[alarmnum].mon=1;//限制设置月份不超过12月,超过则回到1
  444.                                         }
  445.                                         LCD1602_writechar(2,1,(clock[alarmnum].mon/10)+'0');//月的十位
  446.                                         LCD1602_writechar(3,1,(clock[alarmnum].mon%10)+'0');//月的个位
  447.                                         LCD1602_setcur(3,1);//光标保持原位
  448.                                         break;
  449.                         case 3:        if(clock[alarmnum].day<31)
  450.                                 {
  451.                                           clock[alarmnum].day++;
  452.                                         }  
  453.                                         else
  454.                                         {
  455.                                           clock[alarmnum].day=1;//限制设置日期不超过31日,超过则回到1
  456.                                         }
  457.                                         LCD1602_writechar(5,1,(clock[alarmnum].day/10)+'0');//日的十位
  458.                                         LCD1602_writechar(6,1,(clock[alarmnum].day%10)+'0');//日的个位
  459.                                         LCD1602_setcur(6,1);//光标保持原位
  460.                                         break;
  461.                         case 4:        if(clock[alarmnum].hour<23)
  462.                                 {
  463.                                           clock[alarmnum].hour++;
  464.                                         }
  465.                                         else
  466.                                         {
  467.                                           clock[alarmnum].hour=0;//限制设置小时不超过23时,超过则回到0
  468.                                         }                                                                                                                                                                                                                                                                                                                                                                                           
  469.                                         LCD1602_writechar(8,1,(clock[alarmnum].hour/10)+'0');//小时的十位
  470.                                         LCD1602_writechar(9,1,(clock[alarmnum].hour%10)+'0');//小时的个位
  471.                                         LCD1602_setcur(9,1);//光标保持原位
  472.                                         break;
  473.                         case 5: if(clock[alarmnum].min<59)
  474.                                 {
  475.                                           clock[alarmnum].min++;
  476.                                         }  
  477.                                         else
  478.                                         {
  479.                                           clock[alarmnum].min=0;//限制设置分钟不超过59分,超过则回到0
  480.                                         }
  481.                                         LCD1602_writechar(11,1,(clock[alarmnum].min/10)+'0');//分钟的十位
  482.                                         LCD1602_writechar(12,1,(clock[alarmnum].min%10)+'0');//分钟的个位
  483.                                         LCD1602_setcur(12,1);//光标保持原位
  484.                                         break;
  485.                                        
  486.                         case 6:        if(clock[alarmnum].music<2)
  487.                                 {
  488.                                           clock[alarmnum].music++;
  489.                                         }  
  490.                                         else
  491.                                         {
  492.                                           clock[alarmnum].music=0;
  493.                                         }
  494.                                         LCD1602_writechar(1,0,clock[alarmnum].music+'0');//音乐曲目
  495.                                         LCD1602_setcur(1,0);//光标保持原位
  496.                                         break;
  497.                                                                
  498.                         case 7:        clock[alarmnum].alarmre=~clock[alarmnum].alarmre;//取反
  499.                                         LCD1602_writestr(3,0,clockzifu[clock[alarmnum].alarmre+2]);//显示闹钟状态
  500.                                         LCD1602_setcur(3,0);//光标保持原位
  501.                                         break;
  502.                         case 8:        if(clock[alarmnum].week<7)
  503.                                         {
  504.                                           clock[alarmnum].week++;
  505.                                         }  
  506.                                         else
  507.                                         {
  508.                                           clock[alarmnum].week=0;//限制不超过星期日,如果超过则回到不设星期
  509.                                         }
  510.                                         LCD1602_writestr(7,0,week[clock[alarmnum].week]);//显示到液晶上;
  511.                                         LCD1602_setcur(7,0);//光标保持原位
  512.                                         break;

  513.                         case 0: clock[alarmnum].alarmon=~clock[alarmnum].alarmon;//取反
  514.                                         LCD1602_writestr(11,0,clockzifu[clock[alarmnum].alarmon]);//显示闹钟状态
  515.                                         LCD1602_setcur(11,0);//光标保持原位
  516.                                         break;               
  517.                 }               
  518.         }
  519. }

  520. void jianxiao()//S4按键功能函数,数据减
  521. {
  522.         if(system==caidan)
  523.         {
  524.           if(xinghao==0)
  525.           {
  526.             LCD1602_clear();
  527.             LCD1602_writechar(7,1,'*');
  528.             LCD1602_writestr(1,0,"12");
  529.             LCD1602_writestr(1,1,"alarm");
  530.             LCD1602_writestr(8,0,"setclock");
  531.             LCD1602_writestr(8,1,"setalarm");
  532.                 xinghao=3;
  533.           }
  534.           else if(xinghao==3)
  535.           {
  536.                   LCD1602_clear();
  537.             LCD1602_writechar(7,0,'*');
  538.             LCD1602_writestr(1,0,"12");
  539.             LCD1602_writestr(1,1,"alarm");
  540.             LCD1602_writestr(8,0,"setclock");
  541.             LCD1602_writestr(8,1,"setalarm");
  542.                 xinghao=2;
  543.           }
  544.           else if(xinghao==2)
  545.           {
  546.             LCD1602_clear();
  547.             LCD1602_writechar(0,1,'*');
  548.             LCD1602_writestr(1,0,"12");
  549.             LCD1602_writestr(1,1,"alarm");
  550.             LCD1602_writestr(8,0,"setclock");
  551.             LCD1602_writestr(8,1,"setalarm");
  552.                 xinghao=1;
  553.           }
  554.           else if(xinghao==1)
  555.           {
  556.             LCD1602_clear();
  557.             LCD1602_writechar(0,0,'*');
  558.             LCD1602_writestr(1,0,"12");
  559.             LCD1602_writestr(1,1,"alarm");
  560.             LCD1602_writestr(8,0,"setclock");
  561.             LCD1602_writestr(8,1,"setalarm");
  562.                 xinghao=0;
  563.           }
  564.         }
  565.         else if(system==settime)//设置日期/时间
  566.     {
  567.                 switch(flag)//检查光标位置
  568.         {                               
  569.                         case 1:        a=BCDtoten(timeset.sec);//把BCD码转为十进制
  570.                                         if(a!=0)
  571.                                         {
  572.                                           a--;
  573.                                         }  
  574.                                         else
  575.                                         {
  576.                                           a=59;//限制设置秒钟不为0时减1,为0时回到59
  577.                                         }
  578.                                         timeset.sec=tentoBCD(a);//把十进制转为BCD码
  579.                                         LCD1602_writechar(6,1,(timeset.sec>>4)+'0');//秒的十位
  580.                                         LCD1602_writechar(7,1,(timeset.sec&0x0f)+'0');//秒的个位
  581.                                         LCD1602_setcur(7,1);//光标保持原位
  582.                                         break;

  583.                         case 2:        a=BCDtoten(timeset.min);//把BCD码转为十进制
  584.                                         if(a!=0)
  585.                                         {
  586.                                           a--;
  587.                                         }  
  588.                                         else
  589.                                         {
  590.                                           a=59;//限制设置分钟不为0时减1,为0时回到59
  591.                                         }
  592.                                         timeset.min=tentoBCD(a);//把十进制转为BCD码
  593.                                         LCD1602_writechar(3,1,(timeset.min>>4)+'0');//分的十位
  594.                                         LCD1602_writechar(4,1,(timeset.min&0x0f)+'0');//分的个位
  595.                                         LCD1602_setcur(4,1);//光标保持原位
  596.                                         break;

  597.                         case 3:        a=BCDtoten(timeset.hour);//把BCD码转为十进制
  598.                                         if(a!=0)
  599.                                         {
  600.                                           a--;
  601.                                         }  
  602.                                         else
  603.                                         {
  604.                                           a=23;//限制设置小时不为0时减1,为0时回到23
  605.                                         }
  606.                                         timeset.hour=tentoBCD(a);//把十进制转为BCD码
  607.                                         LCD1602_writechar(0,1,(timeset.hour>>4)+'0');//小时的十位
  608.                                         LCD1602_writechar(1,1,(timeset.hour&0x0f)+'0');//小时的个位
  609.                                         LCD1602_setcur(1,1);//光标保持原位
  610.                                         break;

  611.                         case 4: //如果为当前为星期一时,回到星期天
  612.                                         if(timeset.week!=1)
  613.                                         {
  614.                                           timeset.week--;
  615.                                         }  
  616.                                         else
  617.                                         {
  618.                                           timeset.week=7;
  619.                                         }
  620.                                         LCD1602_writestr(11,0,week[timeset.week]);//显示到液晶上;
  621.                                         LCD1602_setcur(11,0);//光标保持原位
  622.                                         break;

  623.                         case 5:        a=BCDtoten(timeset.day);//把BCD码转为十进制
  624.                                         if(a!=1)
  625.                                         {
  626.                                           a--;
  627.                                         }  
  628.                                         else
  629.                                         {
  630.                                           a=31;
  631.                                         }//限制设置日期不为1时减1,为0时回到31
  632.                                         timeset.day=tentoBCD(a);//把十进制转为BCD码
  633.                                         LCD1602_writechar(8,0,(timeset.day>>4)+'0');//日期的十位
  634.                                         LCD1602_writechar(9,0,(timeset.day&0x0f)+'0');//日期的个位
  635.                                         LCD1602_setcur(9,0);//光标保持原位
  636.                                         break;

  637.                         case 6:        a=BCDtoten(timeset.mon);//把BCD码转为十进制
  638.                                         if(a!=1)
  639.                                         {
  640.                                           a--;
  641.                                         }  
  642.                                         else
  643.                                         {
  644.                                           a=12;//限制设置月份不为1时减1,为0时回到12
  645.                                         }
  646.                                         timeset.mon=tentoBCD(a);//把十进制转为BCD码
  647.                                         LCD1602_writechar(5,0,(timeset.mon>>4)+'0');//月份的十位
  648.                                         LCD1602_writechar(6,0,(timeset.mon&0x0f)+'0');//月份的个位
  649.                                         LCD1602_setcur(6,0);//光标保持原位
  650.                                         break;

  651.                         case 0:        a=BCDtoten(timeset.year);//把BCD码转为十进制
  652.                                         if(a!=0)
  653.                                         {
  654.                                           a--;
  655.                                         }  
  656.                                         else
  657.                                         {
  658.                                           a=99;//限制设置年不为0时减1,为0时回到99
  659.                                         }
  660.                                         timeset.year=tentoBCD(a);//把十进制转为BCD码
  661.                                         LCD1602_writechar(2,0,(timeset.year>>4)+'0');//年的十位
  662.                                         LCD1602_writechar(3,0,(timeset.year&0x0f)+'0');//年的个位
  663.                                         LCD1602_setcur(3,0);//光标保持原位
  664.                                         break;
  665.                 }               
  666.         }
  667.         else if(system==setalarm)//设置闹钟
  668.         {
  669.                 switch(flag)//检查光标位置
  670.         {
  671.                         case 1: if(alarmnum!=0)//换闹钟
  672.                                 {
  673.                                           alarmnum--;
  674.                                         }
  675.                                         else
  676.                                         {
  677.                                           alarmnum=4;
  678.                                         }
  679.                                         updatealarm();//刷新闹钟界面
  680.                                         LCD1602_setcur(0,1);//光标保持原位
  681.                                         break;
  682.                         case 2:        if(clock[alarmnum].mon!=1)
  683.                                 {
  684.                                           clock[alarmnum].mon--;
  685.                                         }  
  686.                                         else
  687.                                         {
  688.                                           clock[alarmnum].mon=12;//限制设置月份不超过12月,超过则回到1
  689.                                         }
  690.                                         LCD1602_writechar(2,1,(clock[alarmnum].mon/10)+'0');//月份十位
  691.                                         LCD1602_writechar(3,1,(clock[alarmnum].mon%10)+'0');//月份个位
  692.                                         LCD1602_setcur(3,1);//光标保持原位
  693.                                         break;
  694.                         case 3:        if(clock[alarmnum].day!=1)
  695.                                 {
  696.                                           clock[alarmnum].day--;
  697.                                         }  
  698.                                         else
  699.                                         {
  700.                                           clock[alarmnum].day=31;//限制设置日期不超过31日,超过则回到1
  701.                                         }
  702.                                         LCD1602_writechar(5,1,(clock[alarmnum].day/10)+'0');//日期十位
  703.                                         LCD1602_writechar(6,1,(clock[alarmnum].day%10)+'0');//日期个位
  704.                                         LCD1602_setcur(6,1);//光标保持原位
  705.                                         break;
  706.                         case 4:        if(clock[alarmnum].hour!=0)
  707.                                 {
  708.                                           clock[alarmnum].hour--;
  709.                                         }  
  710.                                         else
  711.                                         {
  712.                                           clock[alarmnum].hour=23;//限制设置小时不超过23时,超过则回到0
  713.                                         }                                                                                                                                                                                                                                                                                                                                                                                           
  714.                                         LCD1602_writechar(8,1,(clock[alarmnum].hour/10)+'0');//小时十位
  715.                                         LCD1602_writechar(9,1,(clock[alarmnum].hour%10)+'0');//小时个位
  716.                                         LCD1602_setcur(9,1);//光标保持原位
  717.                                         break;
  718.                         case 5: if(clock[alarmnum].min!=0)
  719.                                 {
  720.                                           clock[alarmnum].min--;
  721.                                         }  
  722.                                         else
  723.                                         {
  724.                                           clock[alarmnum].min=59;//限制设置分钟不超过59分,超过则回到0
  725.                                         }
  726.                                         LCD1602_writechar(11,1,(clock[alarmnum].min/10)+'0');//分钟十位
  727.                                         LCD1602_writechar(12,1,(clock[alarmnum].min%10)+'0');//分钟个位
  728.                                         LCD1602_setcur(12,1);//光标保持原位
  729.                                         break;
  730.                                        
  731.                         case 6:        if(clock[alarmnum].music!=0)
  732.                                 {
  733.                                           clock[alarmnum].music--;
  734.                                         }  
  735.                                         else
  736.                                         {
  737.                                           clock[alarmnum].music=2;
  738.                                         }
  739.                                         LCD1602_writechar(1,0,clock[alarmnum].music+'0');
  740.                                         LCD1602_setcur(1,0);//光标保持原位
  741.                                         break;
  742.                                                                
  743.                         case 7:        clock[alarmnum].alarmre=~clock[alarmnum].alarmre;
  744.                                         LCD1602_writestr(3,0,clockzifu[clock[alarmnum].alarmre+2]);//显示闹钟状态
  745.                                         LCD1602_setcur(3,0);//光标保持原位
  746.                                         break;
  747.                         case 8:        if (clock[alarmnum].week!=0)
  748.                                         {
  749.                                           clock[alarmnum].week--;
  750.                                         }  
  751.                                         else
  752.                                         {
  753.                                           clock[alarmnum].week=7;
  754.                                         }
  755.                                         LCD1602_writestr(7,0,week[clock[alarmnum].week]);//显示到液晶上;
  756.                                         LCD1602_setcur(7,0);//光标保持原位
  757.                                         break;

  758.                         case 0: clock[alarmnum].alarmon=~clock[alarmnum].alarmon;
  759.                                         LCD1602_writestr(11,0,clockzifu[clock[alarmnum].alarmon]);//显示闹钟状态
  760.                                         LCD1602_setcur(11,0);//光标保持原位
  761.                                         break;
  762.                 }               
  763.         }
  764. }

  765. void alarmset()//闹钟函数
  766. {
  767.         unsigned char i;
  768.         for(i=0;i<5;i++)//扫描闹钟
  769.         {
  770.             //0就是重复 1不重复
  771.                 if(clock[i].alarmre)//不重复时
  772.                 {
  773.                           if((BCDtoten(timeset.hour)==clock[i].hour)&&(BCDtoten(timeset.min)==clock[i].min)&&(BCDtoten(timeset.mon)==clock[i].mon)&&(BCDtoten(timeset.day)==clock[i].day)&&(BCDtoten(timeset.sec))==0)//检查闹钟的时间和日期是否跟目前的时钟时间日期匹配
  774.                     {
  775.                               //0为打开 1为关闭
  776.                           if(!clock[i].alarmon)//检查闹钟是否打开
  777.                                                 {
  778.                                                   LCD1602_clear();//清屏
  779.                                                   LCD1602_writestr(0,0,"Alarm");
  780.                                                   LCD1602_writechar(6,0,i+'0');
  781.                                                   LCD1602_writestr(8,0,"ring!");
  782.                                                   LCD1602_writestr(0,1,"Please press!");
  783.                                                   playmusic(clock[i].music);//播放铃声
  784.                                                   LCD1602_clear();//清屏
  785.                                                 }
  786.                     }
  787.                 }
  788.                 else//如果重复
  789.                 {
  790.                         if(clock[i].week)//有设置星期 则是每一个特定星期重复
  791.                         {
  792.                                 if(clock[i].week==timeset.week)//看闹钟设置的星期是否为现在的星期
  793.                                 {
  794.                                         if((BCDtoten(timeset.hour)==clock[i].hour)&&(BCDtoten(timeset.min)==clock[i].min)&&(BCDtoten(timeset.sec))==0)//检查闹钟的时间是否跟目前的时钟时间匹配
  795.                                     {
  796.                                           if(!clock[i].alarmon)//检查闹钟是否打开
  797.                                                 {
  798.                                                   LCD1602_clear();//清屏
  799.                                                   LCD1602_writestr(0,0,"Alarm");
  800.                                                   LCD1602_writechar(6,0,i+'0');
  801.                                                   LCD1602_writestr(8,0,"ring!");
  802.                                                    LCD1602_writestr(0,1,"Please press!");
  803.                                                   playmusic(clock[i].music);//播放音乐
  804.                                                   LCD1602_clear();//清屏
  805.                                                 }
  806.                                     }
  807.                                        
  808.                                 }       
  809.                        
  810.                         }
  811.                         else//没有设置星期且在重复的情况下 则为每天都响
  812.                         {
  813.                                         if((BCDtoten(timeset.hour)==clock[i].hour)&&(BCDtoten(timeset.min)==clock[i].min)&&(BCDtoten(timeset.sec))==0)//检查闹钟的时间是否跟目前的时钟时间匹配
  814.                                     {
  815.                                         if (!clock[i].alarmon)//检查闹钟是否打开
  816.                                                 {
  817.                                                   LCD1602_clear();//清屏
  818.                                                   LCD1602_writestr(0,0,"Alarm");
  819.                                                   LCD1602_writechar(6,0,i+'0');
  820.                                                   LCD1602_writestr(8,0,"ring!");
  821.                                                   LCD1602_writestr(0,1,"Please press!");
  822.                                                   playmusic(clock[i].music);//播放音乐
  823.                                                   LCD1602_clear();//清屏
  824.                                                 }
  825.                                     }                               
  826.                         }       
  827.                 }
  828.         }          
  829. }


  830. void dingshiqi0()
  831. {
  832.         TMOD|=0x01;
  833.         TH0=0;
  834.         TL0=0;
  835.         TR0=0;
  836.         ET0=1;
  837.         PT0=1;
  838.         EA=1;
  839. }

  840. void dingshiqi1()
  841. {
  842.         TMOD|=0x10;
  843.         EA=1;
  844.         ET1=1;
  845.         TR1=1;
  846.         TH1=0xED;
  847.         TL1=0xFE;
  848. }

  849. void timer0() interrupt 1
  850. {       
  851.     TH0=song[k][i]/256;
  852.         TL0=song[k][i]%256;
  853.         beep=~beep;

  854. }

  855. void timer1() interrupt 3
  856. {
  857.     TH1=0xED;
  858.         TL1=0xFE;
  859.         key_scan();               
  860. }

  861. void main()
  862. {
  863.         dingshiqi0();//定时器0初始化
  864.         dingshiqi1();//定时器1初始化
  865.         LCD1602_init();//LCD1602初始化
  866.         DS1302_init();//DS1302初始化
  867.         while(1)
  868.         {
  869.                 key_driver();
  870.                 alarmset();//闹钟设定函数
  871.                 if(system==normal)//当状态为正常显示时间时
  872.                 {
  873.                    updatetime();//刷新时间
  874.                    updatedate();//刷新日期
  875.                    DS18B20deal(DS18B20readtemp());//DS18B20数据处理函数 同时输出温度
  876.                 }
  877.                 else if(system==normal_12)//当状态为显示12小时制
  878.                 {
  879.                    updatetime_12();//刷新时间
  880.                    updatedate();//刷新日期
  881.                 }
  882.         }
  883. }
复制代码

所有资料51hei提供下载:
单片机考试:51单片机时钟闹钟.zip (143.44 KB, 下载次数: 386)


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

使用道具 举报

沙发
ID:73182 发表于 2019-1-31 07:57 | 只看该作者
感谢分享,再加个电路图就好了
回复

使用道具 举报

板凳
ID:406781 发表于 2019-1-31 12:03 | 只看该作者
ptlantu 发表于 2019-1-31 07:57
感谢分享,再加个电路图就好了

电路图参考普中开发板的就行了
回复

使用道具 举报

地板
ID:406781 发表于 2019-1-31 12:05 | 只看该作者
上面是我用的开发板的电路图

EM3 V2.2开发板原理图.pdf

274.28 KB, 下载次数: 108, 下载积分: 黑币 -5

回复

使用道具 举报

5#
ID:537607 发表于 2019-5-28 10:02 来自手机 | 只看该作者
谢谢分享 帮了大忙
回复

使用道具 举报

6#
ID:469510 发表于 2019-5-28 13:53 | 只看该作者
谢谢分享
回复

使用道具 举报

7#
ID:555438 发表于 2019-6-5 11:40 | 只看该作者
楼主你的程序调整时间之后不具备保存的功能吗,我调整之后按一下k1就自动回到初始时间了
回复

使用道具 举报

8#
ID:406781 发表于 2019-7-16 21:49 | 只看该作者
dreamasakura 发表于 2019-6-5 11:40
楼主你的程序调整时间之后不具备保存的功能吗,我调整之后按一下k1就自动回到初始时间了

时间保存啊只是闹钟没有存储功能上电闹钟会丢失数据而已
回复

使用道具 举报

9#
ID:589966 发表于 2019-7-25 17:47 | 只看该作者
下载了压缩包解压后,keil4打不开,求楼主帮忙
回复

使用道具 举报

10#
ID:406781 发表于 2019-7-29 12:12 | 只看该作者
Fairchild 发表于 2019-7-25 17:47
下载了压缩包解压后,keil4打不开,求楼主帮忙

没有问题啊我这边。刚刚下载用我的keil4是可以打开并且编译的[img][/img]

1564373499(1).jpg (312.58 KB, 下载次数: 45)

1564373499(1).jpg
回复

使用道具 举报

11#
ID:84745 发表于 2019-10-20 12:11 来自手机 | 只看该作者
感谢分享
回复

使用道具 举报

12#
ID:345799 发表于 2019-10-20 14:50 | 只看该作者
学习了
回复

使用道具 举报

13#
ID:611626 发表于 2019-10-27 10:32 | 只看该作者
请教一下:压缩文件内少了4个按键声明,添加到KEY.H以后显示屏无显示,怎么回事
回复

使用道具 举报

14#
ID:613618 发表于 2019-10-27 12:05 来自手机 | 只看该作者
有闹钟功能就应该有储存功能,这应该算不成熟的程序,望楼主改善
回复

使用道具 举报

15#
ID:258542 发表于 2019-11-9 11:42 | 只看该作者
下载一个学习下
回复

使用道具 举报

16#
ID:258542 发表于 2019-11-9 13:16 | 只看该作者
宏达工控 发表于 2019-10-27 10:32
请教一下:压缩文件内少了4个按键声明,添加到KEY.H以后显示屏无显示,怎么回事

我也碰到一样的问题,在key.h中申明,用extern关键词,就可以了。

目前我的问题是:编译时出现错误
main.c(25): error C230: 'Time': unknown struct/union/enum tag
main.c(35): error C230: 'alarmtime': unknown struct/union/enum tag
这两个结构体无法识别,不知道是哪里错了?
回复

使用道具 举报

17#
ID:229641 发表于 2019-11-12 16:41 来自手机 | 只看该作者
掉电还会走时吗?
回复

使用道具 举报

18#
ID:641369 发表于 2019-12-1 19:35 | 只看该作者
想着下来弄个时钟玩玩
回复

使用道具 举报

19#
ID:632112 发表于 2019-12-6 11:51 | 只看该作者
下载一个学习下
回复

使用道具 举报

20#
ID:406781 发表于 2020-2-25 13:27 | 只看该作者
依恋晓 发表于 2019-10-27 12:05
有闹钟功能就应该有储存功能,这应该算不成熟的程序,望楼主改善

对这应该要有存储功能但那时偷懒就没有加
回复

使用道具 举报

21#
ID:406781 发表于 2020-2-25 13:28 | 只看该作者

会啊因为板子里面的DS1302自带电池
回复

使用道具 举报

22#
ID:406781 发表于 2020-2-25 13:32 | 只看该作者
绊脚石13 发表于 2019-11-9 13:16
我也碰到一样的问题,在key.h中申明,用extern关键词,就可以了。

目前我的问题是:编译时出现错误

想看看你的情况截图一下看看呗
回复

使用道具 举报

23#
ID:812792 发表于 2020-8-11 17:42 | 只看该作者
请问楼主,时间显示,温度,闹钟的功能都能实现么
回复

使用道具 举报

24#
ID:812792 发表于 2020-8-11 17:46 | 只看该作者
请问楼主有没有仿真的电路图呢,帮帮小菜鸡叭
回复

使用道具 举报

25#
ID:406781 发表于 2021-10-21 09:59 | 只看该作者
张张不会单片机 发表于 2020-8-11 17:46
请问楼主有没有仿真的电路图呢,帮帮小菜鸡叭

无,只有上面的开发板原理图
回复

使用道具 举报

26#
ID:406781 发表于 2021-10-21 10:00 | 只看该作者
张张不会单片机 发表于 2020-8-11 17:42
请问楼主,时间显示,温度,闹钟的功能都能实现么

对的,可以实现的
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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