[应用方案] 51单片机带闹钟可调时间的电子时钟程序设计

[复制链接]
 楼主| 舒斯特尔 发表于 2015-8-9 20:31 | 显示全部楼层 |阅读模式
我佩服了这焊工。。。
基于51单片机、 ds1302时钟芯片、 ds18b20温度芯片、 以及1602液晶显示的    实时时间   和   实时温度显示 。同时可通过按键 设置 年、月、日、时、分、星期。                                                      并且可以设置闹钟  当闹钟时间到时 蜂鸣器持续发出 滴..声 同时led灯不停闪烁   且在一分钟内没有按指定停止按键 闹钟将自动停止  。。。



 楼主| 舒斯特尔 发表于 2015-8-9 20:31 | 显示全部楼层
  1. #include <reg52.h>
  2. #define uchar unsigned char
  3. #define uint unsigned int
  4. sbit spk=P1^7;
  5. sbit led=P1^5;
  6. sbit DQ=P1^0;
  7. sbit RS=P2^4;
  8. sbit RW=P2^5;
  9. sbit EN=P2^6;
  10. sbit key1=P2^0;
  11. sbit key2=P2^1;
  12. sbit key3=P2^2;
  13. sbit key4=P2^3;
  14. sbit IO=P3^6;
  15. sbit RST=P3^7;
  16. sbit SCLK=P3^5;
  17. uchar code table[]={0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39};
  18. int nian,xing,yue,ri,shi,fen,miao;
  19. uchar num,temp,c,d,time[7],a,b,aa,bb,ns,ng,ys,yg,rs,rg,ss,sg,fs,fg,ms,mg,flag;

  20. /*******************1602************************/

  21. void delay(int z)
  22. {
  23. int x,y;
  24. for(x=z;x>0;x--)
  25.   for(y=100;y>0;y--);
  26. }

  27. void write_com(uchar com)   //写命令
  28. {
  29. RS=0;
  30. P0=com;
  31. delay(5);
  32. EN=1;
  33. delay(5);
  34. EN=0;
  35. }

  36. void write_data(uchar date)      //写数据
  37. {
  38. RS=1;
  39. P0=date;
  40. delay(5);
  41. EN=1;
  42. delay(5);
  43. EN=0;
  44. }
  45. void init()          //初始化
  46. {
  47. RW=0;
  48. EN=0;
  49. write_com(0x38);    //显示模式设置
  50. write_com(0x0c);    //开显示 不显示光标 不闪
  51. write_com(0x06); //写一个字符 地址指针 光标 加一 整屏不移动
  52. write_com(0x01);    //显示清零

  53. write_com(0x80+0x04);
  54. write_data('2');     
  55. write_com(0x80+0x05);
  56. write_data('0');     
  57. write_com(0x80+0x00);
  58. write_data('c');     
  59. write_com(0x80+0x01);
  60. write_data('a');
  61. write_com(0x80+0x02);
  62. write_data('i');      
  63. write_com(0x80+0x4e);
  64. write_data(0xdf);   
  65. write_com(0x80+0x4f);
  66. write_data('C');     
  67. write_com(0x80+0x4b);
  68. write_data(0x2e);       //显示"。"
  69. }

  70. /**************DS18B20****************/

  71. void delay1(unsigned int t) //延时函数
  72. {
  73. while(t--);
  74. }

  75. void init1()  //初始化
  76. {
  77. uchar n=0;
  78. DQ=1;      //DQ复位
  79. delay1(8);  
  80. DQ=0;      //主机将DQ拉低
  81. delay1(80);     //大于480us的延时
  82. DQ=1;
  83. delay1(5);    //延时15~60us
  84. n=DQ;
  85. delay1(5);   //若n=0初始成功 n=1初始失败(可设置返回值查看n是否为1)
  86. }

  87. void write_byte(uchar dat)    //写入一个字节
  88. {
  89. uint i;
  90. for(i=0;i<8;i++)
  91. {
  92.   DQ=0;
  93.   DQ=dat&0x01;
  94.   delay1(12);
  95.   DQ=1;
  96.   dat>>=1;
  97. }
  98. delay1(4);
  99. }

  100. uchar read_byte()    //读入一个字节
  101. {
  102. uint k=0;
  103. uchar value=0;
  104. for(k=0;k<8;k++)
  105. {
  106.   DQ=0;
  107.   value>>=1;
  108.   DQ=1;
  109.   if(DQ)
  110.   value|=0x80;
  111.   delay1(4);
  112. }
  113. return value;
  114. }

  115. uchar read_temp()    //读取温度函数
  116. {
  117. uchar a=0,b=0;
  118. init1();
  119. write_byte(0xcc);
  120. write_byte(0x44);
  121. delay1(200);

  122. init1();
  123. write_byte(0xcc);
  124. write_byte(0xbe);
  125. a=read_byte();  
  126. b=read_byte();
  127. c=b;
  128. d=a;
  129. b<<=4;
  130. b+=(a&0xf0)>>4;
  131. return b;
  132. }

  133. /***********************1302**********************/

  134. void wirte_byte1(uchar date)    //写入一个字节
  135. {
  136. uchar i;
  137. for(i=8;i>0;i--)
  138. {
  139.   IO=date&0x01;
  140.   SCLK=0;
  141.   SCLK=1;
  142.   date=date>>1;
  143.    }
  144. }

  145. uchar read_byte1()       //读一个字节
  146. {
  147. uchar dat,i;
  148. for(i=8;i>0;i--)
  149. {
  150.   dat=dat>>1;
  151.   SCLK=0;
  152.   if(IO)
  153.   dat=dat|0x80;
  154.   SCLK=1;
  155. }
  156. return(dat);
  157. }

  158. void write_ds1302(uchar add,uchar date)     //将数据写入1302中
  159. {
  160. RST=0;
  161. SCLK=0;
  162. RST=1;
  163. wirte_byte1(add);
  164. wirte_byte1(date);
  165. RST=0;
  166. SCLK=1;
  167. }

  168. uchar read_ds1302(uchar add)  //读出1302中数据
  169. {
  170. uchar temp;
  171. RST=0;
  172. SCLK=0;
  173. RST=1;
  174. wirte_byte1(add);
  175. temp=read_byte1();
  176. RST=0;
  177. SCLK=0;
  178. return (temp);
  179. }

  180. uchar huan_BCD(uint z)   //将数据 转换成BCD
  181. {
  182. uint a,b;
  183.   a=z/10;
  184.   b=z%10;
  185.   a=a&0xff;
  186.   b=b&0xff;
  187.   a<<=4;
  188.   a=a|b;
  189. return (a);
  190. }

  191. void xian_shi()       //液晶显示函数
  192. {
  193. if(b==0&a==0)
  194. {
  195.   ms=time[0]/16;
  196.   mg=time[0]%16;

  197.   fs=time[1]/16;
  198.   fg=time[1]%16;
  199.   fen=fs*10+fg;

  200.   ss=time[2]/16;
  201.   sg=time[2]%16;
  202.   shi=ss*10+sg;

  203.   rs=time[3]/16;
  204.   rg=time[3]%16;
  205.   ri=rs*10+rg;

  206.   ys=time[4]/16;
  207.   yg=time[4]%16;
  208.   yue=ys*10+yg;

  209.   ns=time[6]/16;
  210.   ng=time[6]%16;
  211.   nian=ns*10+ng;

  212.   xing=time[5];
  213. }
  214. if(a==1|b==1)
  215. {
  216.   ss=shi/10;
  217.   sg=shi%10;

  218.   write_com(0x80+0x41);
  219.   write_data(0xff);

  220.   write_com(0x80+0x40);   
  221.   write_data(table[ss]);
  222.   write_com(0x80+0x41);   
  223.   write_data(table[sg]);

  224. }
  225. if(a==2|b==2)
  226.     {
  227.   fs=fen/10;
  228.   fg=fen%10;

  229.   write_com(0x80+0x44);
  230.   write_data(0xff);

  231.   write_com(0x80+0x43);   
  232.   write_data(table[fs]);
  233.   write_com(0x80+0x44);   
  234.   write_data(table[fg]);
  235. }

  236. if(a==3)
  237.     {
  238.   rs=ri/10;
  239.   rg=ri%10;

  240.   write_com(0x80+0x0d);
  241.   write_data(0xff);

  242.   write_com(0x80+0x0c);   
  243.   write_data(table[rs]);
  244.   write_com(0x80+0x0d);   
  245.   write_data(table[rg]);
  246. }
  247. if(a==4)
  248.     {
  249.   ys=yue/10;
  250.   yg=yue%10;

  251.   write_com(0x80+0x0a);
  252.   write_data(0xff);

  253.   write_com(0x80+0x09);   
  254.   write_data(table[ys]);
  255.   write_com(0x80+0x0a);   
  256.   write_data(table[yg]);
  257. }
  258. if(a==5)
  259.     {
  260.   ns=nian/10;
  261.   ng=nian%10;

  262.   write_com(0x80+0x07);
  263.   write_data(0xff);

  264.   write_com(0x80+0x06);   
  265.   write_data(table[ns]);
  266.   write_com(0x80+0x07);   
  267.   write_data(table[ng]);
  268. }
  269. if(a==6)
  270.     {
  271.   write_com(0x80+0x0f);
  272.   write_data(0xff);
  273.   write_com(0x80+0x0f);   
  274.   write_data(table[xing]);
  275. }
  276.   write_com(0x80+0x06); //在液晶第一行第七八位显示  年   
  277.   write_data(table[ns]);
  278.   write_com(0x80+0x07);   
  279.   write_data(table[ng]);

  280.   write_com(0x80+0x08);   
  281.   write_data('-');

  282.   write_com(0x80+0x09); //在液晶第一行第十十一位显示  月   
  283.   write_data(table[ys]);
  284.   write_com(0x80+0x0a);   
  285.   write_data(table[yg]);

  286.   write_com(0x80+0x0b);   
  287.   write_data('-');

  288.   write_com(0x80+0x0c); //在液晶第一行第十三 十四位显示  日   
  289.   write_data(table[rs]);
  290.   write_com(0x80+0x0d);   
  291.   write_data(table[rg]);

  292.   write_com(0x80+0x0f);   //在液晶第一行第十七位显示  星期
  293.   write_data(table[xing]);

  294.   write_com(0x80+0x40);   //在液晶第二行第二三位显示    时
  295.   write_data(table[ss]);
  296.   write_com(0x80+0x41);   
  297.   write_data(table[sg]);

  298.   write_com(0x80+0x42);   
  299.   write_data(':');

  300.   write_com(0x80+0x43);   //在液晶第二行第五六位显示  分
  301.   write_data(table[fs]);
  302.   write_com(0x80+0x44);   
  303.   write_data(table[fg]);

  304.   write_com(0x80+0x45);   
  305.   write_data(':');

  306.   write_com(0x80+0x46);   //在液晶第二行第**位显示  秒
  307.   write_data(table[ms]);
  308.   write_com(0x80+0x47);   
  309.   write_data(table[mg]);
  310. }

  311. void keyscan()    //按键设置函数  可任意设置年月日时分秒星期的数值
  312. {
  313. if(key4!=0)
  314. {
  315.   if(key1==0)   //key1按键 选择需设置的位
  316.   {
  317.    if(key1==0)
  318.    {
  319.     a++;
  320.     delay(1);
  321.    }
  322.          while(!key1)
  323.    {      
  324.     delay(1);
  325.    }      
  326.   }

  327.   if(a!=0)
  328.   {
  329.    if(key2==0)    //key2按键 可将需设置的数 调大
  330.    {
  331.     if(a==1)
  332.     {
  333.      shi++;
  334.      if(shi>=24)
  335.      {
  336.       shi=0;
  337.      }
  338.     }
  339.     if(a==2)
  340.     {
  341.      fen++;
  342.      if(fen>=60)
  343.      {
  344.       fen=0;
  345.      }
  346.     }
  347.     if(a==3)
  348.     {
  349.      ri++;
  350.      if(ri>=32)
  351.      {
  352.       ri=1;
  353.      }
  354.     }
  355.     if(a==4)
  356.     {
  357.      yue++;
  358.      if(yue>=12)
  359.      {
  360.       yue=1;
  361.      }
  362.     }
  363.     if(a==5)
  364.     {
  365.      nian++;
  366.      if(nian>=99)
  367.      {
  368.       nian=0;
  369.      }
  370.     }
  371.     if(a==6)
  372.     {
  373.      xing++;
  374.      if(xing>=8)
  375.      {
  376.       xing=1;
  377.      }
  378.     }
  379.    }
  380.    if(key3==0)    //key3按键 可将需设置的数 调小
  381.    {
  382.    
  383.     if(a==1)
  384.     {
  385.      shi--;
  386.      if(shi<0)
  387.      {
  388.       shi=23;
  389.      }
  390.     }
  391.     if(a==2)
  392.     {
  393.      fen--;
  394.      if(fen<0)
  395.      {
  396.       fen=59;
  397.      }
  398.     }
  399.     if(a==3)
  400.     {
  401.      ri--;
  402.      if(ri<1)
  403.      {
  404.       ri=31;
  405.      }
  406.     }
  407.     if(a==4)
  408.     {
  409.      yue--;
  410.      if(yue<1)
  411.      {
  412.       yue=12;
  413.      }
  414.     }
  415.     if(a==5)
  416.     {
  417.      nian--;
  418.      if(nian<0)
  419.      {
  420.       nian=99;
  421.      }
  422.     }
  423.     if(a==6)
  424.     {
  425.      xing--;
  426.      if(xing<1)
  427.      {
  428.       xing=7;
  429.      }
  430.     }
  431.    }
  432.    if(a==7)       //当按下key1 7次后  将个数据写入1302
  433.    {
  434.     a=0;
  435.     write_ds1302(0x8e,0x00);   //WP=0 写操作
  436.     write_ds1302(0x80,0x00);   //0x80是写秒数据
  437.     write_ds1302(0x82,huan_BCD(fen)); //0x82是写分数据
  438.     write_ds1302(0x84,huan_BCD(shi)); //0x84是写时数据
  439.     write_ds1302(0x86,huan_BCD(ri)); //0x84是写日数据
  440.     write_ds1302(0x88,huan_BCD(yue)); //0x84是写月数据
  441.     write_ds1302(0x8a,huan_BCD(xing)); //0x84是写星期数据
  442.     write_ds1302(0x8c,huan_BCD(nian)); //0x84是写年数据
  443.     write_ds1302(0x8e,0x80);   //WP=1 写保护   
  444.    }
  445.   }
  446. }
  447. }

  448. void naozhong()      //通过按键设置闹钟  时 分
  449. {
  450. if(key1!=0)
  451. {
  452.   if(key4==0)
  453.   {
  454.    if(key4==0)
  455.    {
  456.     b++;
  457.     delay(1);
  458.    }
  459.          while(!key4)
  460.    {      
  461.     delay(1);
  462.    }
  463.   }
  464.   if(b!=0)
  465.   {
  466.    if(key2==0)    //key2按键 可将需设置的数 调大
  467.    {
  468.     if(b==1)
  469.     {
  470.      shi++;
  471.      if(shi>=24)
  472.      {
  473.       shi=0;
  474.      }
  475.     }
  476.     if(b==2)
  477.     {
  478.      fen++;
  479.      if(fen>=60)
  480.      {
  481.       fen=0;
  482.      }
  483.     }
  484.    }
  485.    if(key3==0)    //key3按键 可将需设置的数 调小
  486.    {
  487.     if(b==1)
  488.     {
  489.      shi--;
  490.      if(shi<0)
  491.      {
  492.       shi=23;
  493.      }
  494.     }
  495.     if(b==2)
  496.     {
  497.      fen--;
  498.      if(fen<0)
  499.      {
  500.       fen=59;
  501.      }
  502.     }
  503.    }
  504.    aa=huan_BCD(shi);   //将设置的时钟 赋值给aa
  505.    bb=huan_BCD(fen); //将设置的分钟 赋值给bb
  506.    if(b==3)       //当按下key4 3次后 闹钟设置完成
  507.    {
  508.     b=0;
  509.    }
  510.   }
  511. }
  512. }

  513. void main()
  514. {
  515. uint i,temp;
  516. init();
  517. TMOD=0x10;
  518. EA=1;
  519. TH1=(65536-51200)/256;
  520. TL1=(65536-51200)%256;
  521. ET1=1;
  522. while(1)
  523. {
  524.   temp=0x81;          //读的初始地址                  
  525.         for(i=0;i<7;i++)             //分别把秒分时日月年星期数据读出分7次读好一次地址加2" temp+=2;"
  526.       {
  527.          time[i]=read_ds1302(temp);
  528.       temp+=2;
  529.         }
  530.   if(bb==time[1]&aa==time[2]&!time[0])  //如果读出来的时钟 分钟与1302读出来的值相等且读出来的秒钟为零时 进入中断
  531.   {
  532.    TR1=1;
  533.    flag=1;   //标志位设置为1
  534.   }
  535.   if(key3==0)   //进入闹钟后 可由key3按下 停止中断 标志位置零 允许调时闹钟设置按键动作 停止闹铃
  536.   {
  537.    led=1;
  538.    spk=1;
  539.    flag=0;
  540.    TR1=0;
  541.   }
  542.         if(flag!=1)   //当进入闹钟中断后 调时与设置闹钟的按键  无效
  543.      {
  544.          naozhong();
  545.    keyscan();
  546.   }
  547.   xian_shi();
  548.   temp=read_temp();
  549.   write_com(0x80+0x49);   
  550.   write_data(table[temp/10]);    //在液晶第二行第十位显示温度的十位
  551.   write_com(0x80+0x4a);  
  552.   write_data(table[temp%10]);    //在液晶第二行第十一位显示温度的个位
  553.   write_com(0x80+0x4c);   
  554.   write_data(table[(d&0x0f)*625/1000]);   //在液晶第二行第十三位显示温度的小数点后一位
  555.   write_com(0x80+0x4d);   
  556.   write_data(table[(d&0x0f)*625/100%10]);   //在液晶第二行第十四位显示温度的小数点后二位
  557. }
  558. }


  559. void timer1() interrupt 3     //定时器
  560. {
  561. uint t;
  562. TH1=(65536-50000)/256;
  563. TL1=(65536-50000)%256;
  564. t++;
  565. spk=0;      //蜂鸣器  发出 滴答 声
  566. led=!led;      //发光二极管  不停闪烁
  567. delay1(10);
  568. if(t==1120)    //约1分钟后 闹钟自动停止 标志位
  569. {
  570.   led=1;
  571.   spk=1;
  572.   t=0;
  573.   TR1=0;
  574.   flag=0;
  575. }

  576. }
您需要登录后才可以回帖 登录 | 注册

本版积分规则

25

主题

277

帖子

1

粉丝
快速回复 在线客服 返回列表 返回顶部