单片机论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

1602多功能万年历,温湿度计,非RTC时钟芯片

[复制链接]
跳转到指定楼层
楼主
最近闲来无事,学单片机已经快3个月了,前一段时间做出了一个跑步机系统,可以完成霍尔测速,路程卡路里与语音控制,精准度不错,毕设结束了给大家分享一下。想起来刚学单片机有很多弯路,就重新写了一下之前做过的这个电子钟,还是没用DS1302芯片,全程只用了一个定时器,结合了DHT11,DS18B20等常用的东西,希望对刚学的新手能有所帮助,大神见笑了。改万年历具有以下功能:
1.万年历,自编的根据蔡勒公式自动算大小月天数自动算出星期,各种试验都正确无误。
2.DS18B20温度与DHT11湿度的自动循环显示,1S刷新周期约5S循环
3.电子闹钟,可以设置打开或关闭,光标调节闹钟时间,默认为OFF关闭,响铃后按任意键可关闭
4.移动光标设置时间,按键手感舒适
5.温度报警,可以设置 单开上限或者下限或者上下限或者关闭,温度调节自己设置为0-50度,可改范围,默认为NO-NO关闭,低于0度自动报警
6.秒表 可以选择秒表打开,暂停,计次,清零,秒表范围9999秒,精度到10MS,自己对着IPHONE优化调试后误差在0.00-0.02之间,做一般的秒表没问题。
7.优化了温度为负数情况下的效果,有兴趣的可以放冰箱
8.无操作60S自动熄灭背光,有操作点亮屏幕
9.所有模块的开启或者关闭都没有冲突与BUG,比如秒表与走时可以同时打开没有冲突等,所以设置带记忆功能
今天刚下了场雨,天气十分凉爽,在窗户口试了一下温湿度,很稳定精准,变化的速度看起来也很舒服,就想把这个程序分享给大家,对新手入门应该能有所帮助,做个实物放在桌上跑着也是很不错的。



评分

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

查看全部评分

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

使用道具 举报

沙发
 楼主| 打死大四多 发表于 2017-5-29 22:14 | 只看该作者
 
有详尽的注释,有兴趣的同学可以焊接一个实物烧进去试试,因为不用RTC芯片也不用担心换纽扣电池,12MHZ的晶振带软件补偿日误差可以调节到1S以内。调节方法就是算出每误差1S的情况然后改buchang参数的值就可以了。因为手头只有一个多余的DHT11温湿度了所以用18B20的温度和DHT11湿度,实际上温度精度很高,湿度也凑合吧,如果那天有了更好的湿度传感器再改改湿度程序。

单片机源程序如下:
  1. #include <reg52.h>                                                   
  2. typedef  unsigned int u16;         
  3. typedef  unsigned char u8;
  4. sbit k2=P3^2;                                            //K1 K2 K3 K4按键接口,建议从左到右接K1-K4
  5. sbit k1=P3^5;
  6. sbit k3=P3^3;
  7. sbit k4=P3^4;
  8. sbit DQ=P3^6;
  9. sbit beep=P1^6;   
  10. sbit Data=P2^0;                                             //有源蜂鸣器在P16口
  11. sbit lcden=P1^4;                                                //LCD1602接口定义
  12. sbit lcdrs=P1^0;                                                   
  13. sbit lcdrw=P2^6;
  14. sbit bg=P2^7;                                                //背光变量接入LCD1602的K极,通过bg的高低电平就可控制自动熄灭与点亮
  15. u8 k,e,d,o=1,p=1,temp,nxflag=0,mbflag=0,tianmax;      
  16. float temperature;                                           //温度变量,18B20接收时为浮点数
  17. u8 miao1,miao2,fen1,fen2,shi1,shi2,tian1,tian2,wk,tem1,tem2,tem3,wendufu;
  18. u8 day=1,mon=1,day1,day2,yue1,yue2,mbw,n=0,m=0,beiguang,RH,RL,TH,TL,tempH,tempL;
  19. u8 se1,se2,mon1,mon2,hou1,hou2,min1,min2,MB2,nian1,nian2,nian3,nian4;
  20. u16 y,MB1;
  21. u16 temper,buchang,tempwarn=0,tempwarn1=500;                //tempwarn为温度下限,1为温度上限
  22. u8 code set[]={"NaoZhong  Status"};                                    //上电后傻瓜调节模块
  23. u8 code tempwarng[]={"Wendu Waring!"};
  24. u8 code temmin[]={"Min"};
  25. u8 code temmax[]={"Max"};               
  26. u8 code naozhongON[]={" ON"};
  27. u8 code naozhongOFF[]={"OFF"};
  28. u8 code setsucces[]={"Set Success!"};
  29. u8 code thanks[]={"Welcome to use !"};
  30. u8 code thanksu[]={"thanks for using"};
  31. u8 code make[]={"Designed by LY"};
  32. u8 code MB[]={"Stopwatch"};
  33. u8 code week1[]={"[MON]"};
  34. u8 code week2[]={"[TUE]"};
  35. u8 code week3[]={"[WED]"};
  36. u8 code week4[]={"[THU]"};
  37. u8 code week5[]={"[FRI]"};
  38. u8 code week6[]={"[SAT]"};
  39. u8 code week7[]={"[SUN]"};                        
  40. void delay(unsigned int z)                                   //定义延时函数
  41. {                                          
  42.   unsigned int x,y;                       
  43.   for(x=z;x>0;x--)
  44.   for(y=1;y>0;y--);
  45. }
  46. void DHT11_delay_us(u8 n)
  47. {
  48.     while(--n);
  49. }
  50. void DHT11_delay_ms(u16 z)               //定义DHT11延迟函数
  51. {
  52.    u16 i,j;
  53.    for(i=z;i>0;i--)
  54.       for(j=110;j>0;j--);
  55. }

  56.          void DHT11_start()
  57. {
  58.    Data=1;
  59.    DHT11_delay_us(2);
  60.    Data=0;
  61.    DHT11_delay_ms(20);   //延时18ms以上
  62.    Data=1;
  63.    DHT11_delay_us(30);
  64. }
  65. u8 DHT11_rec_byte()      //接收一个字节
  66. {
  67.   u8 i,dat=0;
  68.   for(i=0;i<8;i++)       //从高到低依次接收8位数据
  69.    {         
  70.       while(!Data);       //等待50us低电平过去
  71.       DHT11_delay_us(8);   //延时60us,如果还为高则数据为1,否则为0
  72.       dat<<=1;           //移位使正确接收8位数据,数据为0时直接移位
  73.       if(Data==1)        //数据为1时,使dat加1来接收数据1
  74.          dat+=1;
  75.       while(Data);       //等待数据线拉低   
  76.     }  
  77.     return dat;
  78. }
  79. void DHT11_receive()      //接收40位的数据
  80.         {
  81.     u8 R_H,R_L,T_H,T_L,revise;
  82.     DHT11_start();
  83.     if(Data==0)
  84.     {
  85.         while(Data==0);   //等待拉高     
  86.         DHT11_delay_us(40);      //拉高后延时80us
  87.         R_H=DHT11_rec_byte();    //接收湿度高八位  
  88.         R_L=DHT11_rec_byte();    //接收湿度低八位  
  89.         T_H=DHT11_rec_byte();    //接收温度高八位  
  90.         T_L=DHT11_rec_byte();    //接收温度低八位
  91.         revise=DHT11_rec_byte(); //接收校正位
  92.         DHT11_delay_us(25);      //结束
  93.         if((R_H+R_L+T_H+T_L)==revise)      //校正
  94.         {
  95.             RH=R_H;
  96.             RL=R_L;
  97.                         TH=T_H;
  98.                         TL=T_L;
  99.         }
  100.     }
  101.   }
  102. void beepon()                                                //PWM(如果你是无源蜂鸣器,这里写PWM函数)
  103. {                                                             //当前为有源蜂鸣器,有源蜂鸣器无需更改
  104.    beep=0;
  105.    delay(1200);
  106.    beep=1;     
  107. }         
  108. void write_nian();                                  //预定义
  109. void write_yue();
  110. void write_tian();
  111. void write_shi();
  112. void write_fen();
  113. void write_miao();
  114. void write_week();
  115. void zhuanhuan();
  116. void write_temp();
  117. void write_nz();
  118. void nzON();
  119. void write_setsuccess();
  120. void beiguangpd();

  121. void write_com(u8 com)                                    //LCD1602初始化程序,了解1602时序图后新手的话可以直接照搬使用                                    
  122. {
  123. lcdrs=0;
  124. P0=com;
  125. delay(5);
  126. lcden=1;
  127. delay(5);
  128. lcden=0;
  129. }
  130. void write_data(u8 date)
  131. {
  132. lcdrs=1;
  133. P0=date;
  134. delay(5);
  135. lcden=1;
  136. delay(5);
  137. lcden=0;
  138. }
  139. void init()
  140. {
  141. lcdrw=0;
  142. lcden=0;
  143. write_com(0x38);
  144. write_com(0x0c);
  145. write_com(0x06);
  146. write_com(0x01);
  147. write_com(0x80+0x10);  
  148. }       
  149. void Timer0Init()                                                    //定时器0工作方式1 中断初始化,923位12M晶振在KEIL仿真后的计算结果
  150. {   
  151.     TMOD=0X01;
  152.         TH0=(65535-901)/256;       
  153.         TL0=(65535-901)%256;       
  154.         ET0=1;                                          //打开定时器0中断允许位
  155.         EA=1;                                         //打开总中断允许
  156.         TR0=1;                                                 //打开 定时器0,开始计时
  157. }
  158. Init_DS18B20(void)                                    //DS18B20初始化与时序图程序,仿真时温度问题改进这个初始化程序就解决了
  159.   {
  160.        DQ=1;
  161.        delay(70);
  162.        DQ=0;
  163.        delay(485);
  164.        DQ=1;
  165.        delay(50);
  166.   }
  167. ReadOneChar(void)                                      //18B20读一个字节
  168.   {  
  169.     unsigned char i=0;
  170.     unsigned char dat=0;
  171.        for (i=8;i>0;i--)
  172.      {
  173.          DQ=1;
  174.          delay(1);
  175.          DQ=0;
  176.          dat>>=1;
  177.          DQ=1;
  178.          if(DQ)
  179.          dat|=0x80;
  180.          delay(4);
  181.        }
  182.     return(dat);
  183.    }  
  184. WriteOneChar(unsigned char dat)                     //18B20写一个字节
  185.    {
  186.          unsigned char i=0;
  187.          for(i=8;i>0;i--)
  188.         {
  189.              DQ=0;
  190.              DQ=dat&0x01;
  191.              delay(5);
  192.              DQ=1;
  193.              dat>>=1;
  194.         }
  195.           delay(4);
  196.     }
  197. ReadTemperature(void)                           //读取温度函数定义,返回值为浮点数
  198.    {
  199.         Init_DS18B20();
  200.         WriteOneChar(0xcc);
  201.         WriteOneChar(0x44);
  202.         delay(125);
  203.         Init_DS18B20();
  204.         WriteOneChar(0xcc);
  205.         WriteOneChar(0xbe);
  206.         tempL=ReadOneChar();
  207.         tempH=ReadOneChar();
  208.             if(tempH>0x7f)
  209.                 {
  210.                 tempH=~tempH;
  211.                 tempL=~tempL+1;
  212.                 wendufu=1;
  213.                 }
  214.                 else
  215.                 wendufu=0;
  216.                 temperature=(((tempH*256)+tempL)*0.0625)*10;
  217.         delay(200);
  218.         return(temperature);
  219.     }
  220. void welcome()                                       //定义欢迎函数
  221. { static u8 i;
  222.   init();                                              //初始化1602
  223.   delay(5000);
  224.   for(i=0;i<16;i++)
  225.   {
  226.   write_com(0x80+i);
  227.   write_data(thanks[i]);
  228.   delay(4000);
  229.   }
  230.   delay(50000);
  231.   for(i=0;i<14;i++)
  232.   {
  233.   write_com(0x81+0x40+i);
  234.   write_data(make[i]);
  235.   delay(4000);
  236.   }
  237.   delay(50000);
  238.   delay(50000);
  239. }

  240. void pdtian1()                          //PD在上电后设置完毕主界面处的天数判断
  241. {
  242. if((p==1||p==3)||(p==5||p==7)||(p==8||p==10)||p==12)       
  243.                 tianmax=31;
  244.           if((p==4||p==6)||(p==9||p==11))
  245.            tianmax=30;

  246.           if(p==2)
  247.           {
  248.             if(((y%4==0)&&(y%100!=0))||(y%400==0))
  249.                   tianmax=29;
  250.                 else
  251.                   tianmax=28;
  252.           }
  253. }
  254. void pdxingqi1()                     //PD在上电后设置完毕至主界面处的星期判断
  255. {
  256.   static char c,yi,mt,xwk1,xwk2,xwk3;
  257.   static int xwk,yn,xwk4;
  258.   yn=y;
  259.   if(p==1||p==2)
  260.           { yn=yn-1;
  261.             mt=p+12;
  262.          }
  263.           else
  264.       mt=p;
  265.    yi=yn%100;
  266.    c=yn/100;
  267.   xwk1=yi+(yi/4);
  268.   xwk2=c/4;
  269.   xwk3=2*c;
  270.   xwk4=(26*mt+26)/10;
  271.   xwk=xwk1+xwk2-xwk3+xwk4+o-1;
  272.   while(xwk<0)
  273.   {xwk+=7; }
  274.   wk=xwk%7;
  275. }
  276. void Display()                                //定义主程序 显示部分函数模块
  277. {           static u16 xunhuan;
  278.      RH=RH%100;
  279.      write_nian();                          //1602写入显示年
  280.      write_com(0x84);
  281.      write_data('-');                              
  282.      write_yue();                        //写入月
  283.             write_com(0x87);
  284.      write_data('-');
  285.             write_com(0x88);
  286.      write_tian();                         //写入天
  287.      write_week();
  288.      write_shi();
  289.          write_com(0x82+0x40);
  290.      write_data(':');
  291.      write_fen();
  292.          write_com(0x85+0x40);
  293.      write_data(':');
  294.          write_miao();                           //写入温度,温度TEM1与2与3是温度的三位数                                                         
  295.          xunhuan++;
  296.          if(xunhuan<180)
  297.         {if(wendufu==1)
  298.          {       
  299.          if((temper/100)!=0)
  300.          {
  301.          write_com(0x89+0x40);
  302.          write_data('-');
  303.          write_com(0x8a+0x40);
  304.          write_data(tem1);   
  305.          }
  306.          else
  307.          {
  308.          write_com(0x89+0x40);
  309.          write_data(' ');  
  310.          write_com(0x8a+0x40);
  311.          write_data('-');  
  312.          }
  313.          }

  314.          else
  315.          {
  316.          write_com(0x89+0x40);
  317.          write_data(' ');
  318.          
  319.          if((temper/100)!=0)  
  320.          {
  321.          write_com(0x8a+0x40);
  322.          write_data(tem1);
  323.          }
  324.          else
  325.          {
  326.          write_com(0x8a+0x40);
  327.          write_data(' ');
  328.          } }
  329.          write_com(0x8b+0x40);
  330.          write_data(tem2);
  331.          write_com(0x8c+0x40);
  332.          write_data('.');
  333.          write_com(0x8d+0x40);
  334.          write_data(tem3);
  335.          write_com(0x8e+0x40);
  336.          write_data(0xdf);
  337.          write_com(0x8f+0x40);
  338.          write_data('C');
  339.          }
  340.          if(xunhuan>180)
  341.          {
  342.          write_com(0x89+0x40);
  343.          write_data(' ');
  344.          write_com(0x8a+0x40);
  345.          write_data(' ');
  346.          write_com(0x8b+0x40);
  347.          write_data(RH/10+0x30);
  348.          write_com(0x8c+0x40);
  349.          write_data(RH%10+0x30);
  350.          write_com(0x8d+0x40);
  351.          write_data('%');
  352.          write_com(0x8e+0x40);
  353.           write_data('R');
  354.           write_com(0x8f+0x40);
  355.          write_data('H');
  356.          }
  357.          if(xunhuan==360)
  358.          xunhuan=0;          
  359. }
  360. void NZdisplay()                                    //定义闹钟模块
  361. {
  362.    static u8 nzflag=2,nzwei;                        
  363.    delay(2000);
  364.    init();
  365.    delay(2000);
  366.    nzON();                                         //闹钟开关选择模块
  367.    while(k4)                                     //没有检测到K4键退出时无限循环
  368.     {  
  369.             write_nz();                         //写入闹钟模块
  370.                 if(k3==0)                        //判断K3键是否按下
  371.         {
  372.                  delay(5000);
  373.                  if(k3==0)                      //延时消抖
  374.                 {beepon();                       //响一声
  375.                  if(nxflag==0)                        //如果NXFLAG为0,闹钟为关闭状态,给其赋值为1,
  376.                  nxflag=1;
  377.                  else
  378.              nxflag=0;                                
  379.                 }
  380.                  nzON();                           //判断闹钟的状态
  381.                 }
  382.                 if(k1==0)                             //如果K1键按下后
  383.                 {
  384.                  delay(8000);
  385.                  if(k1==0)
  386.                 {
  387.                  beepon();
  388.                  if(nzwei==0)                             //通过NZWEI来判断当前光标的位置与设置小时还是分钟
  389.                  nzflag=0;
  390.                  if(nzwei==1)
  391.                  nzflag=1;
  392.                 }
  393.                 }

  394.                 if(nzflag==0)
  395.             {
  396.                 while(1)
  397.           {       
  398.                    write_com(0x83+0x40);             //光标闪烁
  399.         write_data(0xff);
  400.                 delay(5000);
  401.                 write_nz();                        //写入闹钟
  402.                   delay(5000);
  403.                 if(k2==0)                           //如果K2为0
  404.              {
  405.                  delay(50);
  406.                  if(k2==0)
  407.                 {
  408.                  beepon();                         //判断小时状态,进行+1
  409.                  if(n<23)
  410.                  n+=1;
  411.                  else
  412.                  n=0;
  413.                 }
  414.                 }
  415.                  if(k3==0)                         //如果K3为0
  416.                  {
  417.                  delay(50);
  418.                  if(k3==0)                       //判断小时状态,进行-1 最大溢出重回最小,最小溢出重回最大
  419.                  {
  420.                  beepon();
  421.                  if(n>0)                          
  422.                  n-=1;
  423.                  else
  424.                  n=23;
  425.                  }
  426.                 }
  427.                 if(k1==0)
  428.                 {
  429.                  delay(1000);                  //如果K1按下,更改NZFLAG,更改闹钟光标位
  430.                  if(k1==0)
  431.                  {
  432.                  nzflag=1;       
  433.                  beepon();
  434.                  break;
  435.                  }
  436.                 }
  437.             if(k4==0)                          //如果K4按下,退出。给NZFLAG重新赋值为2,取消光标并下次进入不会直接进入光标
  438.                  {
  439.                  beepon();
  440.                  delay(6000);
  441.          nzflag=2;
  442.                  nzwei=0;
  443.                  break;         }
  444.            }
  445.         }
  446.         if(nzflag==1)                             //如果NZ为1,同上,此时为分钟调节
  447.     {  while(1)
  448.            {       
  449.                 write_com(0x86+0x40);
  450.         write_data(0xff);
  451.                 delay(5000);
  452.                 write_nz();
  453.                 delay(5000);
  454.                   if(k2==0)
  455.              {
  456.                  delay(50);
  457.                  if(k2==0)
  458.                 {
  459.                  beepon();
  460.                  if(m<59)
  461.                  m+=1;
  462.                  else
  463.                  m=0;
  464.                 }
  465.                 }
  466.                  if(k3==0)
  467.                  {
  468.                  delay(50);
  469.                  if(k3==0)
  470.                  {
  471.                  beepon();
  472.                  if(m>0)
  473.                  m-=1;
  474.                  else
  475.                  m=59;
  476.                  }
  477.                 }
  478.                 if(k1==0)
  479.                 {
  480.                  delay(1000);
  481.                  if(k1==0)
  482.                 {
  483.                  beepon();
  484.                  nzflag=0;
  485.                  break;
  486.                  }
  487.                 }
  488.                 if(k4==0)
  489.                  {
  490.                  beepon();
  491.        
  492.                  delay(6000);
  493.          nzflag=2;
  494.                  nzwei=1;
  495.                  break;         }
  496.           }

  497.         }
  498.         if(k4==0)
  499.         {
  500.          beepon();
  501.          delay(30000);
  502.          break;
  503.         }       
  504.    }
  505.     nzflag=2;
  506.     init();
  507. }
  508. void temperwaring()                           //定义温度警报模块
  509. {  
  510.    static u8 temflag=2,temwei;                        
  511.    delay(5000);
  512.    init();
  513.    delay(5000);
  514.    while(k4)
  515.     {        
  516.             write_temp();                                //写入温度
  517.                 if(k3==0)                           //如果K3为0,为其赋值为N0-N0,关闭温度警报,并且不会闪烁光标
  518.         {
  519.                  beepon();
  520.                  delay(3000);
  521.                  tempwarn=(0X4e-0x30)*100;
  522.                  tempwarn1=(0X4e-0x30)*100;
  523.                 }
  524.                 if(k1==0)                        //如果K1为0,进入光标位,光标闪烁,根据temwei不同进入不同的初始闪烁位置
  525.                 {
  526.                  delay(8000);               
  527.                  if(k1==0)
  528.                 {
  529.                  beepon();
  530.                  if(temwei==0)                     //为只需单独打开温度上限或下限报警时提供方便
  531.                  temflag=0;
  532.                  if(temwei==1)
  533.                  temflag=1;
  534.                 }
  535.                 }
  536.                 if(temflag==0)                       //和闹钟模块 类似,如果temflag为0的话进入下限调整,否则进入上限调整
  537.             {
  538.                 while(1)
  539.           {       
  540.                    write_com(0x86+0x40);
  541.         write_data(0xff);
  542.                 delay(6000);
  543.                 write_temp();
  544.                 delay(4000);
  545.                 if(k2==0)
  546.              {
  547.                  delay(50);
  548.                  if(k2==0)
  549.                 {
  550.                  beepon();
  551.                  if(tempwarn<500)                              //温度范围为精确到小数点后1位,500为50.0度,自己设置每次只调节1度
  552.                  tempwarn+=10;                                 //如果需要温度报警精确到0.1度,请将此处改为1并重新修改界面
  553.                  else
  554.                  tempwarn=0;
  555.                 }
  556.                 }
  557.                  if(k3==0)                  
  558.                  {
  559.                  delay(50);
  560.                  if(k3==0)
  561.                  {
  562.                  beepon();
  563.                  if(tempwarn>0&&(tempwarn!=(0X4e-0x30)*100))       //K3键按下,判断当在关闭状态与一般状态时,温度阀门下限减1度
  564.                  tempwarn-=10;
  565.                  else
  566.                  tempwarn=500;
  567.                  }
  568.                 }
  569.                 if(k1==0)                                 //如果检测K1按下,跳出循环,给FLAG重新赋值为1,光标开始在温度上限处闪烁
  570.                 { delay(1000);                              //并且开始调节温度上限
  571.                  temflag=1;                                        
  572.                  beepon();
  573.                  break;
  574.                 }
  575.             if(k4==0)                            //如果K4等于0,第一次确定,光标停止闪烁,K2K3不会更改数值
  576.                  {                                    //目的是在确定无误后在下次按下K4时可以直接退出
  577.                  beepon();
  578.                  delay(6000);                    
  579.          temflag=2;
  580.                  temwei=0;
  581.                  break;         }
  582.            }
  583.         }
  584.         if(temflag==1)                   //进入温度修改上限部分,同温度修改下限
  585.     {  while(1)
  586.            {       
  587.                 write_com(0x89+0x40);
  588.         write_data(0xff);
  589.                 delay(6000);
  590.                 write_temp();
  591.                 delay(4000);
  592.                   if(k2==0)
  593.              {
  594.                  delay(50);
  595.                  if(k2==0)
  596.                 {
  597.                  beepon();
  598.                  if(tempwarn1<500)
  599.                  tempwarn1+=10;
  600.                  else
  601.                  tempwarn1=0;
  602.                 }
  603.                 }
  604.                  if(k3==0)
  605.                  {
  606.                  delay(50);
  607.                  if(k3==0)
  608.                  {
  609.                  beepon();
  610.                  if((tempwarn1>0)&&(tempwarn1!=(0X4e-0x30)*100))
  611.                  tempwarn1-=10;
  612.                  else
  613.                  tempwarn1=500;
  614.                  }

  615.                 }
  616.                 if(k1==0)
  617.                 {beepon();
  618.                  delay(1000);
  619.                  temflag=0;
  620.                  break;
  621.                 }
  622.                 if(k4==0)
  623.                  {
  624.                  beepon();
  625.        
  626.                  delay(6000);
  627.          temflag=2;
  628.                  temwei=1;
  629.                  break;         }
  630.           }

  631.         }
  632.         if(k4==0)                                           //当光标不闪烁时,按下K4键,直接退出
  633.         {
  634.          beepon();
  635.          delay(30000);
  636.          break;
  637.         }       
  638.    }
  639.                 temflag=2;                           //temflag重新赋值为2,目的是确保下次进入不会直接进入光标调节模块
  640.                 init();ET0=1;                       //这样就可以方便的快速关闭温度报警及快速设置上下限
  641.        
  642. }
  643. void miaobiaods()                           //定义秒表显示模块
  644. {
  645. static u8 i,times;
  646. delay(1000);
  647. init();
  648. delay(10000);
  649. while(1)
  650. {
  651. if(MB1==10000)                           //MB1位16位数,所以秒表在0.00-100.00的计数范围使用MB1,超出后清0累加MB2
  652. {
  653. MB1=0;MB2++;
  654. }
  655. if(MB2==100)                  //如果秒表超出了10000秒,直接清零,若想修改更大秒表范围请将MB2定义为16位数再修改,并修改显示界面
  656. {MB2=0;MB1=0;
  657.   mbflag=0;
  658. }
  659. for(i=0;i<9;i++)                   //1602循环显示STOPWATCH
  660. {
  661. write_com(0x84+i);
  662. write_data(MB[i]);                               
  663. }
  664. write_com(0x83+0x40);                   //显示秒表运行状态模块
  665. write_data(times/10+0x30);
  666. write_com(0x84+0x40);
  667. write_data(times%10+0x30);                 //TIMES为计数部分,不为0时每次暂停可以计数一次
  668. write_com(0x86+0x40);
  669. write_data(MB2/10+0x30);
  670. write_com(0x87+0x40);                     //秒表高位MB2与低位MB1转换为16进制数显示
  671. write_data(MB2%10+0x30);
  672. write_com(0x88+0x40);
  673. write_data('.');
  674. write_data((MB1/1000)+0x30);
  675. write_com(0x8a+0x40);
  676. write_data(MB1%1000/100+0x30);
  677. write_com(0x8b+0x40);
  678. write_data('.');
  679. write_com(0x8c+0x40);
  680. write_data(MB1%1000%100/10+0x30);
  681. write_com(0x8d+0x40);
  682. write_data(MB1%1000%100%10+0x30);
  683.   if(k1==0)                                      //由于秒表对精度要求很高,必须直接中断不能延时
  684. {mbflag=1;                                     //因此也不能只用一个K1进行开始于暂停
  685. beepon();        }                             //此时按下K1键为打开秒表,会有立刻的响铃以便直观表明计时开始
  686.   if(k2==0)                                             //和以上原因一样,秒表暂停
  687. {mbflag=0;                                           //按下K2键为暂停
  688.   beepon();
  689.   if(MB1!=0)                                          //如果不为0,计次+1
  690.   { delay(40000);
  691.    if(times<99)                                       //计次范围0-99
  692.    times+=1;
  693.    }
  694. }
  695.   if(k3==0)                                         //按下K3,秒表数据清0
  696.   {beepon();
  697.    mbflag=0;
  698.    times=0;
  699.    MB1=0;
  700.    MB2=0;
  701.   }
  702.   if(k4==0)
  703.   {beepon();                             //K4为0,退出秒表,如果打开秒表也可直接退出,秒表与时间并不冲突
  704.   break;}
  705.   }
  706.   delay(1000);
  707.   init();                            //延时初始化,确保时间充足无乱码
  708.   delay(10000);
  709. }
  710. void naozhongfamen()                            //主界面上判断是否进入闹钟设置界面的模块
  711. {
  712.   if(k3==0)
  713.   {       
  714.   delay(50000);                                  //如果K3长按,进入闹钟
  715.   if(k3==0)
  716.   {
  717.   beepon();
  718.   delay(3000);
  719.   NZdisplay();
  720.   delay(10000);
  721.   write_setsuccess();
  722.   delay(30000);                                    
  723.   init();
  724.   }
  725.   }
  726. }
  727. void wendufamen()                                 //主界面上判断是否进入温度报警设置界面的模块
  728. {
  729.   if(k2==0)
  730.   {       
  731.   delay(50000);
  732.   if(k2==0)
  733.   { beepon();
  734.   delay(3000);
  735.   temperwaring();                                    
  736.   delay(10000);
  737.   write_setsuccess();
  738.   delay(30000);
  739.   init();
  740.   }
  741.   }
  742. }
  743. void miaobiao()                       //主界面上判断是否进入秒表的模块
  744. {  if(mbflag==1)
  745. {
  746. if(MB1>10000)
  747. {
  748. MB1=0;MB2++;
  749. }
  750. if(MB2==100)
  751. {MB2=0;MB1=0;
  752.   mbflag=0;
  753. }
  754. }
  755. if(k4==0)
  756. {
  757.    delay(50000);
  758.    if(k4==0)
  759.    {
  760.         beepon();
  761.         delay(3000);
  762.         miaobiaods();
  763.         delay(10000);
  764.         init();
  765.    }
  766. }
  767. }
  768. void Timer0() interrupt 1                       //定义中断函数,923为12M晶振的精度,如果是11.05M晶振请根据仿真或实测自行改变这个值
  769. {         
  770.     static u16 i;       
  771.     TH0=(65535-901)/256;       
  772.         TL0=(65535-901)%256;       
  773.         i++;                                   //i为秒,不断累加
  774.         beiguangpd();                              //进行背光判断,确保背光第一时间响应
  775.         if(mbflag==1)
  776.         {                                         //如果检测到打开秒表了,就开始秒表位累加
  777.          mbw++;
  778.          if(mbw==10)
  779.          {
  780.          mbw=0;
  781.          MB1++;
  782.          }
  783.         }
  784.         if(i==1000)                           //如果检测到1000,秒+1
  785.         {
  786.     k++; i=0;
  787.         if(beiguang<60)                       //如果背光变量小于60,此时背光打开
  788.         beiguang++;
  789.         buchang++;         
  790.         DHT11_receive();
  791.         temper=ReadTemperature();               //检测温度,检测周期是1S
  792.     }       
  793.         if(k==60)                                  //判断各个变量,也可将这些放到其他模块里,但是精度未必会提高
  794.         {
  795.           k=0;
  796.       e++;
  797.         }
  798.         if(buchang==4955)                                     //精度补偿部分,不一定适合你的晶振
  799.         {
  800.      buchang=0;k+=1;
  801.          }
  802.          if(e==60)
  803.     {
  804.            e=0;
  805.            d++;
  806.          }
  807.          if(d==24)
  808.          {
  809.            d=0;
  810.            o++;
  811.            if(wk<6)
  812.            wk++;
  813.            else
  814.            wk=0;
  815.          }
  816.          if(o==tianmax+1)
  817.    {
  818.            o=1;
  819.            p++;
  820.          }
  821.          if(p==13)
  822.          {
  823.           p=1;
  824.           y++;
  825.          }
  826. }         
  827. void bijiao()                                 //比较模块,也是报警触发模块
  828. {
  829.   static u8 gbflag;
  830. if(m==e&&n==d)                                  //如果闹钟时间相同,开始响铃,时长1分钟
  831. {
  832. if(gbflag==0)                                   //如果不是在响铃并按键关闭后,才会响铃
  833. {
  834. if(nxflag==1)                                 //如果闹钟为开启状态响铃,否则不响
  835. beepon();
  836. if(k2==0||k3==0||k4==0)                        //如果有K2,K3,K4任何一个按键触发,就会将gbflag设置为1,停止响铃
  837. gbflag=1;                                       //因为K1键快速按下还有快捷粗调暂停1秒的功能,所以没有K1键
  838. }
  839. }
  840. else
  841. gbflag=0;                              //响铃完毕后给gbflag赋值为0;
  842. if(e==0&&k==0)                                      //整点报时模块,设置为7到24点整点报时,可改范围,不会影响休息也比较合适
  843.   {if((d>6&&d<24)||d==0)
  844.    beepon();
  845.   }                       
  846.    if((tempwarn!=(0X4e-0x30)*100))
  847.    {
  848.          if(wendufu==1)
  849.          beepon();
  850.    }
  851.   if((tempwarn!=(0X4e-0x30)*100)||(tempwarn1!=(0X4e-0x30)*100))          //判断温度阀门打开了上限还是下线还是关闭还是上下限同时打开
  852. {
  853.     if((tempwarn==(0x4e-0x30)*100)&&(tempwarn1!=(0X4e-0x30)*100))               //判断完毕后只要触发就会报警
  854.      {
  855.            if(tempwarn1<temper)
  856.           {
  857.            beepon();
  858.           
  859.           }
  860.          }
  861.          if((tempwarn!=(0x4e-0x30)*100)&&(tempwarn1==(0X4e-0x30)*100))
  862.      {
  863.            if(tempwarn>temper)
  864.           beepon();
  865.          }
  866.   if((tempwarn!=(0X4e-0x30)*100)&&(tempwarn1!=(0X4e-0x30)*100))
  867. {
  868.   if((tempwarn>temper)||(tempwarn1<temper))
  869.    {
  870.     beepon();               

  871.    }
  872.   }
  873. }
  874. }
  875. void zhuanhuan()                                   //转换模块,将时间变量转换为1602的16位显示数值
  876. {
  877.   
  878.    nian1=(y/1000)+0x30;
  879.    nian2=(y%1000/100)+0x30;
  880.    nian3=(y%1000%100/10)+0x30;
  881.    nian4=(y%1000%100%10)+0x30;
  882.    yue1=(p/10)+0x30;
  883.    yue2=(p%10)+0x30;
  884.    tian1=(o/10)+0x30;
  885.    tian2=(o%10)+0x30;
  886.    shi1=(d/10)+0x30;
  887.    shi2        =(d%10)+0x30;
  888.    fen1=(e/10)+0x30;
  889.    fen2=(e%10)+0x30;
  890.    miao1=(k/10)+0x30;
  891.    miao2=(k%10)+0x30;
  892.    tem1=(temper/100)+0x30;
  893.    tem2=(temper%100/10)+0x30;
  894.    tem3=(temper%100%10)+0x30;
  895. }
  896. void tiaojie()                                         //光标调节时间模块
  897. {
  898.   static u8 flag=0;          
  899.   if(k1==0)                                           //检测到K1按下一段时间后,开始调节光标
  900.   {         
  901.    delay(30000);
  902.    if(k1==0)
  903.     {
  904.     beepon();                                                 //因为会关闭中断并且停秒,所以给软件补偿buchang值清0
  905.           buchang=0;  
  906.           while(1)
  907.          {
  908.        ET0=0;
  909.            pdtian1();                                       //此时中断已关闭,开始循环判断
  910.            pdxingqi1();                                       //判断天数与星期,比如在将时间调到3月31号后再调到2月
  911.            zhuanhuan();                                    
  912.            if(o>tianmax)
  913.            o=tianmax;
  914.            write_week();                                     //天数就会自动调节到28日,确保不会超出范围,并自动调出星期
  915.            write_tian();
  916.            if(k4==0)                                                           //如果按下K4,就停止时间光标调节并跳出循环
  917.            {
  918.             beepon(); break;
  919.    }
  920.            if(flag==0)                                //flag调节位置判断位
  921.            {
  922.                   write_miao();
  923.                   delay(5000);
  924.                   write_com(0x87+0x40);
  925.           write_data(0xff);
  926.                   delay(5000);
  927.                  if(k2==0)
  928.                  {                                    //此时调秒
  929.           beepon();
  930.                   if(k<59)  k+=1;
  931.                   else  k=0;
  932.                  }
  933.                  if(k3==0)
  934.                  {
  935.           beepon();
  936.                   if(k>0) k-=1;
  937.                   else k=59;
  938.                  }       
  939.                   if(k1==0)
  940.                  {
  941.           beepon();
  942.                   flag+=1;        }
  943.                   write_miao();
  944.            }
  945.            if(flag==1)                                      //此时调分
  946.            {  
  947.               write_fen();
  948.                   delay(5000);
  949.                   write_com(0x84+0x40);
  950.                   write_data(0xff);
  951.                   delay(5000);
  952.                  if(k2==0)
  953.                 {
  954.          beepon();
  955.                  if(e<59) e+=1;
  956.                  else e=0;         }
  957.                  if(k3==0)
  958.                  {
  959.           beepon();
  960.                   if(e>0)  e-=1;
  961.                   else    e=59;
  962.                  }
  963.                   if(k1==0)
  964.                  {
  965.           beepon();
  966.                   flag+=1;         }
  967.                   write_fen();
  968.            }
  969.       if(flag==2)                                          //此时调时
  970.            {  
  971.                      write_shi();
  972.                   delay(5000);
  973.                   write_com(0x81+0x40);
  974.                   write_data(0xff);
  975.                   delay(5000);
  976.                 if(k2==0)
  977.                  {
  978.           beepon();
  979.                   if(d<23) d+=1;
  980.                   else  d=0;       
  981.      }
  982.                 if(k3==0)
  983.                   {
  984.            beepon();
  985.                    if(d>0) d-=1;
  986.                    else   d=23;
  987.                   }
  988.                 if(k1==0)
  989.                   {
  990.           beepon();
  991.                   flag+=1;}
  992.                   write_shi();
  993.             }
  994.        if(flag==3)                                      //此时调天   天、月、年会影响星期,所以在这里加入判断星期模块
  995.            {
  996.               write_tian();
  997.                   delay(5000);
  998.                   write_com(0x89);
  999.                   write_data(0xff);
  1000.                   delay(5000);
  1001.                   if(k2==0)
  1002.                  {
  1003.           beepon();
  1004.                   if(o<tianmax)
  1005.           o+=1;
  1006.                   else
  1007.           o=1;       
  1008.      }
  1009.                   if(k3==0)
  1010.                  {
  1011.           beepon();
  1012.                   pdtian1();
  1013.                   if(o>1)
  1014.           o-=1;
  1015.                   else       
  1016.           o=tianmax;
  1017.                  }
  1018.                   if(k1==0)
  1019.                   {
  1020.            beepon();
  1021.                    flag+=1;
  1022.       }
  1023.          write_tian();
  1024.            }
  1025.            if(flag==4)
  1026.            {   
  1027.                write_yue();                                                //此时调月
  1028.                    delay(5000);
  1029.                    write_com(0x86);
  1030.                    write_data(0xff);                                //循环闪烁光标
  1031.                    delay(5000);
  1032.                  if(k2==0)
  1033.                  {
  1034.            beepon();
  1035.                    if(p<12)
  1036.            p+=1;
  1037.                    else
  1038.            p=1;         
  1039.                  }
  1040.                  if(k3==0)
  1041.                    {
  1042.             beepon();
  1043.                     if(p>1)
  1044.             p-=1;
  1045.                     else
  1046.             p=12;
  1047.                         if(o>tianmax)
  1048.                o=tianmax;
  1049.                  }
  1050.                   if(k1==0)
  1051.                  {
  1052.           beepon();
  1053.                   flag+=1;
  1054.      }
  1055.       write_yue();
  1056.         }
  1057.                if(flag==5)
  1058.         {     
  1059.                write_nian();                               //此时调年
  1060.                    delay(5000);
  1061.                    write_com(0x83);
  1062.                    write_data(0xff);
  1063.                    delay(5000);
  1064.                   if(k2==0)
  1065.                  {
  1066.           beepon();
  1067.                   if(y<9999)
  1068.                   y+=1;
  1069.                   else
  1070.                   y=1;
  1071.        
  1072.      }
  1073.                  if(k3==0)
  1074.                  {
  1075.           beepon();
  1076.                   if(y>0)
  1077.           y-=1;
  1078.                   else
  1079.           y=9999;
  1080.        
  1081.                  }
  1082.                   if(k1==0)
  1083.                   {
  1084.           beepon();
  1085.               flag=0;}
  1086.           write_nian();
  1087.               }
  1088.                                                            //调节完毕并且K4确认后打开中断允许,开始走时
  1089.           }
  1090.    }   
  1091. }
  1092.   ET0=1;

  1093. }
  1094. void beiguangpd()                                         //背光判断模块
  1095. {if(k1==0||k2==0||k3==0|k4==0)
  1096. {        if(bg==1)                                        //如果再背光熄灭的情况下 ,按下任何键都会打开背光并响铃
  1097.         beepon();
  1098.         beiguang=0;                                    //无论是否熄灭,按下都会清零
  1099.   }
  1100. if(beiguang==60)                      //如果检测到没有按键60S,背光自动熄灭
  1101. bg=1;
  1102. else
  1103. bg=0;
  1104. }
  1105. void main()                                   //主函数
  1106. {          bg=0;
  1107.       y=2017;p=5;o=25;
  1108.       DHT11_receive();
  1109.           temper=ReadTemperature();
  1110.       welcome();                                    //欢迎
  1111.       NZdisplay();                                   //断电后第一个调节闹钟
  1112.           init();         
  1113.           Timer0Init();                               //初始化定时器,但是没有打开ET0                             
  1114.       ET0=1;                             
  1115.           init();                                     //调节完毕后延时初始化并延时足够时间,确保不会乱码
  1116.           delay(50000);
  1117.         while(1)                                       //循环各个模块且不会冲突
  1118.         {
  1119.           zhuanhuan();                                   
  1120.           bijiao();
  1121.          tiaojie();
  1122.           naozhongfamen();
  1123.           wendufamen();
  1124.           miaobiao();
  1125.           pdtian1();
  1126.           pdxingqi1();
  1127.          Display();
  1128.         }
  1129. }
  1130. void write_week()                                //1602写并显示星期模块
  1131. {  static u8 i;       
  1132.    switch (wk)
  1133.      {
  1134.           case(1):
  1135.           for(i=0;i<5;i++)
  1136.         {
  1137.          write_com(0x8b+i);
  1138.          write_data(week1[i]);
  1139.          }
  1140.          break;
  1141.           case(2):
  1142.      for(i=0;i<5;i++)
  1143.         {
  1144.          write_com(0x8b+i);
  1145.          write_data(week2[i]);
  1146.          }
  1147.          break;
  1148.          case(3):
  1149.          for(i=0;i<5;i++)
  1150.         {
  1151.          write_com(0x8b+i);
  1152.          write_data(week3[i]);
  1153.          }
  1154.          break;
  1155.          case(4):
  1156.          for(i=0;i<5;i++)
  1157.         {
  1158.          write_com(0x8b+i);
  1159.          write_data(week4[i]);
  1160.          }
  1161.          break;
  1162.          case(5):
  1163.          for(i=0;i<5;i++)
  1164.         {
  1165.          write_com(0x8b+i);
  1166.          write_data(week5[i]);
  1167.          }
  1168.          break;
  1169.          case(6):
  1170.          for(i=0;i<5;i++)
  1171.         {
  1172.          write_com(0x8b+i);
  1173.          write_data(week6[i]);
  1174.          }
  1175.          break;
  1176.          case(0):
  1177.          for(i=0;i<5;i++)
  1178.         {
  1179.          write_com(0x8b+i);
  1180.          write_data(week7[i]);
  1181.          }
  1182. ……………………

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

所有资料51hei提供下载:
非RTC多功能万年历.zip (96.67 KB, 下载次数: 14)


回复

使用道具 举报

板凳
admin 发表于 2017-6-11 02:30 | 只看该作者
 
好资料,51黑有你更精彩!!!
回复

使用道具 举报

地板
348652560 发表于 2017-6-15 16:57 | 只看该作者
谢谢分享!收藏了!
回复

使用道具 举报

5#
fjc1979 发表于 2017-6-17 17:25 | 只看该作者
打死大四多 发表于 2017-5-29 22:14
有详尽的注释,有兴趣的同学可以焊接一个实物烧进去试试,因为不用RTC芯片也不用担心换纽扣电池,12MHZ的晶 ...


好资料,51黑有你更精彩!!!
回复

使用道具 举报

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

本版积分规则

     

QQ|手机版|小黑屋|单片机论坛

Powered by 单片机教程网

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