找回密码
 立即注册

QQ登录

只需一步,快速开始

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

C语言日期与时间戳转换 STM32F103 DS1302

[复制链接]
跳转到指定楼层
楼主
ID:323589 发表于 2020-3-2 16:58 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
由于公司项目原因 用到了DS1302 其中时间是由时间戳转换成日期存到DS1302的 在网上查找过一些代码 再加上自己的一些理解 将代码提供出来
适用于 DS1302 的读写驱动 以及 时间戳转日期 日期转时间戳 DS1302是否掉电等问题。有需要的可以了解一下。  DS1302.c

  1. #include "ds1302.h"

  2. char PowerDown=0;            //掉电标志 如果为 1 说明掉过电
  3. extern volatile u32 system_time;   //系统时间

  4. struct DS1302DATA ds1302Data = {0,0,0,0,0,0,0};
  5. u8 ascii_time[7] = {0};     //保存ascii格式数据

  6. u8 bcd_time[7] = {0};       //保存bcd码数据

  7. static u8 AsciiToBcd(u8 asciiData)
  8. {
  9.     u8 bcdData = 0;
  10.     bcdData = (((asciiData/10)<<4)|((asciiData%10)));
  11.     return bcdData;
  12. }
  13. static u8 BcdToAscii(u8 bcdData)
  14. {
  15.     u8 asciiData = 0;
  16.     asciiData = (((bcdData&0xf0)>>4)*10 + (bcdData&0x0f));
  17.     return asciiData;
  18. }

  19. //IO口初始化
  20. void Ds1302_Gpio_Init(void)
  21. {
  22.     GPIO_InitTypeDef GPIO_InitStructure;
  23.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD, ENABLE);
  24.    
  25.     //RST
  26.     GPIO_InitStructure.GPIO_Pin =GPIO_Pin_12;      
  27.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  28.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;//推挽输出
  29.     GPIO_Init(GPIOD, &GPIO_InitStructure);
  30.    
  31.     //CLK
  32.     GPIO_InitStructure.GPIO_Pin =GPIO_Pin_10;      
  33.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  34.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;//推挽输出
  35.     GPIO_Init(GPIOD, &GPIO_InitStructure);
  36.    
  37.     //IO
  38.     GPIO_InitStructure.GPIO_Pin =GPIO_Pin_11;      
  39.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  40.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;//推挽输出
  41.     GPIO_Init(GPIOD, &GPIO_InitStructure);
  42. }

  43. //读取一个字节的时序
  44. u8 Ds1302_ReadByte(void)
  45. {
  46.     u8 i = 0, dat = 0;
  47.     DS1302_DAT_INPUT();
  48.     delay_us(5);
  49.     for(i = 0; i <8; i++)
  50.     {
  51.         dat >>= 1;
  52.         if(DS1302_DATIN == 1)dat |= 0x80;
  53.         DS1302_CLK = 1;
  54.         delay_us(2);
  55.         DS1302_CLK = 0;
  56.         delay_us(2);
  57.     }
  58.     return dat;
  59. }

  60. //写入一个字节的时序
  61. void Ds1302_WriteByte(u8 dat)
  62. {
  63.     u8 i = 0, data = dat;
  64.     DS1302_DAT_OUTPUT();
  65.     DS1302_CLK = 0;
  66.     delay_us(2);
  67.     for(i = 0; i < 8; i++)
  68.     {
  69.         DS1302_DATOUT = data&0x01;
  70.         delay_us(2);
  71.         DS1302_CLK = 1;
  72.         delay_us(2);
  73.         DS1302_CLK = 0;
  74.         data >>= 1;
  75.     }
  76. }

  77. //写入一个寄存器
  78. void Ds1302_Write(u8 address,u8 dat)
  79. {
  80.     DS1302_RST = 0;
  81.     DS1302_CLK = 0;
  82.     DS1302_RST = 1;
  83.     Ds1302_WriteByte(address);
  84.     Ds1302_WriteByte(dat);
  85.     DS1302_CLK = 1;
  86.     DS1302_RST = 0;
  87. }

  88. //单个写入时间
  89. void Ds1302_Write_Time_Singel(u8 address,u8 dat)
  90. {
  91.     Ds1302_Write(DS1302_CONTROL_REG,0x00);  //取消写保护
  92.     Ds1302_Write(address,dat);
  93.     Ds1302_Write(DS1302_CONTROL_REG,0x80);  //打开写保护
  94. }

  95. //一次完成所有时间更新
  96. //start当前时钟运行还是停止
  97. void Ds1302_Write_Time_All(u8 start)
  98. {
  99.     Ds1302_Write(DS1302_CONTROL_REG,0x00);      //取消写保护
  100.     Ds1302_Write(DS1302_SEC_REG,(AsciiToBcd(ds1302Data.sec)|start));
  101.     Ds1302_Write(DS1302_MIN_REG,AsciiToBcd(ds1302Data.min));
  102.     Ds1302_Write(DS1302_HR_REG,AsciiToBcd(ds1302Data.hour));
  103.     Ds1302_Write(DS1302_DATE_REG,AsciiToBcd(ds1302Data.day));
  104.     Ds1302_Write(DS1302_MONTH_REG,AsciiToBcd(ds1302Data.month));
  105.     Ds1302_Write(DS1302_DAY_REG,AsciiToBcd(ds1302Data.week));
  106.     Ds1302_Write(DS1302_YEAR_REG,AsciiToBcd(ds1302Data.year));
  107.     Ds1302_Write(DS1302_CONTROL_REG,0x80);  //打开写保护
  108. }


  109. //读取一个字节
  110. u8 Ds1302_Read(u8 address)
  111. {
  112.     u8 data = 0;
  113.     DS1302_RST = 0;
  114.     DS1302_CLK = 0;
  115.     DS1302_RST = 1;
  116.     Ds1302_WriteByte(address|0x01); //读取地址需要与0x01相或,最低为变成1
  117.     data = Ds1302_ReadByte();
  118.     DS1302_CLK = 1;
  119.     DS1302_RST = 0;
  120.     return data;
  121. }

  122. //读取时间的时候默认让时间走起来
  123. void Ds1302_Readtime(void)
  124. {
  125.     ds1302Data.sec = BcdToAscii(Ds1302_Read(DS1302_SEC_REG));  //秒
  126.     ds1302Data.min = BcdToAscii(Ds1302_Read(DS1302_MIN_REG));  //分
  127.     ds1302Data.hour = BcdToAscii(Ds1302_Read(DS1302_HR_REG));   //小时
  128.     ds1302Data.day = BcdToAscii(Ds1302_Read(DS1302_DATE_REG)); //日
  129.     ds1302Data.month = BcdToAscii(Ds1302_Read(DS1302_MONTH_REG)); //月
  130.     ds1302Data.week = BcdToAscii(Ds1302_Read(DS1302_DAY_REG));  //星期几
  131.     ds1302Data.year = BcdToAscii(Ds1302_Read(DS1302_YEAR_REG)); //年

  132. }
  133. //判断DS1302是否掉过电
  134. void Time_correct()
  135. {
  136.    
  137.   if(Ds1302_Read(DS1302_RAM_BASE)!=0x55)   //掉过电
  138.   {
  139.         Ds1302_Readtime();
  140.     PowerDown=1;
  141.   }
  142. //   Ds1302_Write(DS1302_RAM_BASE,0x55);   //  RAM中掉电会丢失

  143. }

  144. //UNIX转为UTC 已进行时区转换 北京时间UTC+8
  145. void xSeconds2Date(unsigned int seconds)
  146. {
  147.     static unsigned int month[12]={
  148.         /*01月*/31,
  149.         /*02月*/28,
  150.         /*03月*/31,
  151.         /*04月*/30,
  152.         /*05月*/31,
  153.         /*06月*/30,
  154.         /*07月*/31,
  155.         /*08月*/31,
  156.         /*09月*/30,
  157.         /*10月*/31,
  158.         /*11月*/30,
  159.         /*12月*/31
  160.     };
  161.     unsigned int days;
  162.     unsigned short leap_y_count;
  163.     ds1302Data.sec=seconds%60;//获得秒
  164.     seconds/=60;
  165.     ds1302Data.min=seconds%60;//获得分
  166.     seconds+=8*60 ;        //时区矫正 转为UTC+8 bylzs
  167.     seconds/=60;
  168.     ds1302Data.hour=seconds % 24;//获得时
  169.     days=seconds/24;//获得总天数
  170.     leap_y_count=(days + 365)/1461;//过去了多少个闰年(4年一闰)
  171.     if(((days + 366)%1461)==0)
  172.     {//闰年的最后1天
  173.         ds1302Data.year=1970+(days/366);//获得年
  174.         ds1302Data.month=12;              //调整月
  175.         ds1302Data.day=31;
  176.         return;
  177.     }
  178.     days-=leap_y_count;
  179.     ds1302Data.year=1970+(days/365);     //获得年
  180.     days%=365;                       //今年的第几天
  181.     days=01+days;                  //1日开始
  182.     if((ds1302Data.year%4)==0)
  183.     {
  184.         if(days>60)--days;            //闰年调整
  185.         else
  186.         {
  187.             if(days == 60)
  188.             {
  189.                 ds1302Data.month=2;
  190.                 ds1302Data.day=29;
  191.                 return;
  192.             }
  193.         }
  194.     }
  195.     for(ds1302Data.month= 0;month[ds1302Data.month]<days;ds1302Data.month++)
  196.     {
  197.         days-=month[ds1302Data.month];
  198.     }
  199.     ++ds1302Data.month;               //调整月
  200.     ds1302Data.day=days;           //获得日
  201. }
  202. typedef struct t_xtime {
  203.   int year; int month;  int day;  
  204.   int hour; int minute;  int second;
  205. } _xtime ;

  206. #define xMINUTE   (60) //1分的秒数
  207. #define xHOUR     (60*xMINUTE) //1小时的秒数
  208. #define xDAY      (24*xHOUR) //1天的秒数
  209. #define xYEAR     (365*xDAY) //1年的秒数
  210. unsigned int  xDate2Seconds()
  211. {
  212.   static unsigned int  month[12]={
  213.     /*01月*/xDAY*(0),
  214.     /*02月*/xDAY*(31),
  215.     /*03月*/xDAY*(31+28),
  216.     /*04月*/xDAY*(31+28+31),
  217.     /*05月*/xDAY*(31+28+31+30),
  218.     /*06月*/xDAY*(31+28+31+30+31),
  219.     /*07月*/xDAY*(31+28+31+30+31+30),
  220.     /*08月*/xDAY*(31+28+31+30+31+30+31),
  221.     /*09月*/xDAY*(31+28+31+30+31+30+31+31),
  222.     /*10月*/xDAY*(31+28+31+30+31+30+31+31+30),
  223.     /*11月*/xDAY*(31+28+31+30+31+30+31+31+30+31),
  224.     /*12月*/xDAY*(31+28+31+30+31+30+31+31+30+31+30)
  225.   };
  226.   unsigned int  seconds = 0;
  227.   unsigned int  year = 0;
  228.   year=ds1302Data.year-1970;       //不考虑2100年千年虫问题
  229.   seconds = xYEAR*year + xDAY*((year+1)/4);  //前几年过去的秒数
  230.   seconds += month[ds1302Data.month-1];      //加上今年本月过去的秒数
  231.   if( (ds1302Data.month > 2) && (((year+2)%4)==0) )//2008年为闰年
  232.     seconds += xDAY;            //闰年加1天秒数
  233.   seconds += xDAY*(ds1302Data.day-1);         //加上本天过去的秒数
  234.   seconds += xHOUR*ds1302Data.hour;           //加上本小时过去的秒数
  235.   seconds += xMINUTE*ds1302Data.min;       //加上本分钟过去的秒数
  236.   seconds += ds1302Data.sec;               //加上当前秒数<br> seconds -= 8 * xHOUR;
  237.   return seconds;
  238. }
  239. //读取日期转时间戳 本地时间
  240. void Read_TimeStamp(void)
  241. {
  242.   Ds1302_Readtime();
  243.   system_time=xDate2Seconds();
  244. }
  245. //时间戳转日期 写入DS1302
  246. void Write_TimeStamp(unsigned int secon)
  247. {
  248.   xSeconds2Date(secon);
  249.   
  250.   Ds1302_Write_Time_All(0);
  251.   PowerDown=0;
  252.   Ds1302_Write(DS1302_RAM_BASE,0x55);   //  RAM中掉电会丢失
  253. }
复制代码
DS1302.h

  1. #ifndef __DS1302_H
  2. #define __DS1302_H
  3. #include "stm32f10x.h"
  4. #include "delay.h"
  5. extern u8 ascii_time[7];     //保存ascii格式数据

  6. extern u8 bcd_time[7];       //保存bcd码数据

  7. typedef struct DS1302DATA
  8. {
  9.     u8 year;    //年
  10.     u8 month;   //月
  11.     u8 day;     //日
  12.     u8 hour;    //时
  13.     u8 min;     //分
  14.     u8 sec;     //秒
  15.     u8 week;    //周
  16. }DS1302DATA;

  17. extern struct DS1302DATA ds1302Data;

  18. #define DS1302_RST      PDout(12)
  19. #define DS1302_CLK      PDout(10)
  20. #define DS1302_DATIN    PDin(11)
  21. #define DS1302_DATOUT   PDout(11)

  22. #define DS1302_DAT_INPUT()     {GPIOD->CRH &= 0XFFFF0FFF;GPIOD->CRH|=8<<12;}
  23. #define DS1302_DAT_OUTPUT()    {GPIOD->CRH &= 0XFFFF0FFF;GPIOD->CRH|=3<<12;}

  24. //芯片寄存器地址定义 定义的写地址,读需要+1
  25. #define DS1302_SEC_REG                        0x80                //秒数据地址
  26. #define DS1302_MIN_REG                        0x82                //分数据地址
  27. #define DS1302_HR_REG                        0x84                //时数据地址
  28. #define DS1302_DATE_REG                        0x86                //日数据地址
  29. #define DS1302_MONTH_REG                0x88                //月数据地址
  30. #define DS1302_DAY_REG                        0x8a                //星期几数据地址
  31. #define DS1302_YEAR_REG                        0x8c                //年数据地址
  32. #define DS1302_CONTROL_REG                0x8e                //写保护寄存器地址
  33. #define DS1302_CHARGER_REG                0x90                 //涓流充电寄存器                         
  34. #define DS1302_CLKBURST_REG                0xbe             //脉冲串寄存器
  35. #define DS1302_RAM_BASE                 0X30            //RAM基础地址

  36. #define CLOCKSTOP       0X80
  37. #define CLOCKSTART      0X00


  38. void Ds1302_Gpio_Init(void);
  39. void Ds1302_Write_Time_All(u8 start);
  40. void Ds1302_Readtime(void);
  41. void Time_correct();
  42. unsigned int  xDate2Seconds();
  43. void xSeconds2Date(unsigned int seconds);
  44. void Read_TimeStamp(void);
  45. void Write_TimeStamp(unsigned int secon);

  46. #endif
复制代码
  需要注意的是 DS1302的秒寄存器需要最高位置0,DS1302才能正常工作。
另外DS1302预留有RAM 可以通过读取可以上电判断是否DS1302掉过电
,掉电则需要时钟更新 (掉电后时间不准确)。



评分

参与人数 1黑币 +100 收起 理由
admin + 100

查看全部评分

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

使用道具 举报

沙发
ID:740359 发表于 2020-4-28 19:37 | 只看该作者
你好,请教一下:在void DS1302_WriteByte(u8 dat)中“DAT_OUT = data&0x01;”报错是什么原因呢?
回复

使用道具 举报

板凳
ID:564486 发表于 2022-9-13 10:33 | 只看该作者
年应该用u16吧,u8不太够
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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