总结:我一开始是粘贴别人的rtc.c文件,然后自己找到进入待机模式的代码,然后总是出错,错误是当第二次进入待机后就立马被唤醒,最后发现是进入待机模式前清除待机的标志位出错了,等于说第二次进入待机的时候因为这个标志位造成了很多奇奇怪怪的错误。虽然对于大佬来说我这个错误很低级,但是对我这个新手来说还是很难搞的,因为很多标志位函数我都不太懂,我都是看标志位的注释。
int main(void)
{
//设置中断优先级为组2,2抢占优先级,2响应优先级
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
//初始化延时函数
delay_init(168);
//外设的初始化
peripheral_init();
ret = My_RTC_Init(); //rtc初始化
if(ret == 0)
{
printf("RTC初始化成功\r\n");
}
//要执行的任务代码
/****************/
RTC_Set_WakeUp(RTC_WakeUpClock_CK_SPRE_16bits , 299); // WAKE UP 5min中断一次,用于唤醒待机模式(当299改成59后是一分钟中断一次,改成0时是1s中中断一次)
printf("进入待机模式了,5min后苏醒\r\n");
Sys_Enter_Standby(); //进入待机模式
}
rtc.c 文件
// RTC初始化
// 返回值:0,初始化成功;
// 1,LSE开启失败;
// 2,进入初始化模式失败;
u8 My_RTC_Init(void)
{
RTC_InitTypeDef RTC_InitStructure; // 定义RTC初始化结构体
u16 retry = 0X1FFF; // 定义重试次数
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE); // 使能PWR时钟
PWR_BackupAccessCmd(ENABLE); // 使能后备寄存器访问
if (RTC_ReadBackupRegister(RTC_BKP_DR0) != 0x5053) // 检查是否第一次配置
{
RCC_LSEConfig(RCC_LSE_ON); // 开启LSE(低速外部晶振)
while (RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET) // 检查指定的RCC标志位设置与否,等待低速晶振就绪
{
retry++;
delay_ms(10);
}
if (retry == 0)
return 1; // LSE 开启失败.
RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE); // 设置RTC时钟(RTCCLK),选择LSE作为RTC时钟
RCC_RTCCLKCmd(ENABLE); // 使能RTC时钟
RTC_InitStructure.RTC_AsynchPrediv = 0x7F; // RTC异步分频系数(1~0X7F)
RTC_InitStructure.RTC_SynchPrediv = 0xFF; // RTC同步分频系数(0~7FFF)
RTC_InitStructure.RTC_HourFormat = RTC_HourFormat_24; // RTC设置为24小时格式
RTC_Init(&RTC_InitStructure); // 初始化RTC
RTC_WriteBackupRegister(RTC_BKP_DR0, 0x5053); // 标记已经初始化过了
}
return 0;
}
// 周期性唤醒定时器设置
/*wksel: @ref RTC_Wakeup_Timer_Definitions
#define RTC_WakeUpClock_RTCCLK_Div16 ((uint32_t)0x00000000)
#define RTC_WakeUpClock_RTCCLK_Div8 ((uint32_t)0x00000001)
#define RTC_WakeUpClock_RTCCLK_Div4 ((uint32_t)0x00000002)
#define RTC_WakeUpClock_RTCCLK_Div2 ((uint32_t)0x00000003)
#define RTC_WakeUpClock_CK_SPRE_16bits ((uint32_t)0x00000004)
#define RTC_WakeUpClock_CK_SPRE_17bits ((uint32_t)0x00000006)
*/
// cnt:自动重装载值.减到0,产生中断.
/*唤醒功能可以让RTC实时时钟在设定的时间点或间隔后触发中断,
从而唤醒系统或执行特定的任务。例如,在低功耗应用中,
系统可能会进入睡眠模式以节省能量,但仍然需要在某个时间点或间隔后执行某些任务,
比如更新显示、采集传感器数据等。通过设置唤醒功能,
RTC实时时钟可以在预定的时间点或间隔后触发中断,从而唤醒系统并执行相应的任务。*/
void RTC_Set_WakeUp(u32 wksel, u16 cnt)
{
EXTI_InitTypeDef EXTI_InitStructure;
RTC_WakeUpCmd(DISABLE); // 关闭WAKE UP
RTC_WakeUpClockConfig(wksel); // 唤醒时钟选择
RTC_SetWakeUpCounter(cnt); // 设置WAKE UP自动重装载寄存器
RTC_ClearITPendingBit(RTC_IT_WUT); // 清除RTC WAKE UP的标志
EXTI_ClearITPendingBit(EXTI_Line22); // 清除LINE22上的中断标志位
RTC_ITConfig(RTC_IT_WUT, ENABLE); // 开启WAKE UP 定时器中断
RTC_WakeUpCmd(ENABLE); // 开启WAKE UP 定时器
EXTI_InitStructure.EXTI_Line = EXTI_Line22; // LINE22
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; // 中断事件
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising; // 上升沿触发
EXTI_InitStructure.EXTI_LineCmd = ENABLE; // 使能LINE22
EXTI_Init(&EXTI_InitStructure); // 配置
NVIC_InitStructure.NVIC_IRQChannel = RTC_WKUP_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02; // 抢占优先级1
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x02; // 子优先级2
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; // 使能外部中断通道
NVIC_Init(&NVIC_InitStructure); // 配置NVIC中断向量表
}
// RTC WAKE UP中断服务函数
void RTC_WKUP_IRQHandler(void)
{
if (RTC_GetFlagStatus(RTC_FLAG_WUTF) == SET) // WK_UP中断?
{
RTC_ClearFlag(RTC_FLAG_WUTF); // 清除中断标志
}
EXTI_ClearITPendingBit(EXTI_Line22); // 清除中断线22的中断标志
}
//原文链接:https://blog.csdn.net/qq_55546571/article/details/134699815
//待机模式
void Sys_Enter_Standby(void)
{
// PWR_ClearFlag(PWR_FLAG_SB); // 错误的清除待机标志位
//清除wu状态
PWR_ClearFlag (PWR_FLAG_WU);
//使能wu引脚唤醒功能,使能PA0
PWR_WakeUpPinCmd (ENABLE);
//进入待机模式
PWR_EnterSTANDBYMode();
}
rtc.h
void Sys_Enter_Standby(void); //进入待机
u8 My_RTC_Init(void); //rtc初始化
void RTC_Set_WakeUp(u32 wksel, u16 cnt); //周期性唤醒定时器