找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 4477|回复: 5
收起左侧

STC15F104W单片机+DS3231实时时钟PADS9.5原理图+源程序

[复制链接]
ID:433972 发表于 2018-11-29 09:45 | 显示全部楼层 |阅读模式
实时时钟资料:
0.png

单片机源程序如下:
  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.          I2CWrite(DS3231_ReadAddress);  ////从写  器件码  
  343.          temp = I2CReadNAK();       //<<<<I2C总线读操作,并发送非应答信号,不读了
  344.      I2CStop();   //产生总线停止信号
  345.      return(temp);
  346. }

  347. //BCD转换为Byte
  348. u8 BCD2HEX(u8 val)   
  349. {
  350.      u8 temp;
  351.      temp=val&0x0f;
  352.      val>>=4;
  353.      val*=10;
  354.      temp+=val;
  355.    
  356.      return temp;
  357. }
  358. //Byte码转换为BCD码
  359. u8 HEX2BCD(u8 val)   
  360. {
  361.      u8 temp;
  362.      temp=(val/10%10)<<4;
  363.          temp=temp+val%10;
  364.      return temp;
  365. }
  366. //按钮扫描         需在定时中断中调用
  367. void anjian()
  368. {        static u16 JiShu=0;
  369.     static u8 keybuf = 0xff;

  370.         keybuf = (keybuf <<1) |KEY1;
  371.         if(keybuf == 0x00)
  372.         { JiShu++; if(JiShu>=300) JiShu=300; }
  373.         else if(keybuf == 0xFF)
  374.         {
  375.              if(JiShu>=300)
  376.              {   BianJi_c=1;  }        //大于1.5秒,长按键标记置1
  377.                  else if(BianJi>=1 && JiShu>0 )
  378.                  {         BianJi_d=1;  }        //小于1.5秒,短按键标记置1
  379.                    JiShu=0;
  380.         }

  381. }
复制代码

所有资料51hei提供下载:
实时时钟.zip (169.17 KB, 下载次数: 161)

评分

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

查看全部评分

回复

使用道具 举报

ID:1 发表于 2018-12-2 02:08 | 显示全部楼层
好资料,51黑有你更精彩!!!
回复

使用道具 举报

ID:353831 发表于 2019-12-14 10:17 | 显示全部楼层
楼主 下载的压缩包里没有原理图,另外问一下用的什么型号的单片机?
回复

使用道具 举报

ID:499081 发表于 2020-11-10 07:37 | 显示全部楼层
wl020807 发表于 2019-12-14 10:17
楼主 下载的压缩包里没有原理图,另外问一下用的什么型号的单片机?

15f104
回复

使用道具 举报

ID:227504 发表于 2020-11-24 09:28 | 显示全部楼层
楼主,什么数码管驱动芯片?
回复

使用道具 举报

ID:227504 发表于 2020-11-24 09:34 | 显示全部楼层
楼主,原理图打不开,可以生成PDF文件吗?
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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