总结stm32中RTC和BKP的一些知识
RTC前置知识
UNIX时间戳
两种标准时间
闰秒:从上图可以知道,在UTC设置的9192631770
周所用的时间和GMT标准中的1970-1-1-0-0-0
一致的。但是由于地球自转速度越来越慢,所以需要通过差一个闰秒来解决这个问题。
C语言中的时间库
BKP简介
这个BKP实际上就是一组寄存器(备份数据寄存器x(BKP_DRx) (x = 1 … 10) ),用于保存数据。其可以电源的来源有VDD
引脚和VBAT
引脚。当VDD
没有电的时候就会换到VBAT
引脚,有电的时候就会使用VDD
的电源,以减少对于VBAT
电源的消耗。
需要注意的是,TANPER
引脚;RTC引脚输出RTC校准时钟、闹钟脉冲、秒脉冲;存储RTC时钟校准寄存器这个三个功能是不常用的功能,最常用的是存储应用数据。
BKP基本结构
BKP相关函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| void BKP_DeInit(void); 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); void BKP_WriteBackupRegister(uint16_t BKP_DR, uint16_t Data); uint16_t BKP_ReadBackupRegister(uint16_t BKP_DR);
FlagStatus BKP_GetFlagStatus(void); void BKP_ClearFlag(void); ITStatus BKP_GetITStatus(void); void BKP_ClearITPendingBit(void);
|
RTC简介
STM32的RTC外设(Real Time Clock),实质是一个掉电后还继续运行的定时器。
从定时器的角度来说,相对于通用定时器TIM外设,它十分简单,只有很纯粹的计时和触发中断的功能;但从掉电还继续运行的角度来说,它却是STM32中唯一一个具有如此强大功能的外设。 所以RTC外设的复杂之处并不在于它的定时功能,而在于它掉电还继续运行的特性。
RTC基本结构
上图中灰色的区域是备份区域,也就是说这个范围内的寄存器中的值可以被BKP所保存。
余数寄存器是一个自减计数器
可以看到这个图中只有一个32位的计数器,这是由于stm32使用的是前面记载的秒计数器来记录时间的。需要使用的时候通过C语言中的time.h中的函数来进行转换。time()
函数在stm32中不可以使用,因为stm32是一个脱网的系统。
只有三个中断可以触发后面的控制寄存器,分别是:
- Second:秒中断
- Overflow:溢出中断,由于stm32的计数器是一个无符号数,所以unix时间戳会在2^32次方-1秒后溢出,2106年。
- Alarm:闹钟中断
其中的定时器溢出事件无法被配置为中断。 若STM32原本处于待机状态,可由闹钟事件或WKUP事件(外部唤醒事件,属于EXTI模块,不属于RTC)使它退出待机模式。 闹钟事件是在计数器RTC_CNT的值等于闹钟寄存器RTC_ALR的值时触发的。
时钟源的选择
根据RCC时钟树,可以看到RTC可以选择三种时钟源。一般我们都是使用LSE OSC
这个时钟源,也就是32.768khz
的这个。这个大小的时钟源一般都是用于RTC这个外设的。所以我们之后看到这个大小的时钟就应该要知道这很有可能是提供给RTC外设的。
但是这还不是最重要的,最重要的是只有中间这个时钟源才支持VBAT
引脚,其他的两个都没有这个引脚可以使用,所以要达到要求只有使用中间这个时钟源。
RTC相关函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| void RTC_ITConfig(uint16_t RTC_IT, FunctionalState NewState); void RTC_EnterConfigMode(void); void RTC_ExitConfigMode(void); uint32_t RTC_GetCounter(void); void RTC_SetCounter(uint32_t CounterValue); void RTC_SetPrescaler(uint32_t PrescalerValue); void RTC_SetAlarm(uint32_t AlarmValue); uint32_t RTC_GetDivider(void); 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);
|
注意事项
- 在每一次使用了更改RTC_PRL、RTC_CNT、RTC_ALR寄存器的值的函数时,必须要在后面调用函数
RTC_WaitForLastTask()
- a
实例:实际顺序就是根据上面的RTC基本结构的第一幅图来的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE); RCC_APB1PeriphClockCmd(RCC_APB1Periph_BKP, ENABLE);
PWR_BackupAccessCmd(ENABLE);
if (BKP_ReadBackupRegister(BKP_DR1) != 0xA5A5) { RCC_LSEConfig(RCC_LSE_ON); while (RCC_GetFlagStatus(RCC_FLAG_LSERDY) != SET); RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE); RCC_RTCCLKCmd(ENABLE); RTC_WaitForSynchro(); RTC_WaitForLastTask(); RTC_SetPrescaler(32768 - 1); RTC_WaitForLastTask(); MyRTC_SetTime(); BKP_WriteBackupRegister(BKP_DR1, 0xA5A5); } else { RTC_WaitForSynchro(); RTC_WaitForLastTask(); }
|