提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

STM32 RTC时钟掉电日期不更新 & STM32 HAL库RTC时钟配置

  • 一、STM32CubeMX RTC配置
  • 二、RTC初始化
  • 三、RTC日期掉电不更新(F1...这里暂时只考虑F103,其他系列未测试,对比的也只考虑F4)
  • 四、解决办法
    • 4.1、上电对时
    • 4.2、将时间和日期都换算存入到CNT寄存器中(存入时间戳)
    • 4.3、设置时间时将日期同时设置,且保存到RTC备份存储区
    • 测试结果:

一、STM32CubeMX RTC配置



二、RTC初始化

由于自动生成的RTC程序会在初始化时将默认时间写入到RTC寄存器中,所以这里采用RTC备份存储区(掉电/重启数据不丢失)来做标志位来存储系统时间是否已经初始化过,已经初始化则不在重新写入时间,否则会将RTC时间复位。(其他系列的也可以按此操作)
程序代码加在 /* USER CODE BEGIN Check_RTC_BKUP */区域内,否则更新STM32CubeMx文件会将修改的代码删掉。

  1. 首先判断标志位 0x55AA,标志位自己定义数值,0x55AA没有特别含义;
  2. 如果是首次烧录运行,判断你是不,往下走写入默认时间和0x55AA标志位,且将日期备份到RTC备份存储区;
  3. 第二次运行,判断成功成功,将RTC备份存储区的日期设入RTC寄存器。日期就不会恢复到0-01-01。但是还存在一个日期掉电跨天的问题,在第4步解决
/* RTC init function */
void MX_RTC_Init(void)
{/* USER CODE BEGIN RTC_Init 0 *//* USER CODE END RTC_Init 0 */RTC_TimeTypeDef sTime = {0};RTC_DateTypeDef DateToUpdate = {0};/* USER CODE BEGIN RTC_Init 1 *//* USER CODE END RTC_Init 1 *//** Initialize RTC Only*/hrtc.Instance = RTC;hrtc.Init.AsynchPrediv = RTC_AUTO_1_SECOND;hrtc.Init.OutPut = RTC_OUTPUTSOURCE_ALARM;if (HAL_RTC_Init(&hrtc) != HAL_OK){Error_Handler();}/* USER CODE BEGIN Check_RTC_BKUP */if(HAL_RTCEx_BKUPRead(&hrtc, RTC_BKP_DR1)== 0x55AA)//判断标志位
/*check rtc is ready running! If YES, return , otherwise set the default date and time */{  #if 1DateToUpdate.Year    = HAL_RTCEx_BKUPRead(&hrtc, RTC_BKP_DR2);DateToUpdate.Month   = HAL_RTCEx_BKUPRead(&hrtc, RTC_BKP_DR3);DateToUpdate.Date    = HAL_RTCEx_BKUPRead(&hrtc, RTC_BKP_DR4);DateToUpdate.WeekDay = HAL_RTCEx_BKUPRead(&hrtc, RTC_BKP_DR5);if (HAL_RTC_SetDate(&hrtc, &DateToUpdate, RTC_FORMAT_BIN) != HAL_OK){Error_Handler();}#endifreturn;}/* USER CODE END Check_RTC_BKUP *//** Initialize RTC and set the Time and Date*/sTime.Hours = 16;sTime.Minutes = 45;sTime.Seconds = 0;if (HAL_RTC_SetTime(&hrtc, &sTime, RTC_FORMAT_BIN) != HAL_OK){Error_Handler();}DateToUpdate.WeekDay = RTC_WEEKDAY_THURSDAY;DateToUpdate.Month = RTC_MONTH_MAY;DateToUpdate.Date = 19;DateToUpdate.Year = 22;if (HAL_RTC_SetDate(&hrtc, &DateToUpdate, RTC_FORMAT_BIN) != HAL_OK){Error_Handler();}/* USER CODE BEGIN RTC_Init 2 */HAL_RTCEx_BKUPWrite(&hrtc, RTC_BKP_DR1, 0x55AA);//写入标志位HAL_RTCEx_BKUPWrite(&hrtc, RTC_BKP_DR2, (uint16_t)DateToUpdate.Year);HAL_RTCEx_BKUPWrite(&hrtc, RTC_BKP_DR3, (uint16_t)DateToUpdate.Month);HAL_RTCEx_BKUPWrite(&hrtc, RTC_BKP_DR4, (uint16_t)DateToUpdate.Date);HAL_RTCEx_BKUPWrite(&hrtc, RTC_BKP_DR5, (uint16_t)DateToUpdate.WeekDay);/* USER CODE END RTC_Init 2 */}

三、RTC日期掉电不更新(F1…这里暂时只考虑F103,其他系列未测试,对比的也只考虑F4)

STM32F103的寄存器和F4的不一样:
F4的RTC能够掉电自动更新日期,因为有TR寄存器更新时间,DR寄存器更新日期;
而F1的只能自动更新CNTH和CNTL寄存器。通过寄存器去换算成时间。但是HAL库使用寄存器的值会在跨天的时候自动清零。
F4

F1

跨天自减

四、解决办法

4.1、上电对时

如果对时间有非常明确的要求,有条件的采用上电对时,就不会有时间错乱。方法不多赘述。

4.2、将时间和日期都换算存入到CNT寄存器中(存入时间戳)

#include "time.h"
uint32_t stm32_rtc_timestamp(RTC_TimeTypeDef TimeStruct, RTC_DateTypeDef DateStruct)
{struct tm tm_new;tm_new.tm_sec  = TimeStruct.Seconds;tm_new.tm_min  = TimeStruct.Minutes;    tm_new.tm_hour = TimeStruct.Hours;tm_new.tm_mday = DateStruct.Date;tm_new.tm_mon  = DateStruct.Month;    tm_new.tm_year = DateStruct.Year;return mktime(&tm_new);
}

(暂时没空实现,网上有一些类似方法)但是相对来说要处理的东西比较多,参考下面这个链接其实可以用时间戳转换函数去写入和转换时间。
STM32 RTC时钟掉电日期不更新

4.3、设置时间时将日期同时设置,且保存到RTC备份存储区

1) 设置的日期保存到RTC备份存储器,用作基准时间;自己实现的RTC设置日期函数。

void Bsp_RTC_SetDate(RTC_HandleTypeDef *pRtcHandle, RTC_DateTypeDef *pDateStruct)
{ HAL_RTC_SetDate(pRtcHandle, pDateStruct, FORMAT_BIN);HAL_RTCEx_BKUPWrite(pRtcHandle, RTC_BKP_DR2, (uint16_t)pDateStruct->Year);HAL_RTCEx_BKUPWrite(pRtcHandle, RTC_BKP_DR3, (uint16_t)pDateStruct->Month);HAL_RTCEx_BKUPWrite(pRtcHandle, RTC_BKP_DR4, (uint16_t)pDateStruct->Date);HAL_RTCEx_BKUPWrite(pRtcHandle, RTC_BKP_DR5, (uint16_t)pDateStruct->WeekDay);
}void Bsp_RTC_SetTime(RTC_HandleTypeDef *pRtcHandle, RTC_TimeTypeDef *pTimeStruct)
{ HAL_RTC_SetTime(pRtcHandle, pTimeStruct, FORMAT_BIN);
}

2) 时间设置和日期设置必须保持同步;这一步是为了将基准时间(RTC备份区的日期)和偏移时间(CNTH和CNTL的自增寄存器数值)统一。stm32f1xx_hal_rtc.c文件

void Drv_RTC_CalendarSet(BSP_DateTypeDef Date, BSP_TimeTypeDef Time)
{ static RTC_DateTypeDef DateStruct;static RTC_TimeTypeDef TimeStruct;DateStruct.Year = Date.Year;DateStruct.Month = Date.Month;DateStruct.Date = Date.Date;DateStruct.WeekDay = Date.WeekDay;Bsp_RTC_SetDate(&RtcHandle,&DateStruct);TimeStruct.Hours = Time.Hours;TimeStruct.Minutes = Time.Minutes;TimeStruct.Seconds = Time.Seconds;Bsp_RTC_SetTime(&RtcHandle,&TimeStruct);
}

3) CNTL和CNTH寄存器跨天不更新;即,偏移时间counter_time必须一直自增。stm32f1xx_hal_rtc.c文件
HAL_RTC_GetTime

HAL_StatusTypeDef HAL_RTC_GetTime(RTC_HandleTypeDef *hrtc, RTC_TimeTypeDef *sTime, uint32_t Format)
{/***省略*//* Read the time counter*/counter_time = RTC_ReadTimeCounter(hrtc);/* Fill the structure fields with the read parameters */hours = counter_time / 3600U;sTime->Minutes  = (uint8_t)((counter_time % 3600U) / 60U);sTime->Seconds  = (uint8_t)((counter_time % 3600U) % 60U);if (hours >= 24U){/* Get number of days elapsed from last calculation */days_elapsed = (hours / 24U);/* Set Hours in RTC_TimeTypeDef structure*/sTime->Hours = (hours % 24U);/* Read Alarm counter in RTC registers */counter_alarm = RTC_ReadAlarmCounter(hrtc);/* Calculate remaining time to reach alarm (only if set and not yet expired)*/if ((counter_alarm != RTC_ALARM_RESETVALUE) && (counter_alarm > counter_time)){counter_alarm -= counter_time;}else{/* In case of counter_alarm < counter_time *//* Alarm expiration already occurred but alarm not deactivated */counter_alarm = RTC_ALARM_RESETVALUE;}/* Set updated time in decreasing counter by number of days elapsed *///   counter_time -= (days_elapsed * 24U * 3600U);    //modify by LeoX/* Write time counter in RTC registers */if (RTC_WriteTimeCounter(hrtc, counter_time) != HAL_OK){return HAL_ERROR;}  /***省略*/
}

HAL_RTC_SetDate

HAL_StatusTypeDef HAL_RTC_SetDate(RTC_HandleTypeDef *hrtc, RTC_DateTypeDef *sDate, uint32_t Format)
{/***省略*//* Reset time to be aligned on the same day *//* Read the time counter*/counter_time = RTC_ReadTimeCounter(hrtc);/* Fill the structure fields with the read parameters */hours = counter_time / 3600U;if (hours > 24U){/* Set updated time in decreasing counter by number of days elapsed */
//    counter_time -= ((hours / 24U) * 24U * 3600U);/* Write time counter in RTC registers */if (RTC_WriteTimeCounter(hrtc, counter_time) != HAL_OK){/* Set RTC state */hrtc->State = HAL_RTC_STATE_ERROR;/* Process Unlocked */__HAL_UNLOCK(hrtc);return HAL_ERROR;}/***省略*/
}

4) 日期更新的时候读取RTC备份区的日期来计算偏移;在for循环中计算年月日的偏移。

static void RTC_DateUpdate(RTC_HandleTypeDef *hrtc, uint32_t DayElapsed)
{uint32_t year = 0U, month = 0U, day = 0U;uint32_t loop = 0U;
#if 0            //modify by LeoX/* Get the current year*/year = hrtc->DateToUpdate.Year;/* Get the current month and day */month = hrtc->DateToUpdate.Month;day = hrtc->DateToUpdate.Date;
#else            //modify by LeoXyear   = HAL_RTCEx_BKUPRead(hrtc, RTC_BKP_DR2);month  = HAL_RTCEx_BKUPRead(hrtc, RTC_BKP_DR3);day   = HAL_RTCEx_BKUPRead(hrtc, RTC_BKP_DR4);
#endiffor (loop = 0U; loop < DayElapsed; loop++)

测试结果:

  1. 程序下载,初始化默认的时间
  2. 修改时间
  3. 带电时间跨天,日期更新
  4. 下电时间跨天

    5) 设置时间后立即反复掉电重启


    说明:
    1) 以上的时间全部为测试时间,初始化默认时间和STM32CubeMx的对应不上是因为以及做过几轮测试;
    2) 这个方法要改到库函数,修改库函数后要备份保存好,否则一旦重新获取HAL库,修改都会被覆盖掉。
    3) 仅作参考。4.2的方法有空再实现。
    4) 相对来说4.1的改动最小,不用自己去写日期判断函数,去处理时间戳转换。
    5) 只有在上电和更新时间的时候会写RTC备份存储区。获取时间的时候只读,所以反复读取对寿命无影响。
    6) 参考程序:STM32CubeMX RTC配置 STM32 RTC时钟掉电日期不更新

STM32 RTC时钟掉电日期不更新 STM32 HAL库RTC时钟配置相关推荐

  1. STM32 RTC时钟掉电日期不更新

    RTC(Real-Time Clock)实时时钟,是一个独立的定时器.拥有一组连续计数的计数器,在相应软件配置下,可提供时钟日历的功能.修改计数器的值可以重新设置系统当前的时间和日期. RTC 模块和 ...

  2. 【STM32笔记】HAL库低功耗模式配置(ADC唤醒无法使用、低功耗模式无法烧录解决方案)

    [STM32笔记]HAL库低功耗模式配置(ADC唤醒无法使用.低功耗模式无法烧录解决方案) [STM32笔记]低功耗模式配置及避坑汇总 一.低功耗模式简介 系统提供了多个低功耗模式,可在 CPU 不需 ...

  3. stm32之实时时钟RTC(掉电计时保持、秒中断、闹钟中断、溢出中断)

    前言:stm32系列产品普遍都有实时时钟RTC模块,它提供一个掉电保持计时功能,掉电后由后备供电区域供电.除了提供时间和日期之外,还可以设置闹钟提醒,且可以在待机模式下设置闹钟唤醒系统.在一些小容量. ...

  4. 技能梳理7@stm32+OLED+flash掉电保存+按键

    学校违纪分数记录,按键,1.3寸OLED显示,数据掉电保存 1.项目简介 2.实现逻辑 #如上图为显示屏显示内容 #三个物理按键,一个是选择对哪一项进行控制,两个是加减对应项的分数 #控制范围±10, ...

  5. 03-STM32+Air724UG远程升级篇OTA(自建物联网平台)-STM32+Air724UG实现利用http/https远程更新STM32程序(TCP指令,单片机程序检查更新)

    说明 这节测试一下STM32+Air724UG实现利用http远程更新STM32程序 我已经把固件文件放在了自己的服务器上 默认使用本人提供的下载路径测试 文件路径:  网站根目录->ota-& ...

  6. STM32机器人控制开发教程No.1驱动电机(基于HAL库)

    01 前言 本教程使用的机器人控制板拥有4个带编码器的电机接口,4个舵机接口,串口通信接口.SWD下载调试接口.航模遥控接口.USB5V输出接口以及方便与树莓派直接连接的40PIN接口等,板载资源丰富 ...

  7. STM32F4 HAL库开发 --时钟使能和配置

    在STM32F4的HAL库中,外设时钟使能操作都是在RCC相关固件库文件头文件stm32f4xx_hal_rcc.h 定义的.外设时钟使能在HAL库中都是通过宏定义标识符来实现.首先,我们来看看GPI ...

  8. STM32驱动步进电机(最全的版本寄存器+HAL库实现)

    步进电机 1 简介 1.1 什么是步进电机 1.2 步进电机和直流电机区别 1.3 器材与配置 1.3.1 步进电机 1.3.2 驱动器 1.3.3 引脚 2 定时器的 3 驱动代码 3.1 初始化 ...

  9. 升级到 iOS 16 后掉电快?更新后手机发热怎么办?

    在刚刚结束的 WWDC 2022 全球开发者大会上,iOS 16 正式亮相.苹果发布iOS16正式版,不少用户都将系统升级到了最新版本,不过有些小伙伴们发现iOS16更新后似乎手机很容易发烫,电池健康 ...

最新文章

  1. 《30天吃掉那只 TensorFlow2.0 》(附下载)
  2. python中的List 和 Tuple
  3. maven 多模块项目:单独构建某个模块
  4. 软件测试行业有哪些细分方向,软件测试人员有哪些职业发展方向?
  5. 【渝粤题库】陕西师范大学292301 国际金融学Ⅱ 作业(专升本)
  6. ctr 平滑_CTR预估中的贝叶斯平滑方法及其代码实现
  7. oracle_导致实例逐出的五大问题
  8. 计算机专业的大专大学规划,大学生计算机专业职业规划个人简历
  9. 南方cass快捷键命令修改在哪_南方cass快捷键命令大全
  10. 软件测试——风险分析
  11. 代理服务器有问题怎么办?
  12. 阿里云免费服务器搭建个人博客
  13. hadoop安装作业
  14. 程序员跳槽频繁不稳定被质疑,一番话后HR哑口无言!
  15. 基于微型计算机系统的实时时钟设计,基于单片机的DS12C887时钟芯片应用研究
  16. “自然”语言编程(NLC)的到来比你想象的要快
  17. 赶集网CEO杨浩涌向搜狐IT确认
  18. DC/DC电路自举电容作用
  19. JVM介绍与知识脉络梳理
  20. excel导出access_将Access 2003报表导出到Excel电子表格中

热门文章

  1. ubuntu 运行QQ轻聊版7.9
  2. 最新cocos2d-x 3.0博客教学 小游戏[史上最坑爹的游戏] 002第一关:关闭卡死的电脑
  3. day7 Excel函数-动态函数
  4. Advertising on YouTube 如何在YouTube发布广告 Lynda课程中文字幕
  5. 电脑充电和电池保养的标准答案
  6. python爬取三国演义文本,统计三国演义中出场次数前30的人物,并生成词云、图表
  7. IT世界里爱恨交加的OpenStack
  8. 小型局域网络搭建(可访问外网)
  9. ai人工智能算法工程师_与AI时代息息相关:阿里巴巴算法工程师指南
  10. 新手必学:利用电影贴吧引流轻松变现