STM32进入Standby模式并唤醒
程序员文章站
2022-06-08 19:42:31
...
项目背景
设备具备电池、电源适配器两种供电方式,实现出厂时最低功耗(即进入待机模式),到用户开始使用时需要手动唤醒,开始复位运行。在检测到设备是交流供电时,设备全速运行;电测到是电池供电时,定时采集数据,采集完毕进入停止模式,定时器唤醒等待下次数据采集。(stm32f103ret6)
备注:本节只记录待机模式的进入和唤醒,停止模式的实现方式见STM32进入STOP模式并唤醒实验总结
用待机模式的理由及与停止模式的区别
- 选用待机模式
设备出厂,电池装在电路板上,封闭在模具当中,在到用户开始使用之前,必须保持最低功耗。停止模式下CPU电流消耗在20uA左右,而待机模式的电流消耗只有2uA。
- 和停止模式的区别
因为SRAM和寄存器的内容会保存,即能PC指针能记录程序当前运行的位置,从停止模式唤醒时,能继续沿着到时进入停止模式处继续往下运行。(故运行时,设备检测到是电池供电时,选用停止模式:采集完数据进入停止模式,2小时后(根据需求自定义)定时唤醒采集,依此循环)
SRAM和寄存器内容不会保存,即待机模式唤醒相当于系统复位,从头运行(设备测试完成,整机入库时,通过外部按键等方式触发进入待机模式)
待机模式实现
进入待机模式三个步骤说明:
1.将系统控制寄存器第二位置1,当进入深度睡眠时,允许停止系统时钟(系统控制寄存器参考《Cortex-M3权威指南》)
2.使能PWR_CR的PDDS位,使得深度休眠时进入待机模式
3.清除WUF唤醒标志(WUF标志由硬件置位,当系统是WKUP唤醒复位而不是上电等复位时会置位。应用中可以用来读取PWR_CSR的WUF位是否为1来判断系统复位是不是待机唤醒)
4.
以上三个步骤由库函数PWR_EnterSTANDBYMode()实现
进入待机模式
void Standby_Entering(void)
{
RCC_APB2PeriphResetCmd(0x01fc, DISABLE); //准备进入待机模式,复位所有IO,降低功耗(参照手册,根据需要复位对应IO)
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);//需要配置电源控制寄存器,所以使能时钟,否则不能正常使用命令进入待机状态和唤醒
PWR_WakeUpPinCmd(ENABLE); //使能WKUP引脚唤醒功能,否则WKUP引脚上升沿不能唤醒
PWR_EnterSTANDBYMode(); //进入待机模式
}
void Standby_Configure(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
//EXTI_InitTypeDef EXTI_InitStructure;
//NVIC_InitTypeDef NVIC_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;
GPIO_Init(WAKEUP_PORT, &GPIO_InitStructure);
/*如果PA0只是用于唤醒,这部分可以不要,唤醒不是中断,中断控制器已经停止工作,如果正常模式下需要用到,可根据需要添加,这时候是中断事件
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0);
EXTI_InitStructure.EXTI_Line = EXTI_Line0;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x03;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
*/
}
中断处理(注:唤醒之后相当于复位,不会执行中断函数里的内容)
void EXTI0_IRQHandler(void)
{
EXTI_ClearITPendingBit(EXTI_Line0); //清除LINE0上的中断标志位
}
void main(void)
{
...
Standby_Configure();
...
//读取PWR_CSR的WUF位检测复位来源,这也就是为什么在进入待机模式之前需要清除WUF唤醒标志,这样检测到唤醒标志就能确定发生了唤醒复位
if(PWR_GetFlagStatus(PWR_FLAG_WU) == SET)//从待机唤醒后,除了电源控制/状态寄存器(PWR_CSR),所有寄存器被复位
{
//是待机唤醒复位,可帮助调试
}
else
{
//上电复位、软件复位等非唤醒复位
}
while(1)
{
if(外部按键标志) //根据硬件和个人需求确定什么时候进入待机模式
{
Standby_Entering();
}
//数据采集、发送
//进入停止模式
//定时从停止模式唤醒
}
}