基础知识
介绍
RTC是STM32的一个独立定时器,在相应软件配置下可以实现时钟日历的功能。蓝桥杯对RTC主要考察他的时钟功能,具体可以参考嵌入式第九届的省赛题。对RTC的考察并不难,但也必须要掌握。
需要记住的是RTC和普通定时器不一样的地方:RTC模块和时钟配置系统是在后备区域,即在系统复位或从待机模式唤醒后,RTC的设置和时间维持不变。但在系统复位后会禁止访问后备寄存器和RTC,以防止对后备区域的意外操作,所以在设置RTC之前要去掉备份区域写保护。(这些内容在STM32参考手册都有些写,我希望大家能够熟练使用参考手册,无论做客观题还是主观题都是非常有用的!)
RTC配置步骤:
- 使能PWR和BKP时钟
- 使能后备寄存器访问
- 配置RTC时钟源并使能RTC时钟
- 配置RTC预分频系数
- 设置时间
- 开启相关中断
- 编写中断服务函数
- 注意:部分操作要等待写操作完成和同步
代码:
在RTC驱动文件中是下面这个:
#define HH 11 //时
#define MM 59 //分
#define SS 50 //秒
extern uint32_t TimeDisplay;//标志位,在产生秒中断时更新时间
void RTC_Config()
{
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR|RCC_APB1Periph_BKP,ENABLE);//使能PWR和BKP的时钟
PWR_BackupAccessCmd(ENABLE);//使能后备寄存器访问
BKP_DeInit();
RCC_LSICmd(ENABLE);//选择LSI为时钟
while (RCC_GetFlagStatus(RCC_FLAG_LSIRDY) == RESET);//等待LSI低速时钟准备就绪
RCC_RTCCLKConfig(RCC_RTCCLKSource_LSI);
RCC_RTCCLKCmd(ENABLE);
RTC_WaitForSynchro(); //等待同步
RTC_WaitForLastTask(); //等待写完成
RTC_ITConfig(RTC_IT_SEC, ENABLE);
RTC_WaitForLastTask();//等待写完成
/* Set RTC prescaler: set RTC period to 1sec */
RTC_SetPrescaler(39999); /* RTC period = RTCCLK/RTC_PR = (40 KHz)/(39999+1) */
RTC_WaitForLastTask();//等待写完成
RTC_SetCounter(HH*3600+MM*60+SS);//设置时间
RTC_WaitForLastTask();//等待写完成
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //中断分组1
NVIC_InitStructure.NVIC_IRQChannel = RTC_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
void Time_Display(u32 TimeVar)//LCD显示函数
{
char text[20];
u32 THH = 0, TMM = 0, TSS = 0;
/* Compute hours */
THH = TimeVar / 3600;
/* Compute minutes */
TMM = (TimeVar % 3600) / 60;
/* Compute seconds */
TSS = (TimeVar % 3600) % 60;
sprintf(text,"Time: %0.2d:%0.2d:%0.2d",THH, TMM, TSS);
LCD_DisplayStringLine(Line6,(u8 *)text);
}
void RTC_IRQHandler(void)//RTC的秒中断
{
if (RTC_GetITStatus(RTC_IT_SEC) != RESET)
{
RTC_ClearITPendingBit(RTC_IT_SEC);
TimeDisplay = 1; //时间更新标志置位
/* Wait until last write operation on RTC registers has finished */
RTC_WaitForLastTask();
/* 23:59:59 */
if (RTC_GetCounter() == 0x00015180)//写成24*3600也是可以的
{
RTC_SetCounter(0x0);
RTC_WaitForLastTask();
}
}
}
在主函数这样写:
while(1)
{
if(TimeDisplay == 1)//RTC计数器每加1s,会进入中断更新标志位,在主函数中便会显示当前计数器的值。
{
Time_Display(RTC_GetCounter());
TimeDisplay = 0; //清除标志位
}
}