本课讲为大家讲解CKS32F4xx系列产品的低功耗模式之睡眠(Sleep)模式。MCU为满足某些应用场景:如小型化低容量设备,长期监测设备等,低功耗应运而生,其中根据需求,用户可以选择睡眠模式、停止模式及待机模式,今天本课将带大家一起配置睡眠模式。
电源系统及低功耗
首先,MCU要做到低功耗,必须要知道电源是怎么分配的,CKS32F4xx系列的电源系统框图如下所示:
(资料图)
电源框图中,第1部分是备份域电路,由VDD或Vbat电池供电,接入3V纽扣电池后,可保证VDD掉电时,能够保留关键数据。
第2部分为电压调压器供电,由于其输出约为1.2V,又称1.2V域。1.2V域给除备份域和待机电路以外的所有数字电路供电,在低功耗的三种模式中,1.2V域也对应三种状态:正常开启、低功耗和关闭。
第3部分为A/D转换器及参考电压供电,故为VDDA供电区,目的是使用独立电源能更好的滤波,从而提高精度,也可以在Vref上外接高精度电源,进一步提高进度。
所谓低功耗,即是关闭相应功耗路线,1)睡眠模式仅关闭第二部分中的内核时钟;2)停止模式关闭所有时钟,且调压器可选择正常开启或低功耗运行;3)待机模式关闭所有时钟以及调压器,仅保留备份域及待机电路;
外部中断唤醒睡眠模式验证
接下来举一个低功耗睡眠模式且由外部中断唤醒的例子,睡眠模式比较简单,直接调用编译器内置函数__WFE()或__WFI(),取决于使用事件唤醒还是中断唤醒;另外默认SCR(系统控制寄存器)的SLEEPDEEP位和SLEEPONEXIT位置0,效果是立即触发睡眠,如果将SLEEPONEXIT置1可以设置成中断退出后触发睡眠,也就是说内核将会只在中断内工作。
验证流程如下图,电源串联万用表电流档,直观比较睡眠模式开启前后的电流大小。
程序配置及中断服务函数
1)开启时钟及GPIO初始化如下,按键直连PE10,按下为低电平。
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE ,ENABLE); //开启按键GPIO口的时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE); //由于使用外部中断需要使能 SYSCFG 时钟GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; //选择按键PE10的引脚 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN; //设置引脚为输入模式GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; //不上拉也不下拉GPIO_Init( GPIOE, &GPIO_InitStructure); //使用上面的结构体初始化按键
2)总中断NVIC初始化如下,GPIO外部中断源一共对应7个通道,PX0~PX4分别对应EXTI0~EXTI4的5个通道,PX5~PX9对应通道EXTI_9_5,PX10~PX15 对应通道EXTI_15_10,故PE10对应中断服务函数EXTI15_10_IRQHandler()。
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1); //配置NVIC为优先级组1NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn; //按键PE10使用中断源EXTI15_10NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; //配置抢占优先级:1NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; //配置子优先级:1NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能中断通道NVIC_Init(&NVIC_InitStructure); //使用上面的结构体初始化总中断
3)外部中断配置如下,主要在初始化中对中断屏蔽寄存器EXTI_IMR及下降沿触发选择寄存器EXTI_FTSR配置,将EXTI_IMR的MR10位置1,可开放相应通道中断请求。
SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOE,EXTI_PinSource10); //连接外部中断源到PE10EXTI_InitStructure.EXTI_Line = EXTI_Line10; //选择EXTI中断源EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; //选择为中断模式EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising; //下降沿触发EXTI_InitStructure.EXTI_LineCmd = ENABLE; //使能中断/事件线EXTI_Init(&EXTI_InitStructure); //使用上面的结构体初始化外部中断:EXTI_IMR的MR10位置1等
4)中断服务函数如下,触发后验证标志位,确保发生的是外部线中断;其次外部中断线发生事件后,中断挂起寄存器EXTI_PR会置1,通过 EXTI_ClearITPendingBit再次在PR写入1,从而清除它,进入下一次外部中断等待。
void EXTI15_10_IRQHandler(void){ if(EXTI_GetITStatus(EXTI_Line10) != RESET) //验证是否产生了外部线中断 { Delay(0x1FFFFFF); //简单延时验证电流 EXTI_ClearITPendingBit(EXTI_Line10); //清除标志位 } }
主函数及现象
Main函数首先初始化GPIO、NVIC中断、外部中断,进入主循环后先延迟观测电流,测得19.3mA,延迟后,__WFI()自动触发睡眠模式,电流测得13.3mA,如果不进行按键操作,MCU将一直睡眠,不再执行任何代码,此时按下轻触开关,触发外部中断,电流回升至19.3mA,睡眠模式唤醒时间无延迟,执行完中断服务程序后,会回到代码睡眠时的句段,继续执行。PS:如果需要设置成中断退出后触发睡眠模式,则将SLEEPONEXIT置1。
int main(void){ EXTI_Config(); //配置及初始化GPIO、NVIC中断、外部中断 while(1) { Delay(0x1FFFFFF); //SCB->SCR |= SCB_SCR_SLEEPONEXIT_Msk; //如需设置成中断退出后触发睡眠模式 __WFI(); //进入睡眠模式,电流从19.3mA降至13.3mA }}审核编辑:汤梓红
标签: