STM32中的RTC/BKP模块详解

一、Unix时间戳

1.1 Unix简介

  • Unix 时间戳(Unix Timestamp):定义为从UTC/GMT的1970年1月1日0时0分0秒开始所经过的秒数,不考虑闰秒。
  • GMT:格林尼治标准时间(以地球自转为标准);UTC:协调时间时间(以原子钟为标准)
  • 闰秒:UTC和GMT偏差超过0.9s时,UTC执行闰秒。
  • 时间戳存储在一个秒计数器中,秒计数器为32位/64位的整型变量,不进位。
  • 世界上所有时区的秒计数器相同,不同时区通过添加偏移来得到当地时间。
  • 1.2 time.h标准库

  • C语言的time.h模块提供了时间获取和时间戳转换的相关函数,可以方便地进行秒计数器、日期时间和字符串之间的转换。

  • time_t实际是32/64位的整型数据;struct_tm实际是封装的整型结构体;

  • 二、BKP

    2.1 BKP简介

  • BKP(Backup Registers)备份寄存器,用于存储用户应用程序数据
  • 特性:BKP本质上位RAM存储器,但当VDD(2.0-3.6V)电源被切断,他们仍然由备用电源VBAT(1.8-3.6V)维持供电。当系统在待机模式下被唤醒,或系统复位或电源复位时,他们也不会被复位
  • 防拆功能:BKP的TAMPER引脚产生的侵入事件会将所有备份寄存器内容清除。
  • 时钟输出功能:BKP的RTC引脚可以输出RTC校准时钟、RTC闹钟脉冲或者秒脉冲。
  • 时钟误差校准功能:有RTC时钟校准寄存器
  • 用户数据存储容量:20字节(中容量和小容量)/ 84字节(大容量和互联型)
  • 2.2 BKP基本结构

  • 图中橙色部分位于STM32的后备区域,VDD主电源掉电时,后备区域会由备用电源VBAT维持供电。

  • 三、RTC

    3.1 RTC简介

  • RTC(Real Time Clock)实时时钟,是一个独立的定时器,可为系统提供时钟和日历的功能。

  • RTC和时钟配置系统处于后备区域,系统复位时数据不清零,VDD(2.0-3.6V)断电后可借助VBAT(1.8-3.6V)维持供电继续走时。

  • STM32的RTC外设内置32位的可编程计数器,可对应Unix时间戳的秒计数器。

  • STM32的RTC外设拥有20位的可编程预分频器,可适配不同频率的输入时钟。

  • 可选择三种RTC时钟源:

  • HSE时钟除以128(通常为8MHz/128),高速外部时钟
  • LSE振荡器时钟(通常为32.768KHz),低速外部时钟(最常用于RTC)
  • LSI振荡器时钟(40KHz),低速内部时钟
  • 内部时钟由RC电路产生;外部时钟由外置晶振产生,更准确。

    3.2 RTC基本结构


  • 时钟信号接RTCCLK,通向预分频器。
  • 预分频器分频出每秒一次的信号传给计数器。
  • 计数器CNT每秒自增实现Unix时间(秒时间)。
  • ALR闹钟寄存器可以设置时钟闹钟,在ALR=CNT时,可进中断,可唤醒芯片。
  • 有三种信号可以进中断
  • Second:秒中断,每秒进一次中断。
  • Overflow:溢出中断,CNT溢出时进中断,32位CNT溢出要等到2106年。
  • Alarm:闹钟中断,闹钟时间到,ALR=CNT时进中断。
  • 3.3 RTC操作注意事项

  • 执行以下操作将使能对BKP和RTC的访问:
  • 设置RCC_APB1ENR的PWREN和BKPEN,使能PWR和BKP时钟
  • 设置PWR_CR的DBP,使能对BKP和RTC的访问
  • 若在读取RTC寄存器时,RTC的APB1接口曾经处于禁止状态,则软件首先必须等待RTC_CRL寄存器中的RSF位(寄存器同步标志)被硬件置1
  • 必须设置RTC_CRL寄存器中的CNF位,使RTC进入配置模式后,才能写入RTC_PRL、RTC_CNT、RTC_ALR寄存器
  • 对RTC任何寄存器的写操作,都必须在前一次写操作结束后进行。可以通过查询RTC_CR寄存器中的RTOFF状态位,判断RTC寄存器是否处于更新中。仅当RTOFF状态位是1时,才可以写入RTC寄存器
  • 省流

  • 用之前,要先开启PWR和BKP的时钟,以及使能访问。
  • 上电后,要先等待同步。
  • 配置模式,不管
  • 每次写之前需要先等待上次写完。

  • 四、配置BKP/RTC

    读写BKP

    '1. BKP初始化'
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_BKP, ENABLE);
    PWR_BackupAccessCmd(ENABLE);
    '2. 写BKP'
    BKP_WriteBackupRegister(BKP_DR1, 0x1234);	// 小容量产品有BKP_DR1-10
    '3. 读BKP'
    Data = BKP_ReadBackupRegister(BKP_DR1);
    

    初始化RTC

    '1. 开启PWR和BKP时钟,且PWR使能'
    // 与BKP初始化相同
    '2. 开启RTC的时钟,此处使用LSE'
    RCC_LSEConfig(LSE_ON);				// 来自rcc.h
    while (RCC_GetFlagStatus()!=SET);	// 等待LSE开启完成,来自rcc.h
    '3. 配置RTCCLK数据选择器,选择LSE时钟源'
    RCC_RTCCLKConfig(LSE);				// 选择时钟源,来自rcc.h
    RCC_RTCCLKCmd(ENABLE);				// 使能时钟,来自rcc.h
    '4. 等待同步,等待上一次操作完成'
    RTC_WaitForSynchro();
    RTC_WaitForLastTask();
    '5. 配置预分频器, 保证CNT一秒一跳'
    RTC_SetPrescaler(32768-1);			// LSE是32768HZ
    RTC_WaitForLastTask();				// 等待操作完成
    '6. 配置CNT初始值'
    RTC_SetCounter(114514);
    RTC_WaitForLastTask();	
    '7. 按需配置闹钟、中断'
    
    '补充:RTC初始化完成,可以读取RTC的值获取Unix时间'
    RTC_GetCounter();
    '补充:可以根据需求编写函数,实现读取/写入北京时间等操作'
    
    '实现RTC时钟上下电不重置,可以借助BKP制造一个初始化标志位,若RTC已经初始化过则不需要重新初始化。'
    

    五、常用库函数

    BKP

    void BKP_DeInit(void);
    		// BKP复位函数,用于手动清空BKP所有数据
    void BKP_WriteBackupRegister(uint16_t BKP_DR, uint16_t Data);
    		// 写BKP
    uint16_t BKP_ReadBackupRegister(uint16_t BKP_DR);
    		// 读BKP
    // 下面五个小功能,用的不多
    void BKP_TamperPinLevelConfig(uint16_t BKP_TamperPinLevel);
    		// 配置侵入检测功能(高低电平)
    void BKP_TamperPinCmd(FunctionalState NewState);
    		// 侵入检测功能使能
    void BKP_ITConfig(FunctionalState NewState);
    		// 中断使能
    void BKP_RTCOutputConfig(uint16_t BKP_RTCOutputSource);
    		// 配置时钟输出功能
    void BKP_SetRTCCalibrationValue(uint8_t CalibrationValue);
    		// 设置RTC校准值
    
    FlagStatus BKP_GetFlagStatus(void);
    		// 获取标志位
    void BKP_ClearFlag(void);
    		// 清除标志位
    ITStatus BKP_GetITStatus(void);
    		// 获取中断标志位
    void BKP_ClearITPendingBit(void);
    		// 清除中断标志位
    

    RTC

    void RTC_ITConfig(uint16_t RTC_IT, FunctionalState NewState);
    		// 中断配置
    void RTC_EnterConfigMode(void);
    		// 进入配置模式,各库函数都有进入配置模式的代码,不需要单独执行
    void RTC_ExitConfigMode(void);
    		// 退出配置模式,同上
    uint32_t  RTC_GetCounter(void);
    		// 获取CNT的值,读取时间
    void RTC_SetCounter(uint32_t CounterValue);
    		// 写入CNT的值,用于写入CNT初值
    void RTC_SetPrescaler(uint32_t PrescalerValue);
    		// 配置分频器
    void RTC_SetAlarm(uint32_t AlarmValue);
    		// 配置闹钟值
    uint32_t  RTC_GetDivider(void);
    		// 获取余数寄存器DIV的值
    void RTC_WaitForLastTask(void);
    		// 等待上次写入操作完成
    void RTC_WaitForSynchro(void);
    		// 等待同步
    FlagStatus RTC_GetFlagStatus(uint16_t RTC_FLAG);
    		// 获取标志位
    void RTC_ClearFlag(uint16_t RTC_FLAG);
    		// 清除标志位
    ITStatus RTC_GetITStatus(uint16_t RTC_IT);
    		// 获取中断标志位
    void RTC_ClearITPendingBit(uint16_t RTC_IT);
    		// 清除中断标志位
    

    六、补充


    Reference
    STM32入门教程-2023版(江科大)

    物联沃分享整理
    物联沃-IOTWORD物联网 » STM32中的RTC/BKP模块详解

    发表评论