目录
[32.768HZ 如何产生1S定时](#32.768HZ 如何产生1S定时)
背景
通过本篇文章对常用的RTC时钟(实时时钟)进行说明. 以及了解如何通过程序来区分上电复位和管脚复位。
**RTC(实时时钟)**和后备寄存器
RTC 和后备寄存器通过一个开关供电,在 V DD 有效时该开关选择 V DD 供电,否则由 V BAT 引脚供电。后 备寄存器(10 个 16 位的寄存器 ) 可以用于在关闭 V DD 时,保存 20 个字节的用户应用数据。 RTC 和后备寄 存器不会被系统或电源复位源复位;当从待机模式唤醒时,也不会被复位。
实时时钟具有一组连续运行的计数器,可以通过适当的软件提供日历时钟功能,还具有闹钟中断和
阶段性中断功能。 RTC 的驱动时钟可以是一个使用外部晶体的 32.768kHz 的振荡器、内部低功耗 RC 振荡器或高速的外部时钟经128 分频。内部低功耗 RC 振荡器的典型频率为 40kHz 。为补偿天然晶体的偏差,可以通过输出一个512Hz的信号对RTC的时钟进行校准。RTC具有一个32位的可编程计数器, 使用比较寄存器可以进行长时间的测量。有一个20 位的预分频器用于时基时钟,默认情况下时钟为 32.768kHz时,它将产生一个 1 秒长的时间基准。
RTC晶振 (LSE:外部低速时钟):32.768KHZ
STM32单片机内部集成了一个40KHZ的RC振荡器,内部RC振荡器会会因为温度产生漂移,精度不够高,因此使用32.768HZ的LSE作为RTC的时钟源。RTC备用电池,在单片机主电源断开的时候,给RTC时钟供电,也可以用于保存备用存储器中的数据(计时器的时间值,以及用户临时存放的数据),备用寄存器 20字节保存用户数据
32.768HZ 如何产生1S定时信号
32.768KHZ的时钟晶振产生的振荡信号经过石英钟内部 分频器进行15次分频( 2的15次方就是32768 )后得到1HZ秒信号,即秒针每秒钟走一下,石英钟内部分频器只能进行 15 次分频 , 要是换成别的频率的晶振(比如说STM32中的内部RC振荡器40KHZ),15次分频后就不是1HZ的秒信号,时钟就不准了。32.768K=32768=2的15次方,数据转换比较方便、精确。
1970-01-01主要是因为这是Unix时间戳的起点。Unix时间戳是从1970年1月1日开始计算的秒数,被广泛用于计算机系统中以表示和记录时间.
RTC配置程序
RTC的配置有两种情况:
1)第一次上电
2)非第一次上电,且备用电池有电情况。
第一次上电RTC配置
void RTC_First_Config(void){ //首次启用RTC的设置
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);//启用PWR和BKP的时钟(from APB1)
PWR_BackupAccessCmd(ENABLE);//后备域解锁
BKP_DeInit();//备份寄存器模块复位
RCC_LSEConfig(RCC_LSE_ON);//外部32.768KHZ晶振开启
while (RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET);//等待稳定
RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);//RTC时钟源配置成LSE(外部低速晶振32.768KHZ)
RCC_RTCCLKCmd(ENABLE);//RTC开启
RTC_WaitForSynchro();//开启后需要等待APB1时钟与RTC时钟同步,才能读写寄存器
RTC_WaitForLastTask();//读写寄存器前,要确定上一个操作已经结束
RTC_SetPrescaler(32767);//设置RTC分频器,使RTC时钟为1Hz,RTC period = RTCCLK/RTC_PR = (32.768 KHz)/(32767+1)
RTC_WaitForLastTask();//等待寄存器写入完成
//当不使用RTC秒中断,可以屏蔽下面2条
// RTC_ITConfig(RTC_IT_SEC, ENABLE);//使能秒中断
// RTC_WaitForLastTask();//等待写入完成
}
第1步、启用备用寄存器外设时钟和PWR外设时钟
通过stm32的数据手册可以知道RTC需要是能APB1
RCC_APB1Periph_PWR
**主要用于控制电源管理单元(Power Control Unit,简称PWR)的时钟使能。**
在STM32中,RCC(复位和时钟控制)模块负责管理微控制器的时钟树和外设的晶振、内部振荡器以及各种时钟源的分频和倍频。具体到RCC_APB1Periph_PWR ,它是APB1总线上的一个外设,用于控制电源管理单元(PWR)的时钟使能。通过使能或失能PWR的时钟,可以控制电源管理功能的工作状态,进而影响整个系统的功耗管理。
![](https://i-blog.csdnimg.cn/direct/517d58c2852a4cd0b682c990515e60c3.png)
![](https://i-blog.csdnimg.cn/direct/bae427cd401a429ebb35b56eaf0e1234.png)
LSE作为RTC时钟源之后,即使VDD断电,仍然可以通过RTC纽扣电池(备用电池)使得RTC外设继续工作。因此要启用PWR外设的时钟!
RCC_APB1Periph_BKP
是和后备存储器相关
![](https://i-blog.csdnimg.cn/direct/27ec8b792fb04481aabb333d0581fdda.png)
第2步、使能RTC和备份寄存器访问
后面需要对RTC进行分频设置和备份寄存器初始化!
![](https://i-blog.csdnimg.cn/direct/8d2ae38f8b5143b292f3fca894e3d10c.png)
第3步、备份寄存器初始化
![](https://i-blog.csdnimg.cn/direct/c35cfd7224cd4b2fa2badf08dfbfeddf.png)
第4步、开启LSE
![](https://i-blog.csdnimg.cn/direct/8efcbedd79be49d2973c6166de12e62a.png)
第5步、等待LSE启动后稳定状态
![](https://i-blog.csdnimg.cn/direct/0747580f2f4f4811ac87f50ca9d243a8.png)
![](https://i-blog.csdnimg.cn/direct/2876626a53a74167be33b121da095d6f.png)
![](https://i-blog.csdnimg.cn/direct/e1ebc6e704ce4ad28e5cb9bd4d68fdf7.png)
第6步、配置LSE为RTC时钟源
![](https://i-blog.csdnimg.cn/direct/60b8d4d069524b6fb52d5d06a203ef41.png)
stm32数据手册中的时钟树可以RTC的时钟源有三个
1)LSE
- LSI(40khz)
3)HSE的128分频
![](https://i-blog.csdnimg.cn/direct/c9703e826bc54daebdf7ae5672348223.png)
第7步、使能RTC时钟
![](https://i-blog.csdnimg.cn/direct/30732bad775f40cbb354eb7533f3d21c.png)
第8步、设置RTC预分频
1)等待 RTC 寄存器(RTC_CNT, RTC_ALR and RTC_PRL)与 RTC 的 APB 时钟同步
2)等待上一次rtc寄存器写操作完成
3)设置预分频
4)等待rtc寄存器写完成
![](https://i-blog.csdnimg.cn/direct/8e72f1648b844b2293eafc2c78ef1f18.png)
![](https://i-blog.csdnimg.cn/direct/29bdb647b20e4ed68c6d90c48ce0fc74.png)
![](https://i-blog.csdnimg.cn/direct/8bdbc1c68f3f43f2869826e66f4e9f5c.png)
固件库函数具体实现(ST公司提供)
![](https://i-blog.csdnimg.cn/direct/67f3c8ef576a465a9804ffc92bfcae02.png)
![](https://i-blog.csdnimg.cn/direct/20c8e61c07ac428b8c0111d78c736cdb.png)
![](https://i-blog.csdnimg.cn/direct/84e6a33d26f541dda0404a9153872a3c.png)
![](https://i-blog.csdnimg.cn/direct/3e8194614f3e433d9b3f88db9e680536.png)
所以要特别注意实际上的预分频数为设置值+1
第9步、设置秒中断
![](https://i-blog.csdnimg.cn/direct/fddd4df6392441318882ed653ef494af.png)
第10步、秒中断函数封装
void RTC_IRQHandler(void){ //RTC时钟1秒触发中断函数(名称固定不可修改)
if (RTC_GetITStatus(RTC_IT_SEC) != RESET){
}
RTC_ClearITPendingBit(RTC_IT_SEC);
RTC_WaitForLastTask();
}
RTC配置程序(用于main函数调用)
![](https://i-blog.csdnimg.cn/direct/8cc111a791334b558324a47e665dc5b6.png)
void RTC_Config(void){ //实时时钟初始化
//在BKP的后备寄存器1中,存了一个特殊字符0xA5A5
//第一次上电或后备电源掉电后,该寄存器数据丢失,表明RTC数据丢失,需要重新配置
if (BKP_ReadBackupRegister(BKP_DR1) != 0xA5A5){//判断寄存数据是否丢失
RTC_First_Config();//重新配置RTC
BKP_WriteBackupRegister(BKP_DR1, 0xA5A5);//配置完成后,向后备寄存器中写特殊字符0xA5A5
}else{
//若后备寄存器没有掉电,则无需重新配置RTC
//这里我们可以利用RCC_GetFlagStatus()函数查看本次复位类型
if (RCC_GetFlagStatus(RCC_FLAG_PORRST) != RESET){
//这是上电复位
}
else if (RCC_GetFlagStatus(RCC_FLAG_PINRST) != RESET){
//这是外部RST管脚复位
}
RCC_ClearFlag();//清除RCC中复位标志
//虽然RTC模块不需要重新配置,且掉电后依靠后备电池依然运行
//但是每次上电后,还是要使能RTCCLK
RCC_RTCCLKCmd(ENABLE);//使能RTCCLK
RTC_WaitForSynchro();//等待RTC时钟与APB1时钟同步
//当不使用RTC秒中断,可以屏蔽下面2条
// RTC_ITConfig(RTC_IT_SEC, ENABLE);//使能秒中断
// RTC_WaitForLastTask();//等待操作完成
}
}
![](https://i-blog.csdnimg.cn/direct/8b7d99be8978440cb6f68de611f02956.png)
![](https://i-blog.csdnimg.cn/direct/b33403a04bbe42418f70193fcc32de8f.png)
![](https://i-blog.csdnimg.cn/direct/48678066ba8c437fb2d2b65dae0e64f8.png)
可用的部分是前面的10个,以为备份寄存器为20个字节。
RCC_FLAG_PORRST就是上电复位、RCC_FLAG_PINRST管脚复位
![](https://i-blog.csdnimg.cn/direct/9bc0adb494b34c4fbe349671524450e1.png)
![](https://i-blog.csdnimg.cn/direct/e47e488975d046a0a50132587a6c3e0a.png)