赞
踩
RTC是一个独立的定时器,系统断电后仍然可以计时,配置其参数的寄存器RCC_BDCR是在后备区域,系统复位后,会自动禁止访问后备区域,所以在设置时间之前,要先取消备份区域(BKP)的写保护。
时钟源RTCCLK: 高速外部晶振的128分频,低速外部晶振,低速内部RC振荡器(一般不用它,时间不准)
RTC_PRL: RTC_PRL是预分频装载寄存器,用来配置RTC的分频数,其值可由软件设置。比如,使用外部的32.768K的晶振作为时钟输入,那么要设置它的值为32767,就可以得到一秒的计数频率。RTCCLK,RTC_PRL,TR_CLK的关系如下:
T
R
_
C
L
K
=
R
T
C
_
C
L
K
R
T
C
_
P
R
L
TR\_CLK=\dfrac{RTC\_CLK}{RTC\_PRL}
TR_CLK=RTC_PRLRTC_CLK
RTC_DIV 只读,RTC_DIV的初始值和RTC_PRL的值是相同的,其值在RTCCLK的时钟控制下减少(每一个RTCCLK脉冲就减1),而这个减少的过程是由硬件控制的。当其减少到0时,产生一个TR_CLK脉冲。并且在TR_CLK这个脉冲的作用下,再次被赋值为RTC_PRL的值。
TR_CLK RTC的时间基准,每个TR_CLK周期都可以产生一个秒中断。
RTC_CNT 32位可编程计数器,可以被初始化为当前时间。计数TR_CLK的脉冲数,当其值和RTC_ALR相等时,就会产生一个闹钟中断。
以上是RTC的核心部分,接下来是关于控制寄存器的介绍,需要注意的是,在配置控制寄存器之前,首先需要等待其同步标志位被硬件置1(RTC_CRL 寄存器的 RSF).
这是参考手册关于RTC_CRH的介绍,该寄存器用于控制中断。
以下是参考手册关于RTC_CRL的介绍。
这里介绍0、3~5这几个位。
第0位是秒钟标志位,进入闹钟中断的时候,由这个位来判断是否发生了秒钟中断,然后必须通过软件将该位清零。
第3位RSF是寄存器同步标志位,在修改控制寄存器之前,必须先通过该位来判断是否已经同步,如果没有同步则不能修改控制寄存器RTC_CRH/CRL的值
第4位是配置标位,软件修改计数器值RTC_CNT、闹钟值RTC_ALR,预分频值RTC_PRL的时候,必须先用软件配置该位,以允许进入配置模式
第5位RCOFF,用于判断上一次的写操作是否完成,如果未完成,则不能进行下一次的写操作。
RTC_PRLH和RTC_PRLL 预分频值存在这两个寄存器中,其中,RTC_PRLL存储低16位,RTC_PRLH存储高4位,总共20位。
RCC_BDCR寄存器
RTC的时钟源选择、使能设置都是通过该寄存器实现的。在RTC操作之前,先要通过该寄存器选择RTC时钟源,然后才能开始其它操作。
重点:库函数配置RTC步骤
需要用到的文件:stm32f10x_rtc.c 和 stm32f10x_rtc.h,为RTC相关,stm32f10x_bkp.c 和文件 stm32f10x_bkp.h为BKP相关
1:使能电源时钟和备份区时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);
2:取消备份区写保护
每次硬复位后都会使能写保护,取消写保护才能访问RTC和后备寄存器
PWR_BackupAccessCmd(ENABLE); //使能 RTC 和后备寄存器访问
3:复位备份区域
BKP_DeInit();//复位备份区域
4:开启外部低速振荡器
RCC_LSEConfig(RCC_LSE_ON);// 开启外部低速振荡器
5:RTC时钟源设置
RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE); //选择 LSE 作为 RTC 时钟
RCC_RTCCLKCmd(ENABLE); //使能 RTC 时钟
对于 RTC 时钟的选择,还有 RCC_RTCCLKSource_LSI 和 RCC_RTCCLKSource_HSE_Div128两个,顾名思义,前者为 LSI,后者为 HSE 的 128 分频
6:设置RTC的分频,配置RTC时钟
注意,这里仅仅介绍需要用到的库函数,具体的使用见后文的完整配置代码
在进行配置前,打开允许配置位(CNF)
RTC_EnterConfigMode();/// 允许配置
设置 RTC 时钟分频数。这个函数只有一个入口参数,就是 RTC 时钟的分频数,很好理解。
void RTC_SetPrescaler(uint32_t PrescalerValue);
RTC使能中断函数:
void RTC_ITConfig(uint16_t RTC_IT, FunctionalState NewState);
使能秒中断
RTC_ITConfig(RTC_IT_SEC, ENABLE); //使能 RTC 秒中断
设置RTC的计数值,也就是RTC_CNT。注意,这也就是设置时间,时间和计数值是需要换算的。
void RTC_SetCounter(uint32_t CounterValue)
更新配置同时退出配置模式
RTC_ExitConfigMode();//退出配置模式,更新配置
在退出配置模式更新配置之后我们在备份区域 BKP_DR1 中写入 0X5050 代表我们已经初始化过时钟了,下次开机(或复位)的时候,先读取 BKP_DR1 的值,然后判断是否是0X5050 来决定是不是要配置。接着我们配置 RTC 的秒钟中断,并进行分组。
往备份区域写用户数据的函数是:
void BKP_WriteBackupRegister(uint16_t BKP_DR, uint16_t Data);
这个函数的第一个参数就是寄存器的标号了,这个是通过宏定义定义的。比如我们要往BKP_DR1 写入 0x5050,方法是:
BKP_WriteBackupRegister(BKP_DR1, 0X5050);
同时,有写便有读,读取备份区域指定寄存器的用户数据的函数是:
uint16_t BKP_ReadBackupRegister(uint16_t BKP_DR);
最后需要调用NVIC_Init函数进行中断分组,并且编写中断服务函数
static void RTC_NVIC_Config(void) { NVIC_InitTypeDef NVIC_InitStructure; NVIC_InitStructure.NVIC_IRQChannel = RTC_IRQn;//RTC全局中断 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器 } u8 RTC_Init(void) { u8 temp=0;//计数变量,用于判断外部晶振是否有问题 RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE); //使能PWR和BKP时钟 PWR_BackupAccessCmd(ENABLE); //使能后备寄存器访问 if (BKP_ReadBackupRegister(BKP_DR1) != 0x5050) //如果需要重新配置以下值,需要将5050修改成任意其它四位数字 { BKP_DeInit(); //复位备份区域 RCC_LSEConfig(RCC_LSE_ON); //设置外部低速晶振 while (RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET) //检查指定的RCC标志位是否设置,等待低速晶振就绪 { temp++; delay_ms(10); } if(temp>=250)return 1;//初始化晶振失败,晶振有问题 RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE); //设置RTC时钟(RTCCLK),选择LSE作为RTC时钟 RCC_RTCCLKCmd(ENABLE); //使能RTC时钟 RTC_WaitForLastTask(); //等待最近一次RTC寄存器写操作完成 RTC_WaitForSynchro(); //等待RTC寄存器同步 RTC_ITConfig(RTC_IT_SEC, ENABLE); //使能RTC秒中断 RTC_WaitForLastTask(); //等待最近一次对RTC寄存器的写操作完成 RTC_EnterConfigMode();//允许配置 //RTC_SetPrescaler(32767); //设置RTC预分频值,中断时间为1s RTC_SetPrescaler(3277);//根据自己的需要将中断时间修改为0.1s RTC_WaitForLastTask(); //等待最近一次对RTC寄存器的写操作完成 RTC_SetCounter(100); //设置RTC计数器的初始值(这里随便设置的,这里对我来说并不重要) RTC_ExitConfigMode(); //退出配置模式 BKP_WriteBackupRegister(BKP_DR1, 0X5050);//向指定后备寄存器中写入用户程序数据 } else//系统继续计时 { RTC_WaitForSynchro(); RTC_ITConfig(RTC_IT_SEC, ENABLE); //使能RTC秒中断 RTC_WaitForLastTask(); } RTC_NVIC_Config();//RTC中断分组的设置 return 0; //ok }
需要把stm32f10x_rtc.c, stm32f10x_bkp.c, 这两个文件加进来,还需要stm32f10x_pwr.c,否则就会出现下面的报错。
也就是说,如果要使用rtc,就需要添加上面的三个文件,如果出现如图类似的报错,说明是少了文件。
这里解释一下pwr,使用rtc需要用到后备寄存器,pwr和后备寄存器的访问控制有关,例如下面这个函数
Reference:
链接: STM32-RTC时钟学习笔记
链接: STM32的RTC时钟及其相关寄存器
链接: STM32F10x_PWR
正点原子的《STM32不完全手册_库函数版本》
《STM32中文参考手册》
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。