標題: 單片機DS3231時鐘+溫度顯示源碼原理圖與實物制作 [打印本頁]

作者: 0o000000    時間: 2017-12-18 18:53
標題: 單片機DS3231時鐘+溫度顯示源碼原理圖與實物制作
采用stc15單片機做的主控芯片,僅供參考
制作出來的ds3132時鐘實物圖:



電路原理圖:




pcb文件:工程文件可到本帖附件中下載


51單片機源程序如下:
  1. //#include <reg52.h>
  2. #include "stc15f104w.h"
  3. #include "I2C.h"        
  4. #include "Led_can.h"
  5.          
  6. typedef unsigned int u16;  //16位無符號整型數(shù)
  7. typedef unsigned char u8;  //8位無符號整型數(shù)

  8. #define E2PROM_WriteAddress 0xAE    //器件寫地址
  9. #define DS3231_WriteAddress 0xD0    //器件寫地址
  10. #define DS3231_ReadAddress  0xD1    //器件讀地址
  11. #define DS3231_SECOND       0x00    //秒
  12. #define DS3231_MINUTE       0x01    //分
  13. #define DS3231_HOUR         0x02    //時
  14. #define DS3231_WEEK         0x03    //星期                           
  15. #define DS3231_DAY          0x04    //日
  16. #define DS3231_MONTH        0x05    //月
  17. #define DS3231_YEAR         0x06    //年
  18. //鬧鈴1            
  19. //#define DS3231_SALARM1ECOND 0x07    //秒
  20. //#define DS3231_ALARM1MINUTE 0x08    //分
  21. //#define DS3231_ALARM1HOUR   0x09    //時
  22. //#define DS3231_ALARM1WEEK   0x0A    //星期/日
  23. //鬧鈴2
  24. //#define DS3231_ALARM2MINUTE 0x0b    //分
  25. //#define DS3231_ALARM2HOUR   0x0c    //時
  26. //#define DS3231_ALARM2WEEK   0x0d    //星期/日
  27. #define DS3231_CONTROL      0x0e    //控制寄存器
  28. #define DS3231_STATUS       0x0f    //狀態(tài)寄存器
  29. #define BSY                 2       //忙
  30. #define OSF                 7       //振蕩器停止標志
  31. #define DS3231_XTAL         0x10    //晶體老化寄存器
  32. #define DS3231_TEMPERATUREH 0x11    //溫度寄存器高字節(jié)(8位)
  33. #define DS3231_TEMPERATUREL 0x12    //溫度寄存器低字節(jié)(高2位)



  34. sbit BP = P1^5;         //秒數(shù)碼管驅(qū)動
  35. sbit KEY1 =        P1^5;  //按鍵輸入引腳

  36. u8  Time[18];          //時鐘數(shù)值緩沖區(qū)
  37. bit BiaoJi=0;          //讀實時時鐘標記
  38. bit BianJi_c=0;          //長按鍵標記
  39. bit BianJi_d=0;          //短按鍵標記
  40. u8 BianJi=0;          //編輯模式標記
  41. u8 L_u[4]={2,3,4,5};//數(shù)碼管顯示第幾時鐘緩沖區(qū)
  42. u8 ling=0;              //數(shù)碼管首位是否顯示零標記
  43. bit WenDu = 0;          //溫度轉(zhuǎn)換標記

  44. void ConfigTimer0(u8 ms);               //配置并啟動T0,ms-T0定時時間
  45. void write_byte(u8 addr, u8 write_data);//DS3231_寫一個字節(jié)數(shù)據(jù)到時鐘芯片        
  46. u8 read_byte(u8 random_addr);           //DS3231_讀一個字節(jié)數(shù)據(jù)到時鐘芯片
  47. void write_byte_E2( u8 write_data);     //E2PROM-寫一個字節(jié)數(shù)據(jù)到時鐘芯片        
  48. u8 read_byte_E2();                      //E2PROM-讀一個字節(jié)數(shù)據(jù)到時鐘芯片
  49. u8 BCD2HEX(u8 val);                     //BCD轉(zhuǎn)換為Byte
  50. u8 HEX2BCD(u8 val);                     //B碼轉(zhuǎn)換為BCD碼
  51. void anjian();                                                     //按鈕掃描         需在定時中斷中調(diào)用
  52. void Anjian_d(u8 addr, u8 map);         //短按鍵處理—子程序

  53. void main()
  54. {
  55.      u8 map;
  56.          u16 wend;
  57.          
  58.          EA = 1;      //開總中斷
  59.          Led_cu();         //數(shù)碼管初始化
  60.          ConfigTimer0(5);   //配置T0定時

  61.          ling=read_byte_E2();         //E2PROM讀出數(shù)據(jù)—數(shù)碼管首位是否顯示零標記        
  62.      //初始化實時時鐘,小時采用24小時制
  63.          write_byte(DS3231_CONTROL, 0x1C);              //控制寄存器  DS3231_CONTROL
  64.      write_byte(DS3231_STATUS, 0x00);               //狀態(tài)寄存器  DS3231_STATUS
  65.          //write_byte(DS3231_SECOND,HEX2BCD(30)); //修改秒
  66.      //write_byte(DS3231_MINUTE,HEX2BCD(30)); //修改分
  67.          //write_byte(DS3231_HOUR,HEX2BCD(16));   //修改時
  68.          //write_byte(DS3231_DAY,HEX2BCD(1));     //修改日
  69.          //write_byte(DS3231_MONTH,HEX2BCD(12));  //修改月
  70.          //write_byte(DS3231_YEAR,HEX2BCD(17));   //修改年
  71.                                        
  72.      while(1)
  73.          {         //讀取時鐘芯片并寫進數(shù)碼管顯示緩沖區(qū)======================
  74.                   if(BiaoJi == 1)
  75.                  {      BiaoJi = 0;                                
  76.                                        
  77.                                 map=read_byte(DS3231_SECOND);     //讀秒        
  78.                             map=BCD2HEX(map);
  79.                                 Time[0]=map%10;
  80.                                 Time[1]=map/10%10;
  81.                             map=read_byte(DS3231_MINUTE);     //讀分        
  82.                             map=BCD2HEX(map);
  83.                                 Time[2]=map%10;
  84.                                 Time[3]=map/10%10;
  85.                                 map=read_byte(DS3231_HOUR)&0x3f;  //讀小時 24小時制               
  86.                             map=BCD2HEX(map);
  87.                                 Time[4]=map%10 ;
  88.                                 Time[5]=map/10%10 ;
  89.                         
  90.                                 //map=read_byte(DS3231_WEEK );      //讀星期           
  91.                                 //Time[6]=map
  92.                                 //map=read_byte(DS3231_DAY);        //讀日
  93.                             //map=BCD2HEX(map);
  94.                                 //Time[8]=map%10
  95.                                 //Time[9]=map/10%10
  96.                             //map=read_byte(DS3231_MONTH);      //讀月
  97.                             //map=BCD2HEX(map);
  98.                                 //Time[10]=map%10
  99.                                 //Time[11]=map/10%10
  100.                                 //map=read_byte(DS3231_YEAR);       //讀年
  101.                             //map=BCD2HEX(map);
  102.                                 //Time[12]=map%10
  103.                                 //Time[13]=map/10%10

  104.                                 if((ling==0) && (Time[L_u[3]]==0))         //判斷數(shù)碼管首位零是否顯示
  105.                                 Led_buff[3]        = 0xff;
  106.                                 else
  107.                                 Led_buff[3]        = Led_Char[ Time[L_u[3]]];  
  108.                                 Led_buff[2]        = Led_Char[ Time[L_u[2]]];
  109.                                 Led_buff[1]        = Led_Char[ Time[L_u[1]]];
  110.                                 Led_buff[0]        = Led_Char[ Time[L_u[0]]];
  111.                                        
  112.                  }
  113.                  //讀取溫度并寫進數(shù)碼管顯示緩沖區(qū)======================
  114.                  if(WenDu == 1)
  115.                  {            WenDu = 0;
  116.                                                 //零上溫度轉(zhuǎn)換
  117.                                 map=read_byte(DS3231_TEMPERATUREH);    //溫度高字節(jié)—整數(shù)位
  118.                                    if((map&0x80)==0)                //判斷首字節(jié)為1即為        零下溫度
  119.                                    {   Led_buff[0] = 0xa7;
  120.                                     Time[16]=map%10        ;
  121.                                     Time[17]=map/10%10;        
  122.                                         map=read_byte(DS3231_TEMPERATUREL);    //溫度低字節(jié)—小數(shù)位
  123.                                     map=(map>>6)*25;  //由于分辨率為0.25        所以擴大25倍便于顯示
  124.                                         Time[14]=map%10;
  125.                                         Time[15]=map/10%10;
  126.                                 }
  127.                                    else         //零下溫度轉(zhuǎn)換—零下是以2的補碼形式存儲的
  128.                                 {        Led_buff[0] = 0xa6;
  129.                                         wend=map;                 //單字節(jié)轉(zhuǎn)換雙字節(jié)
  130.                                         wend=wend<<2;         //移出兩位放溫度的低位
  131.                                         map=read_byte(DS3231_TEMPERATUREL);    //讀溫度低字節(jié)
  132.                                         map=map>>6;                 //由于2位放在頭兩位上,移到低位
  133.                                         wend=wend+map;         //組成10位的2進制的溫度編碼
  134.                                         wend=(~wend)+1;         //負數(shù)是以2的補碼形式存儲的,轉(zhuǎn)為原碼
  135.                                         wend=wend&0x03ff;//10位的2進制的溫度編碼,截去無用位
  136.                                         map= wend&0x0003;//分離低兩位,作為小數(shù)位
  137.                                         map= map*25;          //由于分辨率為0.25        所以擴大25倍便于顯示
  138.                                         Time[14]=map%10;
  139.                                         Time[15]=map/10%10;
  140.                                         wend=wend>>2;         //整數(shù)位處理
  141.                                         Time[16]=wend%10;
  142.                                     Time[17]=wend/10%10;        
  143.                                 }        
  144.         
  145.                                 if((ling==0) && (Time[L_u[17]]==0))         //判斷數(shù)碼管首位零是否顯示
  146.                                 Led_buff[3]        = 0xff;
  147.                                 else
  148.                                 Led_buff[3]        = Led_Char[ Time[17]]; //整數(shù)位顯示兩位
  149.                                 Led_buff[2]        = Led_Char[ Time[16]];
  150.                                 Led_buff[1]        = Led_Char[ Time[15]]; //小數(shù)位顯示一位
  151.                                 
  152.                                 write_byte(DS3231_CONTROL, 0x3C);  //溫度強制轉(zhuǎn)換—準備下次讀取
  153.                  }

  154.                  //長按鍵處理
  155.          if(BianJi_c==1)
  156.                  {           BianJi_c=0;
  157.                                 KEY1=1;
  158.                                  BianJi++;
  159.                                 if(BianJi==1)         //進入溫度顯示
  160.                             {  WenDu = 1; }
  161.                                 if(BianJi==2)        //進入首位數(shù)碼管修改位
  162.                             {        Led_buff[3]        = Led_Char[ Time[L_u[3]]];
  163.                                         Led_buff[2]        = 0xbf;
  164.                                         Led_buff[1]        = 0xbf;
  165.                                         Led_buff[0]        = 0xbf;
  166.                             }
  167.                                 if(BianJi==3)  //進入第二位數(shù)碼管修改位
  168.                             {        Led_buff[3]        = 0xbf;
  169.                                         Led_buff[2]        = Led_Char[ Time[L_u[2]]];
  170.                                         if(Time[L_u[3]]==2 && Time[L_u[2]]>3) //若為24小時制 首位為2則壓縮次位的修改范圍
  171.                                         {   Time[L_u[2]]=3;
  172.                                                 Anjian_d(L_u[2],3);
  173.                                         }        
  174.                             }
  175.                             if(BianJi==4)  //進入第三位數(shù)碼管修改位
  176.                             {        Led_buff[2]        = 0xbf;
  177.                                         Led_buff[1]        = Led_Char[ Time[L_u[1]]];               
  178.                             }
  179.                                 if(BianJi==5)  //進入第四位數(shù)碼管修改位
  180.                             {        Led_buff[1]        = 0xbf;
  181.                                     Led_buff[0]        = Led_Char[ Time[L_u[0]]];                        
  182.                             }
  183.                                 if(BianJi==6)  //進入數(shù)碼管首位零是否顯示,修改選項         顯示零:ON         不顯示零:OFF
  184.                                  {    if(ling==0)
  185.                                           {        Led_buff[3]        = 0xff;  
  186.                                                 Led_buff[2]        = 0xC0;
  187.                                                 Led_buff[1]        = 0x8E;
  188.                                                 Led_buff[0]        = 0x8E;
  189.                                           }
  190.                                           else
  191.                                           {        Led_buff[3]        = 0xff;  
  192.                                                 Led_buff[2]        = 0xff;
  193.                                                 Led_buff[1]        = 0xC0;
  194.                                                 Led_buff[0]        = 0xc8;
  195.                                           }
  196.                                 }
  197.                                 if(BianJi==7)  //退出編輯模式
  198.                             { BianJi=0; }
  199.                                    
  200.                  }
  201.                  //短按鍵處理        
  202.          if(BianJi_d==1)
  203.                  {          BianJi_d=0;
  204.                                 if(BianJi==1) //退出編輯模式
  205.                             {        BianJi=0;  }
  206.                                 if(BianJi==2) //首位數(shù)碼管修改位
  207.                             {  Anjian_d(L_u[3],2);}
  208.                                 if(BianJi==3) //第二位數(shù)碼管修改位
  209.                             {        if(Time[L_u[3]]==2 )
  210.                                         { Anjian_d(L_u[2],3); }
  211.                                     else
  212.                                     { Anjian_d(L_u[2],9); }
  213.                                                 
  214.                             }
  215.                             if(BianJi==4) //第三位數(shù)碼管修改位
  216.                             {  Anjian_d(L_u[1],5); }
  217.                                 if(BianJi==5) //第四位數(shù)碼管修改位
  218.                             {  Anjian_d(L_u[0],9); }
  219.                                 if(BianJi==6) //進入數(shù)碼管首位零是否顯示,修改選項         顯示零:ON         不顯示零:OFF
  220.                             {
  221.                                           if(ling==0)
  222.                                           {        ling = 1;
  223.                                             Led_buff[3]        = 0xff;  
  224.                                                 Led_buff[2]        = 0xff;
  225.                                                 Led_buff[1]        = 0xC0;
  226.                                                 Led_buff[0]        = 0xc8;
  227.                                                 write_byte_E2(ling);         
  228.                                           }
  229.                                           else
  230.                                           {        ling = 0;
  231.                                             Led_buff[3]        = 0xff;  
  232.                                                 Led_buff[2]        = 0xC0;
  233.                                                 Led_buff[1]        = 0x8E ;
  234.                                                 Led_buff[0]        = 0x8E;
  235.                                                 write_byte_E2(ling);        
  236.                                   }
  237.                         }

  238.                            
  239.                  }                 

  240.          }

  241. }

  242. //短按鍵處理
  243. void Anjian_d(u8 addr, u8 map)
  244. {   
  245.          u8 i;

  246.      Time[addr]++; //時間變量
  247.          if(Time[addr]>map)         //時間變量最大值
  248.          Time[addr]=0;                 
  249.          if((addr%2)==0)  //計算傳入值時十位或個位  0:各位  1:十位
  250.          i = Time[addr+1]*10+Time[addr]; //十位個位組成數(shù)值待寫入DS3231
  251.          else
  252.          i = Time[addr]*10+Time[addr-1]; //十位個位組成數(shù)值待寫入DS3231
  253.          Led_buff[5-BianJi] = Led_Char[ Time[addr]]; //修改的值顯示到數(shù)碼管上
  254.          write_byte(addr/2,HEX2BCD(i)); //寫入DS3231
  255.          
  256. }

  257. /* 配置并啟動T0,ms-T0定時時間 */
  258. void ConfigTimer0(u8 ms)
  259. {
  260.     unsigned long tmp;  //臨時變量
  261.    
  262.     tmp = 12000000 / 12;      //定時器計數(shù)頻率
  263.     tmp = (tmp * ms) / 1000;  //計算所需的計數(shù)值
  264.     tmp = 65536 - tmp;        //計算定時器重載值
  265.     TMOD &= 0xF0;   //清零T0的控制位
  266.     TH0 = (u8)(tmp>>8);  //定時器重載值拆分為高低字節(jié)
  267.     TL0 = (u8)tmp;
  268.     ET0 = 1;        //使能T0中斷
  269.     TR0 = 1;        //啟動T0
  270. }
  271. //中斷定義為5毫秒
  272. void InterruptTimer0() interrupt 1
  273. {        
  274.         static        u8 Di;
  275.          //非編輯模式進入
  276.          if(BianJi==0)
  277.          {
  278.              Di++;
  279.                  if(Di==100)
  280.                  {BP=1;}          //秒顯示賦值 0.5秒
  281.                  if(Di==200)
  282.                  {   
  283.                      Di=0;
  284.                      BiaoJi=1; //一秒一次讀DS3231時間,并寫入數(shù)碼管緩沖區(qū)的標記
  285.                          BP=0;           //秒顯示賦值 0.5秒
  286.                  }
  287.          }
  288.          //編輯模式(1)進入
  289.          if(BianJi==1)
  290.          {        Di++;
  291.                 if(Di==200)
  292.                 { Di=0; WenDu = 1;}        //一秒一次讀DS3231溫度,并寫入數(shù)碼管緩沖區(qū)的標記
  293.          }
  294.          
  295.      Led_can();         //數(shù)碼管刷新
  296.          anjian();         //按鍵掃描
  297.          WDT_CONTR=0x37;           //看門狗刷新  8.4S

  298. }
  299. //E2PROM-寫一個字節(jié)數(shù)據(jù)到時鐘芯片
  300. void write_byte_E2( u8 write_data)        
  301. {         

  302.      I2CStart();      //產(chǎn)生總線起始信號
  303.      I2CWrite(E2PROM_WriteAddress);  //<<<<I2C總線寫操作  E2PROM-器件碼
  304.      I2CWrite(0);     //                                   E2PROM-存儲空間高八位地址
  305.          I2CWrite(1);     //                                   E2PROM-存儲空間低八位地址
  306.      I2CWrite(write_data);  //             寫數(shù)據(jù)         
  307.      I2CStop();       //產(chǎn)生總線停止信號   
  308.    
  309. }

  310. //E2PROM-讀一個字節(jié)數(shù)據(jù)到時鐘芯片
  311. u8 read_byte_E2()
  312. {
  313.          char temp;

  314.      I2CStart();      //產(chǎn)生總線起始信號
  315.          I2CWrite(E2PROM_WriteAddress);  //<<<<I2C總線寫操作 E2PROM-器件碼
  316.      I2CWrite(0);     //                       E2PROM-存儲空間高八位地址
  317.          I2CWrite(1);     //                      E2PROM-存儲空間低八位地址
  318.          I2CStart();      //產(chǎn)生總線起始信號
  319.          I2CWrite(E2PROM_WriteAddress|1);     //從寫                E2PROM-器件碼
  320.          temp = I2CReadNAK();  //             讀數(shù)據(jù)-發(fā)送非應答信號,不讀了
  321.      I2CStop();       //產(chǎn)生總線停止信號
  322.      return(temp);
  323. }

  324. //DS3231_寫一個字節(jié)數(shù)據(jù)到時鐘芯片
  325. void write_byte(u8 addr, u8 write_data)        
  326. {         

  327.      I2CStart();  //產(chǎn)生總線起始信號
  328.      I2CWrite(DS3231_WriteAddress);  //<<<<I2C總線寫操作
  329.      I2CWrite(addr);  //<<<<I2C總線寫操作
  330.      I2CWrite(write_data);  //<<<<I2C總線寫操作         
  331.      I2CStop();   //產(chǎn)生總線停止信號   
  332.    
  333. }

  334. //DS3231_讀一個字節(jié)數(shù)據(jù)到時鐘芯片
  335. u8 read_byte(u8 random_addr)
  336. {
  337.          char temp;

  338.      I2CStart();  //產(chǎn)生總線起始信號
  339.          I2CWrite(DS3231_WriteAddress);  //<<<<I2C總線寫操作 器件碼
  340.      I2CWrite(random_addr);  //<<<<存儲空間地址
  341.          I2CStart();  //產(chǎn)生總線起始信號
  342. ……………………

  343. …………限于本文篇幅 余下代碼請從51黑下載附件…………
復制代碼


所有資料51hei提供下載:
實時時鐘.rar (145.56 KB, 下載次數(shù): 369)



作者: 單片機設計時鐘    時間: 2017-12-18 23:21
樓主方便嗎?加我QQ1094883144,想問問 問題
作者: gxlin    時間: 2018-1-3 14:26
樓主這個程序電路都有問題,能不能實物點亮。
作者: cyllife    時間: 2018-3-4 13:12
謝謝分享
作者: 其實我們都一樣    時間: 2018-3-5 10:28
很棒。!
作者: cqhejian    時間: 2018-4-4 21:27
不錯的資料,學習一下
作者: A17094430    時間: 2018-4-26 21:13
仿制了一個不成功,秒點能閃爍,時間顯示68:08,而且不會變化,會是哪里出了問題
作者: 1031041272    時間: 2018-5-15 19:56
66666666
作者: yxdz1358    時間: 2018-5-21 12:36
剛剛下載了,程序很完整,還沒有試呢,謝謝樓主!
作者: yileiliyang    時間: 2018-5-26 16:49
下一個試一試感謝樓主
作者: wanglx    時間: 2018-8-9 13:17
謝謝樓主
作者: sunke928    時間: 2018-8-10 06:49
學習貼,收藏了,謝謝分享
作者: 1113634577    時間: 2018-8-19 16:54
數(shù)碼管的顯示就是功耗的問題
作者: tb0412    時間: 2018-9-17 15:59
好貼,學習了。
作者: 1182581777    時間: 2018-10-7 19:11
謝謝分享!!哈哈
作者: zhaozonghui    時間: 2018-10-10 18:00
這焊接技術(shù),膜拜中
作者: zgmzgm    時間: 2018-11-11 14:56
非常好的例程,照著做就可以了,謝謝
作者: 蒼穹鯤鵬    時間: 2018-12-6 13:42
看著不錯,學習一下
作者: 陳建建    時間: 2019-1-1 16:49
這個電路有做成功的嗎??
作者: 隨風飄零翼    時間: 2019-6-4 01:42
感謝分享




歡迎光臨 (http://www.torrancerestoration.com/bbs/) Powered by Discuz! X3.1