找回密码
 立即注册

QQ登录

只需一步,快速开始

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

单片机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位无符号整型数
  7. typedef unsigned char u8;  //8位无符号整型数

  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    //状态寄存器
  29. #define BSY                 2       //忙
  30. #define OSF                 7       //振荡器停止标志
  31. #define DS3231_XTAL         0x10    //晶体老化寄存器
  32. #define DS3231_TEMPERATUREH 0x11    //温度寄存器高字节(8位)
  33. #define DS3231_TEMPERATUREL 0x12    //温度寄存器低字节(高2位)



  34. sbit BP = P1^5;         //秒数码管驱动
  35. sbit KEY1 =        P1^5;  //按键输入引脚

  36. u8  Time[18];          //时钟数值缓冲区
  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};//数码管显示第几时钟缓冲区
  42. u8 ling=0;              //数码管首位是否显示零标记
  43. bit WenDu = 0;          //温度转换标记

  44. void ConfigTimer0(u8 ms);               //配置并启动T0,ms-T0定时时间
  45. void write_byte(u8 addr, u8 write_data);//DS3231_写一个字节数据到时钟芯片        
  46. u8 read_byte(u8 random_addr);           //DS3231_读一个字节数据到时钟芯片
  47. void write_byte_E2( u8 write_data);     //E2PROM-写一个字节数据到时钟芯片        
  48. u8 read_byte_E2();                      //E2PROM-读一个字节数据到时钟芯片
  49. u8 BCD2HEX(u8 val);                     //BCD转换为Byte
  50. u8 HEX2BCD(u8 val);                     //B码转换为BCD码
  51. void anjian();                                                     //按钮扫描         需在定时中断中调用
  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();         //数码管初始化
  60.          ConfigTimer0(5);   //配置T0定时

  61.          ling=read_byte_E2();         //E2PROM读出数据—数码管首位是否显示零标记        
  62.      //初始化实时时钟,小时采用24小时制
  63.          write_byte(DS3231_CONTROL, 0x1C);              //控制寄存器  DS3231_CONTROL
  64.      write_byte(DS3231_STATUS, 0x00);               //状态寄存器  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.          {         //读取时钟芯片并写进数码管显示缓冲区======================
  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))         //判断数码管首位零是否显示
  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.                  //读取温度并写进数码管显示缓冲区======================
  114.                  if(WenDu == 1)
  115.                  {            WenDu = 0;
  116.                                                 //零上温度转换
  117.                                 map=read_byte(DS3231_TEMPERATUREH);    //温度高字节—整数位
  118.                                    if((map&0x80)==0)                //判断首字节为1即为        零下温度
  119.                                    {   Led_buff[0] = 0xa7;
  120.                                     Time[16]=map%10        ;
  121.                                     Time[17]=map/10%10;        
  122.                                         map=read_byte(DS3231_TEMPERATUREL);    //温度低字节—小数位
  123.                                     map=(map>>6)*25;  //由于分辨率为0.25        所以扩大25倍便于显示
  124.                                         Time[14]=map%10;
  125.                                         Time[15]=map/10%10;
  126.                                 }
  127.                                    else         //零下温度转换—零下是以2的补码形式存储的
  128.                                 {        Led_buff[0] = 0xa6;
  129.                                         wend=map;                 //单字节转换双字节
  130.                                         wend=wend<<2;         //移出两位放温度的低位
  131.                                         map=read_byte(DS3231_TEMPERATUREL);    //读温度低字节
  132.                                         map=map>>6;                 //由于2位放在头两位上,移到低位
  133.                                         wend=wend+map;         //组成10位的2进制的温度编码
  134.                                         wend=(~wend)+1;         //负数是以2的补码形式存储的,转为原码
  135.                                         wend=wend&0x03ff;//10位的2进制的温度编码,截去无用位
  136.                                         map= wend&0x0003;//分离低两位,作为小数位
  137.                                         map= map*25;          //由于分辨率为0.25        所以扩大25倍便于显示
  138.                                         Time[14]=map%10;
  139.                                         Time[15]=map/10%10;
  140.                                         wend=wend>>2;         //整数位处理
  141.                                         Time[16]=wend%10;
  142.                                     Time[17]=wend/10%10;        
  143.                                 }        
  144.         
  145.                                 if((ling==0) && (Time[L_u[17]]==0))         //判断数码管首位零是否显示
  146.                                 Led_buff[3]        = 0xff;
  147.                                 else
  148.                                 Led_buff[3]        = Led_Char[ Time[17]]; //整数位显示两位
  149.                                 Led_buff[2]        = Led_Char[ Time[16]];
  150.                                 Led_buff[1]        = Led_Char[ Time[15]]; //小数位显示一位
  151.                                 
  152.                                 write_byte(DS3231_CONTROL, 0x3C);  //温度强制转换—准备下次读取
  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)        //进入首位数码管修改位
  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)  //进入第二位数码管修改位
  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)  //进入第三位数码管修改位
  176.                             {        Led_buff[2]        = 0xbf;
  177.                                         Led_buff[1]        = Led_Char[ Time[L_u[1]]];               
  178.                             }
  179.                                 if(BianJi==5)  //进入第四位数码管修改位
  180.                             {        Led_buff[1]        = 0xbf;
  181.                                     Led_buff[0]        = Led_Char[ Time[L_u[0]]];                        
  182.                             }
  183.                                 if(BianJi==6)  //进入数码管首位零是否显示,修改选项         显示零: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) //首位数码管修改位
  207.                             {  Anjian_d(L_u[3],2);}
  208.                                 if(BianJi==3) //第二位数码管修改位
  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) //第三位数码管修改位
  216.                             {  Anjian_d(L_u[1],5); }
  217.                                 if(BianJi==5) //第四位数码管修改位
  218.                             {  Anjian_d(L_u[0],9); }
  219.                                 if(BianJi==6) //进入数码管首位零是否显示,修改选项         显示零: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]; //十位个位组成数值待写入DS3231
  251.          else
  252.          i = Time[addr]*10+Time[addr-1]; //十位个位组成数值待写入DS3231
  253.          Led_buff[5-BianJi] = Led_Char[ Time[addr]]; //修改的值显示到数码管上
  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;      //定时器计数频率
  263.     tmp = (tmp * ms) / 1000;  //计算所需的计数值
  264.     tmp = 65536 - tmp;        //计算定时器重载值
  265.     TMOD &= 0xF0;   //清零T0的控制位
  266.     TH0 = (u8)(tmp>>8);  //定时器重载值拆分为高低字节
  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时间,并写入数码管缓冲区的标记
  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温度,并写入数码管缓冲区的标记
  293.          }
  294.          
  295.      Led_can();         //数码管刷新
  296.          anjian();         //按键扫描
  297.          WDT_CONTR=0x37;           //看门狗刷新  8.4S

  298. }
  299. //E2PROM-写一个字节数据到时钟芯片
  300. void write_byte_E2( u8 write_data)        
  301. {         

  302.      I2CStart();      //产生总线起始信号
  303.      I2CWrite(E2PROM_WriteAddress);  //<<<<I2C总线写操作  E2PROM-器件码
  304.      I2CWrite(0);     //                                   E2PROM-存储空间高八位地址
  305.          I2CWrite(1);     //                                   E2PROM-存储空间低八位地址
  306.      I2CWrite(write_data);  //             写数据         
  307.      I2CStop();       //产生总线停止信号   
  308.    
  309. }

  310. //E2PROM-读一个字节数据到时钟芯片
  311. u8 read_byte_E2()
  312. {
  313.          char temp;

  314.      I2CStart();      //产生总线起始信号
  315.          I2CWrite(E2PROM_WriteAddress);  //<<<<I2C总线写操作 E2PROM-器件码
  316.      I2CWrite(0);     //                       E2PROM-存储空间高八位地址
  317.          I2CWrite(1);     //                      E2PROM-存储空间低八位地址
  318.          I2CStart();      //产生总线起始信号
  319.          I2CWrite(E2PROM_WriteAddress|1);     //从写                E2PROM-器件码
  320.          temp = I2CReadNAK();  //             读数据-发送非应答信号,不读了
  321.      I2CStop();       //产生总线停止信号
  322.      return(temp);
  323. }

  324. //DS3231_写一个字节数据到时钟芯片
  325. void write_byte(u8 addr, u8 write_data)        
  326. {         

  327.      I2CStart();  //产生总线起始信号
  328.      I2CWrite(DS3231_WriteAddress);  //<<<<I2C总线写操作
  329.      I2CWrite(addr);  //<<<<I2C总线写操作
  330.      I2CWrite(write_data);  //<<<<I2C总线写操作         
  331.      I2CStop();   //产生总线停止信号   
  332.    
  333. }

  334. //DS3231_读一个字节数据到时钟芯片
  335. u8 read_byte(u8 random_addr)
  336. {
  337.          char temp;

  338.      I2CStart();  //产生总线起始信号
  339.          I2CWrite(DS3231_WriteAddress);  //<<<<I2C总线写操作 器件码
  340.      I2CWrite(random_addr);  //<<<<存储空间地址
  341.          I2CStart();  //产生总线起始信号
  342. ……………………

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


所有资料51hei提供下载:
实时时钟.rar (145.56 KB, 下载次数: 365)


评分

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

查看全部评分

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

使用道具 举报

沙发
ID:259274 发表于 2017-12-18 23:21 | 只看该作者
楼主方便吗?加我QQ1094883144,想问问 问题
回复

使用道具 举报

板凳
ID:231936 发表于 2018-1-3 14:26 | 只看该作者
楼主这个程序电路都有问题,能不能实物点亮。
回复

使用道具 举报

地板
ID:58730 发表于 2018-3-4 13:12 | 只看该作者
谢谢分享
回复

使用道具 举报

5#
ID:287653 发表于 2018-3-5 10:28 | 只看该作者
很棒!!!
回复

使用道具 举报

6#
ID:96881 发表于 2018-4-4 21:27 | 只看该作者
不错的资料,学习一下
回复

使用道具 举报

7#
ID:183763 发表于 2018-4-26 21:13 | 只看该作者
仿制了一个不成功,秒点能闪烁,时间显示68:08,而且不会变化,会是哪里出了问题
回复

使用道具 举报

8#
ID:243262 发表于 2018-5-15 19:56 | 只看该作者
66666666
回复

使用道具 举报

9#
ID:334781 发表于 2018-5-21 12:36 | 只看该作者
刚刚下载了,程序很完整,还没有试呢,谢谢楼主!
回复

使用道具 举报

10#
ID:310015 发表于 2018-5-26 16:49 | 只看该作者
下一个试一试感谢楼主
回复

使用道具 举报

11#
ID:367948 发表于 2018-8-9 13:17 | 只看该作者
谢谢楼主
回复

使用道具 举报

12#
ID:363686 发表于 2018-8-10 06:49 | 只看该作者
学习贴,收藏了,谢谢分享
回复

使用道具 举报

13#
ID:371527 发表于 2018-8-19 16:54 | 只看该作者
数码管的显示就是功耗的问题
回复

使用道具 举报

14#
ID:387328 发表于 2018-9-17 15:59 | 只看该作者
好贴,学习了。
回复

使用道具 举报

15#
ID:299145 发表于 2018-10-7 19:11 | 只看该作者
谢谢分享!!哈哈
回复

使用道具 举报

16#
ID:101808 发表于 2018-10-10 18:00 | 只看该作者
这焊接技术,膜拜中
回复

使用道具 举报

17#
ID:57984 发表于 2018-11-11 14:56 | 只看该作者
非常好的例程,照着做就可以了,谢谢
回复

使用道具 举报

18#
ID:124234 发表于 2018-12-6 13:42 | 只看该作者
看着不错,学习一下
回复

使用道具 举报

19#
ID:59525 发表于 2019-1-1 16:49 | 只看该作者
这个电路有做成功的吗??
回复

使用道具 举报

20#
ID:237159 发表于 2019-6-4 01:42 | 只看该作者
感谢分享
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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