[STM32F1] STM32Cube RTC时钟掉电不保存日期

[复制链接]
1481|18
 楼主| kkzz 发表于 2022-10-27 08:00 | 显示全部楼层 |阅读模式
使用STM32Cube生成STM32F103 RTC时钟例程项目中,虽然有外部电池供电,使得系统断电后依然能够计时,但在实际使用中,系统掉电后,日期参数会重置,只有时间参数正常运行。这是因为STM32F103系列的RTC外设只是一个简单的计数器,并没有所谓的日历功能。
1.将日期参数保存到后备区域存储器
这种方法比较简单,但是没办法根治问题,断电时,一旦时间到达24:00,时间参数会重置从00:00重新开始计时,但是日期并不会更新。


2.将日期和时间换算为时间戳保存在计数器中
STM32F103的RTC本质上是一个32位的计数器,在断电后,由电池供电还能保持计数。所以可以将日期和时间换算为时间戳保存到计数器中,当需要读取时间时,从计数器中读取时间戳,重新换算成日期和时间即可。


相关接口函数:
  1. // 设置时间戳计数的基准日期
  2. RTC_DateTypeDef DateBase = {
  3.     .Year = 22,
  4.     .Month = 01,
  5.     .Date = 01,
  6.     .WeekDay = RTC_WEEKDAY_SATURDAY,
  7. };

  8. //===========================================================================
  9. //函数名: GetDiffDate(uint32_t StartDate, uint32_t EndDate)
  10. //功能  : 计算两个日期之间的天数并返回
  11. //参数  : RTC_DateTypeDef StartDate, RTC_DateTypeDef EndDate
  12. //返回值: uint32_t
  13. //===========================================================================
  14. uint32_t GetDiffDate(RTC_DateTypeDef StartDate, RTC_DateTypeDef EndDate)
  15. {
  16.     uint32_t DayDiff = 0; // 两个日期的天数差

  17.     while (1)
  18.     {
  19.         if ((StartDate.Year == EndDate.Year) && (StartDate.Month == EndDate.Month))
  20.         {
  21.             DayDiff += EndDate.Date - StartDate.Date;
  22.             break;
  23.         }
  24.         else
  25.         {
  26.             DayDiff += EndDate.Date;
  27.             EndDate.Month--;
  28.             if (EndDate.Month == 0)
  29.             {
  30.                 EndDate.Month = 12;
  31.                 EndDate.Year--;
  32.             }
  33.             EndDate.Date = GetDayOfMonth(EndDate.Year, EndDate.Month);
  34.         }
  35.     }

  36.     return DayDiff;
  37. }

  38. //===========================================================================
  39. //函数名: CalculateDate
  40. //功能  : 根据起始日期和天数,计算之后的日期并返回
  41. //参数  : RTC_DateTypeDef FromDate, uint32_t DayDiff
  42. //返回值: RTC_DateTypeDef
  43. //===========================================================================
  44. RTC_DateTypeDef CalculateDate(RTC_DateTypeDef FromDate, uint32_t DayDiff)
  45. {
  46.     uint16_t day = 0;

  47.     while (1)
  48.     {
  49.         day = GetDayOfMonth(FromDate.Year, FromDate.Month);
  50.         if (FromDate.Date + DayDiff > day)
  51.         {
  52.             DayDiff -= day - FromDate.Date;
  53.             FromDate.Month++;
  54.             FromDate.Date = 0;

  55.             if (FromDate.Month == 13)
  56.             {
  57.                 FromDate.Month = 1;
  58.                 FromDate.Year++;
  59.             }
  60.         }
  61.         else
  62.         {
  63.             FromDate.Date += DayDiff;
  64.             break;
  65.         }
  66.     }

  67.     FromDate.WeekDay = DateBase.WeekDay + (DayDiff % 7);
  68.     if (FromDate.WeekDay >= 7)
  69.         FromDate.WeekDay -= 7;

  70.     return FromDate;
  71. }

  72. //===========================================================================
  73. //函数名: GetDayOfMonth
  74. //功能  : 根据年月,获取当月的天数并返回
  75. //参数  : uint8_t year, uint8_t month
  76. //返回值: uint8_t
  77. //===========================================================================
  78. uint8_t GetDayOfMonth(uint8_t year, uint8_t month)
  79. {
  80.     uint8_t DayOfMonth[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

  81.     if (month == 2)
  82.     {
  83.         if ((year % 400 == 0) || ((year % 4 == 0) && (year % 100 != 0)))
  84.             return 29;
  85.         else
  86.             return 28;
  87.     }
  88.     else
  89.         return DayOfMonth[month - 1];
  90. }


  91. //===========================================================================
  92. //函数名: RTC_Set_DateTimeCounter
  93. //功能  : 设置RTC时间(将时间转化为时间戳保存到RTC中)
  94. //参数  :
  95. //返回值:
  96. //===========================================================================
  97. void RTC_Set_DateTimeCounter(RTC_DateTypeDef *sDate, RTC_TimeTypeDef *sTime)
  98. {
  99.     uint32_t timecounter = (uint32_t)sTime->Hours * 3600 + (uint32_t)sTime->Minutes * 60 + sTime->Seconds + GetDiffDate(DateBase, *sDate) * 3600 * 24;
  100.     RTC_WriteTimeCounter(&hrtc, timecounter);
  101. }

  102. //===========================================================================
  103. //函数名: RTC_Get_DateTimeCounter
  104. //功能  : 获取RTC时间(获取存储在计数器中的时间戳,再将其转化为时间)
  105. //参数  :
  106. //返回值:
  107. //===========================================================================
  108. void RTC_Get_DateTimeCounter(RTC_DateTypeDef *sDate, RTC_TimeTypeDef *sTime)
  109. {
  110.     uint32_t timecounter = RTC_ReadTimeCounter(&hrtc);
  111.     uint32_t SecOfToday = timecounter % (3600 * 24);
  112.     uint32_t DiffDay = timecounter / (3600 * 24);

  113.     sTime->Hours = SecOfToday / 3600;
  114.     sTime->Minutes = SecOfToday % 3600 / 60;
  115.     sTime->Seconds = SecOfToday % 60;

  116.     *sDate = CalculateDate(DateBase, DiffDay);
  117. }
改写RTC时钟初始化函数 void MX_RTC_Init(void)


  1. void MX_RTC_Init(void)
  2. {

  3.     /* USER CODE BEGIN RTC_Init 0 */

  4.     /* USER CODE END RTC_Init 0 */

  5.     RTC_TimeTypeDef sTime = {0};
  6.     RTC_DateTypeDef DateToUpdate = {0};

  7.     /* USER CODE BEGIN RTC_Init 1 */
  8.     __HAL_RCC_BKP_CLK_ENABLE();
  9.     __HAL_RCC_PWR_CLK_ENABLE();
  10.     /* USER CODE END RTC_Init 1 */
  11.     /** Initialize RTC Only
  12.      */
  13.     hrtc.Instance = RTC;
  14.     hrtc.Init.AsynchPrediv = RTC_AUTO_1_SECOND;
  15.     hrtc.Init.OutPut = RTC_OUTPUTSOURCE_NONE;
  16.     if (HAL_RTC_Init(&hrtc) != HAL_OK)
  17.     {
  18.         Error_Handler();
  19.     }

  20.     /* USER CODE BEGIN Check_RTC_BKUP */
  21.     if (HAL_RTCEx_BKUPRead(&hrtc, RTC_BKP_DR1) != 0x0102)
  22.     {
  23.         /* USER CODE END Check_RTC_BKUP */

  24.         /** Initialize RTC and set the Time and Date
  25.          */
  26.         sTime.Hours = 23;
  27.         sTime.Minutes = 59;
  28.         sTime.Seconds = 50;

  29.         DateToUpdate.WeekDay = RTC_WEEKDAY_SATURDAY;
  30.         DateToUpdate.Month = 01;
  31.         DateToUpdate.Date = 01;
  32.         DateToUpdate.Year = 22;

  33.         // 将日期和时间换算为时间戳保存到计数器中
  34.         RTC_Set_DateTimeCounter(&DateToUpdate, &sTime);

  35.         HAL_RTCEx_BKUPWrite(&hrtc, RTC_BKP_DR1, 0x0102);
  36.         /* USER CODE BEGIN RTC_Init 2 */
  37.     }
  38.     /* USER CODE END RTC_Init 2 */
  39. }
当需要获取时间时,只需要通过接口 void RTC_Get_DateTimeCounter(RTC_DateTypeDef *sDate, RTC_TimeTypeDef *sTime) 获取即可。
原文链接:https://blog.csdn.net/Yellow0102/article/details/123281814

belindagraham 发表于 2022-11-15 21:22 | 显示全部楼层
这个确实有这个问题的              
mikewalpole 发表于 2022-11-15 21:43 | 显示全部楼层
是不是可以把时间保存到backup的寄存器中呢?  
nomomy 发表于 2022-11-15 22:04 | 显示全部楼层
是不是stm32的bug呢?如何修正这个问题。
bestwell 发表于 2022-11-16 20:45 | 显示全部楼层
RTC时钟掉电不保存日期,但是时间没有问题
abotomson 发表于 2022-11-16 21:25 | 显示全部楼层
这个HAL修改的代码吗?              
sesefadou 发表于 2022-11-16 22:27 | 显示全部楼层
RTC初始化以后,怎么才能不再修改时间呢
jf101 发表于 2024-6-23 14:30 | 显示全部楼层
RTC初始化前一定要进行单独的电池进行供电设计
帛灿灿 发表于 2024-11-16 07:20 | 显示全部楼层

得到不同测试条件下的输出电流和电压值,分析数据并进行比较
帛灿灿 发表于 2024-11-16 07:20 | 显示全部楼层

得到不同测试条件下的输出电流和电压值,分析数据并进行比较
Bblythe 发表于 2024-11-16 08:23 | 显示全部楼层

这样可以获得更光滑的表面。
周半梅 发表于 2024-11-16 10:19 | 显示全部楼层

是因为它作用是起到抑制,多应用于开关电源电路中
Pulitzer 发表于 2024-11-16 11:22 | 显示全部楼层

对于标准PCB设计,c形孔的最小直径为0.5mm,
童雨竹 发表于 2024-11-16 13:18 | 显示全部楼层

它是由两个尺寸相同、匝数相同的线圈对称地绕制在同一个铁氧体环形磁芯
Wordsworth 发表于 2024-11-16 14:21 | 显示全部楼层

镀半孔或c形孔是在板的边缘上镀半个半孔的一半。
Clyde011 发表于 2024-11-16 15:24 | 显示全部楼层

驱动脉冲变压器原边时,
公羊子丹 发表于 2024-11-16 16:17 | 显示全部楼层

这种电路结构的特点是:由四只相同的开关管接成电桥结构驱动脉冲变压器原边。
万图 发表于 2024-11-16 17:20 | 显示全部楼层

这种技术称为板对板焊接
Uriah 发表于 2024-11-16 18:23 | 显示全部楼层

开模的话,模具不会塌踏。。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

332

主题

11262

帖子

13

粉丝
快速回复 在线客服 返回列表 返回顶部