因为LSI是RC振荡电路产生,所以产生的时钟周期都不会太准。但是由于很多公司为了节约成本不会选择LSE,当然这也没有问题,只要定时器能正常工作也能够很准的计时。
但是,很多类型的设备例如手持设备,需要做到低功耗,就需要进入停止模式,这时候只有RTC可以运行对芯片进行唤醒。这时候就需要进行精准的进行唤醒(例如:10s唤醒一次)。此时可采用的一种方法是,使用定时器进行校准。
校准函数如下所示:
void RTC_Calibrate(double* m)
{
u32 timeT3 = 0;
u32 timeRTC = 0;
RTC_WaitForLastTask();//等待RTC完成设置
RTC_SetCounter(0);
RTC_WaitForLastTask();
TIM_ClearITPendingBit(TIM3,TIM_IT_Update);
TIM3->CNT = 0;
timeT3 = Get_Ticks();//外部函数,每1ms自加1
while(1)
{
IWDG->KR = 0xAAAA;
if(Get_Ticks() - timeT3 >= 500)
{
timeRTC = RTC_GetCounter();
*m = (double)timeRTC / (double)500;//
break;
}
}
}
m的值即为校准之后的值,若需要延时10s
停止模式前和停止模式后加入以下代码:
Sys_Enter_StopMode(m*10);
Sys_Exit_StopMode(m*10);
在你需要进入停止模式时:
void Sys_Enter_StopMode(u32 rtcs)
{
GPIO_InitTypeDef GPIO_InitStructure;
u32 remainTime = 0;
//非关机模式下
if(rtcs != 0)
{
remainTime = rtcs;
//如果时间大于20s,则先等待20s后再唤醒喂狗后再接着等待,若未开启看门口,可略去
if(remainTime >= 700000UL)
remainTime -= 700000UL;
else
remainTime = 0;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE); //使能PWR和BKP外设时钟
PWR_BackupAccessCmd(ENABLE); //使能后备寄存器访问
BKP_WriteBackupRegister(REMAIN_TIME_DR_H, (u16)(remainTime >> 16)); //将剩余时间写入后备寄存器中
BKP_WriteBackupRegister(REMAIN_TIME_DR_L, (u16)(remainTime));
if(rtcs >= 700000UL)
RTC_SetAlarmTime(700000UL);
else
RTC_SetAlarmTime(rtcs);
}
//一定要打开PWR时钟,否则功耗会增加
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
//将未使用的IO口初始化为模拟输入,降低功耗,串口脚PA9/PA10需要设置为模拟,不然实测使用内部晶振时连接串口线会导致RTC计数变慢,慢了18个ms左右。没有测试过外部晶振
// 模拟输入你未使用的GPIO
//进入停止模式
PWR_EnterSTOPMode(PWR_Regulator_LowPower, PWR_STOPEntry_WFI);
}
//当设备被唤醒时,需要对rtcs进行判断
当自动退出停止模式时进行判断:
void Sys_Exit_StopMode(u32 rtcs)
{
u32 remainTime = 0;
while(1)
{
remainTime = ((u32)BKP_ReadBackupRegister(REMAIN_TIME_DR_H) << 16)
+ BKP_ReadBackupRegister(REMAIN_TIME_DR_L) ;
if(remainTime == 0) //唤醒时间,直接唤醒,
{
//add your code
break;
}
else //每20S喂狗,避免复位
{
IWDG_ReloadCounter();
Sys_Enter_StopMode(remainTime);
}
}
}
}