STM32 RTC 功能详解与代码示例
本文主要讲解如何在 STM32F405RG单片机上实现实时时钟(RTC)的功能,包括初始化 RTC、设置时间和日期、配置唤醒和闹钟中断等内容,并结合示例代码进行详细说明。
一、RTC 简介
RTC是一种独立于主 MCU 工作的时钟模块,能够在主芯片掉电时通过电池供电继续计时,非常适合需要记录时间的应用场景,例如定时任务、计时器、唤醒功能等。
STM32 的 RTC 模块支持:
二、RTC 初始化
初始化代码
以下是 RTC 初始化的代码
#define Access 0xf00
void rtc_Init(void)
{
RTC_InitTypeDef RTC_InitSturcture;
//允许访问
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
PWR_BackupAccessCmd(ENABLE); //启用备份存储区
//设置时间标志位,不用每次设置
if(RTC_ReadBackupRegister(RTC_BKP_DR0)!=Access)
{
RCC_LSEConfig(RCC_LSE_ON);//外部低速时钟
while (RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET){} // 等待LSE准备好
// 设置 RTC 时钟源为 LSE
RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);
RCC_RTCCLKCmd(ENABLE);
RTC_StructInit(&RTC_InitSturcture);// 初始化结构体
RTC_InitSturcture.RTC_AsynchPrediv = 127; // 异步预分频值 32768/128 = 256
RTC_InitSturcture.RTC_SynchPrediv = 255; // 同步预分频值
RTC_InitSturcture.RTC_HourFormat = RTC_HourFormat_24;
RTC_Init(&RTC_InitSturcture);
rtc_SetDateTime(24,11,26,2,9,10,30);
RTC_WriteBackupRegister(RTC_BKP_DR0,Access);
}
}
代码解析
- 备份寄存器访问:
- 通过
PWR_BackupAccessCmd(ENABLE)
允许对 RTC 和备份寄存器的访问。 - 时钟源配置:
- 使用外部低速晶振 (LSE) 作为 RTC 的时钟源,保证时间精度。
- 预分频设置:
- 异步预分频为 127,同步预分频为 255,实现 1 秒的计时周期。
- 时间初始化:
- 设置初始时间为 2024 年 11 月 26 日 09:10:30。
三、时间和日期设置
使用以下函数可以方便地设置 RTC 的时间和日期:
/*设置日期和时间 年月日 星期 时分秒 */
void rtc_SetDateTime(uint8_t year, uint8_t month, uint8_t date, uint8_t weekday,uint8_t hours,uint8_t minutes,uint8_t seconds)
{
RTC_DateTypeDef RTC_DateStructure;
RTC_TimeTypeDef RTC_TimeStructure;
RTC_DateStructure.RTC_Year = year;
RTC_DateStructure.RTC_Month = month;
RTC_DateStructure.RTC_Date = date;
RTC_DateStructure.RTC_WeekDay = weekday;
RTC_TimeStructure.RTC_Hours = hours;
RTC_TimeStructure.RTC_Minutes = minutes;
RTC_TimeStructure.RTC_Seconds = seconds;
RTC_TimeStructure.RTC_H12 = RTC_H12_AM; //24小时
RTC_SetTime(RTC_Format_BIN,&RTC_TimeStructure);
RTC_SetDate(RTC_Format_BIN, &RTC_DateStructure);
}
// 设置时间函数
void rtc_SeTime(uint8_t hours,uint8_t minutes,uint8_t seconds)
{
RTC_TimeTypeDef RTC_TimeStructure;
RTC_TimeStructure.RTC_Hours = hours;
RTC_TimeStructure.RTC_Minutes = minutes;
RTC_TimeStructure.RTC_Seconds = seconds;
RTC_TimeStructure.RTC_H12 = RTC_H12_AM; //24小时
RTC_SetTime(RTC_Format_BIN,&RTC_TimeStructure);
}
四、RTC 唤醒功能
RTC 的唤醒功能可以定期唤醒 MCU,适用于低功耗应用。
唤醒初始化
//设置唤醒
void WKUP_init(uint32_t WUCKSEL,uint32_t CNT)
{
u32 timeout;
NVIC_InitTypeDef NVIC_InitStruct={0};
EXTI_InitTypeDef EXTI_InitStruct={0};
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG,ENABLE);//开启线时钟
RTC_WakeUpCmd(DISABLE);//关闭定时器
while(RTC_GetFlagStatus(RTC_FLAG_WUTF)==RESET&&timeout<100)// 准备就绪
{
timeout++;
delay_ms(10);
}
RTC_ClearFlag(RTC_FLAG_WUTF);
RTC_WakeUpClockConfig(WUCKSEL);//最大计时18小时 一般16位
RTC_SetWakeUpCounter(CNT-1);
//EXTI_ClearITPendingBit(RTC_IT_WUT);
EXTI_ClearITPendingBit(EXTI_Line22);//清0 线22
EXTI_InitStruct.EXTI_LineCmd = ENABLE;//使能线
EXTI_InitStruct.EXTI_Line = EXTI_Line22;
EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Rising;//上升沿有效
EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_Init(&EXTI_InitStruct);
NVIC_InitStruct.NVIC_IRQChannel= RTC_WKUP_IRQn; //开启唤醒中断
NVIC_InitStruct.NVIC_IRQChannelCmd=ENABLE;//使能
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=1; //抢占
NVIC_InitStruct.NVIC_IRQChannelSubPriority=1; //响应
NVIC_Init(&NVIC_InitStruct);
RTC_ITConfig(RTC_IT_WUT,ENABLE);//开启唤醒中断
RTC_WakeUpCmd(ENABLE);
}
唤醒中断处理
RTC_TimeTypeDef RTC_Time={0};
//设置唤醒中断
void RTC_WKUP_IRQHandler(void)
{
if(RTC_GetITStatus(RTC_IT_WUT)==SET)
{
RTC_GetTime(RTC_Format_BIN,&RTC_Time);
}
RTC_ClearITPendingBit(RTC_IT_WUT);
EXTI_ClearITPendingBit(EXTI_Line22);
}
五、闹钟功能
RTC 支持两个闹钟(A 和 B),可根据需要设置。
设置闹钟
/*******************
设置闹钟
RTC_AlarmX 选择闹钟 RTC_Alarm_A | RTC_Alarm_B
hh min,sec ,week 小时 分钟 ,秒 星期
*******************/
void rtc_Alarm(uint32_t RTC_AlarmX,uint8_t hh,uint8_t min,uint8_t sec,uint8_t week)
{
RTC_AlarmTypeDef RTC_AlarmStruct={0};
RTC_TimeTypeDef RTC_AlarmTime={0};
NVIC_InitTypeDef NVIC_InitStruct={0};
EXTI_InitTypeDef EXTI_InitStruct={0};
RTC_AlarmCmd(RTC_AlarmX,DISABLE);
if(RTC_AlarmX==RTC_Alarm_A)
{
while(RTC_GetFlagStatus(RTC_FLAG_ALRAWF)==RESET);// 准备就绪 0x01
}
else if(RTC_AlarmX==RTC_Alarm_B)
{
while(RTC_GetFlagStatus(RTC_FLAG_ALRBWF)==RESET); //0x02
}
RTC_ClearFlag(RTC_FLAG_ALRAWF);
RTC_ClearFlag(RTC_FLAG_ALRBWF);
RTC_ClearITPendingBit(RTC_IT_ALRA);
RTC_ClearITPendingBit(RTC_IT_ALRB);
EXTI_ClearITPendingBit(EXTI_Line17);//清0 线17
EXTI_InitStruct.EXTI_LineCmd = ENABLE;//使能线
EXTI_InitStruct.EXTI_Line = EXTI_Line17;
EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Rising;//上升沿有效
EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_Init(&EXTI_InitStruct);
NVIC_InitStruct.NVIC_IRQChannel= RTC_Alarm_IRQn; //开启中断
NVIC_InitStruct.NVIC_IRQChannelCmd=ENABLE;//使能
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=3; //抢占
NVIC_InitStruct.NVIC_IRQChannelSubPriority=3; //响应
NVIC_Init(&NVIC_InitStruct);
RTC_AlarmStruct.RTC_AlarmMask = RTC_AlarmMask_None; //是日期才选匹配
RTC_AlarmStruct.RTC_AlarmDateWeekDaySel = RTC_AlarmDateWeekDaySel_WeekDay; //星期闹钟
RTC_AlarmStruct.RTC_AlarmDateWeekDay = week;
RTC_AlarmTime.RTC_H12 = RTC_H12_AM;
RTC_AlarmTime.RTC_Hours = hh;
RTC_AlarmTime.RTC_Minutes = min;
RTC_AlarmTime.RTC_Seconds = sec;
RTC_AlarmStruct.RTC_AlarmTime = RTC_AlarmTime; //设置闹钟的时间
RTC_SetAlarm(RTC_Format_BIN,RTC_AlarmX,&RTC_AlarmStruct);
if(RTC_AlarmX==RTC_Alarm_A)
{
RTC_ITConfig(RTC_IT_ALRA,ENABLE);
}
else if(RTC_AlarmX==RTC_Alarm_B)
{
RTC_ITConfig(RTC_IT_ALRB,ENABLE);
}
RTC_AlarmCmd(RTC_AlarmX,ENABLE);
}
闹钟中断处理
//设置闹钟中断
void RTC_Alarm_IRQHandler(void)
{
if(RTC_GetITStatus(RTC_IT_ALRA)==SET)
{
BEEP_Alarm(2,200);//蜂鸣器提示
RTC_ClearITPendingBit(RTC_IT_ALRA);
}else
if(RTC_GetITStatus(RTC_IT_ALRB)==SET)
{
BEEP_Alarm(2,200);
RTC_ClearITPendingBit(RTC_IT_ALRB);
}
EXTI_ClearITPendingBit(EXTI_Line17);
}
六、主程序使用
mian.c
int main(void)
{
//....
rtc_Init();
WKUP_init(RTC_WakeUpClock_CK_SPRE_16bits,1);//1秒唤醒一次
rtc_Alarm(RTC_Alarm_A,20,50,0,2); //Alarm_A
while(1)
{
/** RTC更新时间,LCD显示 **/
if(oldtime!=RTC_Time.RTC_Seconds)
{
oldtime=RTC_Time.RTC_Seconds;
sprintf((char*)buff1,"%2d:%02d:%02d",RTC_Time.RTC_Hours,RTC_Time.RTC_Minutes,RTC_Time.RTC_Seconds);
LCD_ShowString2(40,80,(u8*)buff1,BLACK,32);
printf("%2d:%02d:%02d\r\n",RTC_Time.RTC_Hours,RTC_Time.RTC_Minutes,RTC_Time.RTC_Seconds);
}
}
}
作者:ghs980