硬汉嵌入式论坛

 找回密码
 立即注册
查看: 5724|回复: 5
收起左侧

[客户分享] 早期给STM32F1的RTC做的年月日时分秒和星期计算驱动

  [复制链接]

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
107049
QQ
发表于 2020-12-16 12:17:32 | 显示全部楼层 |阅读模式
由于F1系列的RTC仅仅是个计数器,没有日期功能,所以单独做了个驱动

bsp_cpu_rtc.c (10.41 KB, 下载次数: 64)
bsp_cpu_rtc.h (1.05 KB, 下载次数: 61)


  1. /*
  2. *********************************************************************************************************
  3. *        函 数 名: RTC_WriteClock
  4. *        功能说明: 设置RTC时钟
  5. *        形    参:无
  6. *        返 回 值: 1表示成功 0表示错误
  7. *********************************************************************************************************
  8. */
  9. uint8_t RTC_WriteClock(uint16_t _year, uint8_t _mon, uint8_t _day, uint8_t _hour, uint8_t _min, uint8_t _sec)
  10. {
  11.         uint16_t t;
  12.         uint32_t seccount=0;

  13.         if (_year < 2000 || _year > 2099)
  14.         {
  15.                 return 0;        /* _year范围1970-2099,此处设置范围为2000-2099 */   
  16.         }               
  17.         
  18.         for (t = 1970; t < _year; t++)         /* 把所有年份的秒钟相加 */
  19.         {
  20.                 if (Is_Leap_Year(t))                /* 判断是否为闰年 */
  21.                 {
  22.                         seccount += 31622400;        /* 闰年的秒钟数 */
  23.                 }
  24.                 else
  25.                 {
  26.                         seccount += 31536000;         /* 平年的秒钟数 */
  27.                 }
  28.         }

  29.         _mon -= 1;

  30.         for (t = 0; t < _mon; t++)         /* 把前面月份的秒钟数相加 */
  31.         {
  32.                 seccount += (uint32_t)mon_table[t] * 86400;        /* 月份秒钟数相加 */

  33.                 if (Is_Leap_Year(_year) && t == 1)
  34.                 {
  35.                         seccount += 86400;        /* 闰年2月份增加一天的秒钟数 */
  36.                 }                        
  37.         }

  38.         seccount += (uint32_t)(_day - 1) * 86400;        /* 把前面日期的秒钟数相加 */

  39.         seccount += (uint32_t)_hour * 3600;                /* 小时秒钟数 */

  40.         seccount += (uint32_t)_min * 60;        /* 分钟秒钟数 */

  41.         seccount += _sec;        /* 最后的秒钟加上去 */
  42.                                                                                                                                        
  43.         PWR_BackupAccessCmd(ENABLE);        /* 必须要 */

  44.         RTC_WaitForLastTask();

  45.         RTC_SetCounter(seccount);

  46.         RTC_WaitForLastTask();                        /* 必须加 PWR_BackupAccessCmd(ENABLE); 不然进入死循环 */

  47.         return 1;      
  48. }

  49. /*
  50. *********************************************************************************************************
  51. *        函 数 名: RTC_ReadClock
  52. *        功能说明: 得到当前时钟。结果存放在 g_tRTC。
  53. *        形    参:无
  54. *        返 回 值: 1表示成功 0表示错误
  55. *********************************************************************************************************
  56. */
  57. void RTC_ReadClock(void)
  58. {
  59.         static uint16_t daycnt = 0;
  60.         uint32_t timecount = 0;
  61.         uint32_t temp = 0;
  62.         uint16_t temp1 = 0;

  63.         timecount = RTC_GetCounter();     

  64.         temp = timecount / 86400;   /* 得到天数 */

  65.         if (daycnt != temp)        /* 超过一天了 */
  66.         {      
  67.                 daycnt = temp;
  68.                 temp1 = 1970;  /* 从1970年开始 */

  69.                 while (temp >= 365)
  70.                 {                          
  71.                         if (Is_Leap_Year(temp1))        /* 是闰年 */
  72.                         {
  73.                                 if (temp >= 366)
  74.                                 {
  75.                                         temp -= 366;                /* 闰年的秒钟数 */
  76.                                 }
  77.                                 else
  78.                                 {
  79.                                         //temp1++;                /* armfly: 这里闰年处理错误,不能加1 */
  80.                                         break;
  81.                                 }  
  82.             }
  83.                         else
  84.                         {
  85.                                 temp -= 365;       /* 平年 */
  86.                         }
  87.                         temp1++;  
  88.                 }   
  89.                 g_tRTC.Year = temp1;        /* 得到年份 */
  90.                
  91.                 temp1 = 0;
  92.                 while (temp >= 28)        /* 超过了一个月 */
  93.                 {
  94.                         if(Is_Leap_Year(g_tRTC.Year) && temp1 == 1)        /* 当年是不是闰年/2月份 */
  95.                         {
  96.                                 if (temp >= 29)
  97.                                 {
  98.                                         temp -= 29;        /* 闰年的秒钟数 */
  99.                                 }
  100.                                 else
  101.                                 {
  102.                                         break;
  103.                                 }
  104.             }
  105.             else
  106.                         {
  107.                                 if (temp >= mon_table[temp1])
  108.                                 {
  109.                                         temp -= mon_table[temp1];        /* 平年 */
  110.                                 }
  111.                                 else
  112.                                 {
  113.                                         break;
  114.                                 }
  115.                         }
  116.                         temp1++;  
  117.                 }
  118.                 g_tRTC.Mon = temp1 + 1;        /* 得到月份 */
  119.                 g_tRTC.Day = temp + 1;  /* 得到日期 */
  120.         }

  121.         temp = timecount % 86400;    /* 得到秒钟数 */

  122.         g_tRTC.Hour = temp / 3600;        /* 小时 */

  123.         g_tRTC.Min = (temp % 3600) / 60; /* 分钟 */

  124.         g_tRTC.Sec = (temp % 3600) % 60; /* 秒钟 */

  125.         g_tRTC.Week = RTC_CalcWeek(g_tRTC.Year, g_tRTC.Mon, g_tRTC.Day);        /* 计算星期 */
  126. }   

  127. /*
  128. *********************************************************************************************************
  129. *        函 数 名: bsp_CalcWeek
  130. *        功能说明: 根据日期计算星期几
  131. *        形    参: _year _mon _day  年月日  (年是2字节整数,月和日是字节整数)
  132. *        返 回 值: 周几 (1-7) 7表示周日
  133. *********************************************************************************************************
  134. */
  135. uint8_t RTC_CalcWeek(uint16_t _year, uint8_t _mon, uint8_t _day)
  136. {
  137.     /*
  138.     蔡勒(Zeller)公式
  139.     历史上的某一天是星期几?未来的某一天是星期几?关于这个问题,有很多计算公式(两个通用计算公式和
  140.     一些分段计算公式),其中最著名的是蔡勒(Zeller)公式。
  141.         即w=y+[y/4]+[c/4]-2c+[26(m+1)/10]+d-1

  142.     公式中的符号含义如下,
  143.          w:星期;
  144.          c:年的高2位,即世纪-1
  145.          y:年(两位数);
  146.          m:月(m大于等于3,小于等于14,即在蔡勒公式中,某年的1、2月要看作上一年的13、14月来计算,
  147.             比如2003年1月1日要看作2002年的13月1日来计算);
  148.          d:日;
  149.          [ ]代表取整,即只要整数部分。
  150.         算出来的W除以7,余数是几就是星期几。如果余数是0,则为星期日。
  151.             如果结果是负数,负数求余数则需要特殊处理:
  152.                 负数不能按习惯的余数的概念求余数,只能按数论中的余数的定义求余。为了方便
  153.             计算,我们可以给它加上一个7的整数倍,使它变为一个正数,然后再求余数

  154.     以2049年10月1日(100周年国庆)为例,用蔡勒(Zeller)公式进行计算,过程如下:
  155.     蔡勒(Zeller)公式:w=y+[y/4]+[c/4]-2c+[26(m+1)/10]+d-1
  156.     =49+[49/4]+[20/4]-2×20+[26× (10+1)/10]+1-1
  157.     =49+[12.25]+5-40+[28.6]
  158.     =49+12+5-40+28
  159.     =54 (除以7余5)
  160.     即2049年10月1日(100周年国庆)是星期5。
  161.     */
  162.     uint8_t y, c, m, d;
  163.     int16_t w;

  164.     if (_mon >= 3)
  165.     {
  166.         m = _mon;
  167.         y = _year % 100;
  168.         c = _year / 100;
  169.         d = _day;
  170.     }
  171.     else        /* 某年的1、2月要看作上一年的13、14月来计算 */
  172.     {
  173.         m = _mon + 12;
  174.         y = (_year - 1) % 100;
  175.         c = (_year - 1) / 100;
  176.         d = _day;
  177.     }

  178.     w = y + y / 4 +  c / 4 - 2 * c + ((uint16_t)26*(m+1))/10 + d - 1;
  179.     if (w == 0)
  180.     {
  181.         w = 7;        /* 表示周日 */
  182.     }
  183.     else if (w < 0)        /* 如果w是负数,则计算余数方式不同 */
  184.     {
  185.         w = 7 - (-w) % 7;
  186.     }
  187.     else
  188.     {
  189.         w = w % 7;
  190.     }

  191.     /* modified by eric2013 -- 2016-12-25 */
  192.     if (w == 0)
  193.     {
  194.         w = 7;        /* 表示周日 */
  195.     }

  196.     return w;
  197. }
复制代码



评分

参与人数 1金币 +20 收起 理由
scarecrow + 20

查看全部评分

回复

使用道具 举报

6

主题

126

回帖

144

积分

初级会员

积分
144
发表于 2020-12-17 08:55:07 | 显示全部楼层
早期的代码也是这么规整
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
107049
QQ
 楼主| 发表于 2020-12-18 08:45:58 | 显示全部楼层
role_2099 发表于 2020-12-17 08:55
早期的代码也是这么规整

前几天网友咨询了个这方面的问题,特此发出来,方便查看。

评分

参与人数 1金币 +20 收起 理由
wangertan + 20 很给力!

查看全部评分

回复

使用道具 举报

0

主题

10

回帖

10

积分

新手上路

积分
10
发表于 2020-12-27 22:02:08 | 显示全部楼层
Is_Leap_Year();这个函数是怎么实现的?代码中只调用了它。
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
107049
QQ
 楼主| 发表于 2020-12-28 07:58:49 | 显示全部楼层
nicole088 发表于 2020-12-27 22:02
Is_Leap_Year();这个函数是怎么实现的?代码中只调用了它。

在楼主位上传的C文件里面,下载查看即可
回复

使用道具 举报

29

主题

514

回帖

606

积分

金牌会员

积分
606
QQ
发表于 2021-3-30 19:13:18 | 显示全部楼层
感谢分享。
Releasing your creativity
回复

使用道具 举报

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

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2024-5-16 06:11 , Processed in 0.206147 second(s), 33 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

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