本帖最后由 1455555 于 2023-12-25 15:43 编辑
1、引言 在不需要微控制器运行时,可以使其进入低功耗模式,降低系统功耗。当需要微控制器运行时,再唤醒即可。 这段时间我学习了一下几种低功耗模式。参考了APM32F072(M0),APM32F003(M0),APM32F103(M3)三款芯片,发现他们的低功耗模式有一些差异。下面我将从三款芯片各自的用户手册中摘出低功耗相关表格。 APM32F4XX APM32F103 APM32F072 APM32F003 根据贴出来的四张图可以发现M3,M4内核的产品和072的低功耗模式都分为三种:睡眠模式、停止模式和待机模式。但003特立独行,分为等待模式、快速活跃停机模式、慢速活跃停机模式、停机模式四种。 仔细对比每个模式下的各个设置,发现003的四种和072的三种并没有能完全吻合的分类。下面将其放置在一张表格中,可能更清晰一些。
2、例程介绍 接下来每款芯片介绍一种模式下的唤醒例程。
2、1 F003等待模式串口中断唤醒 注意到F003等待模式下的唤醒方式可以为所有外部内部中断。这里我们使用串口中断作为唤醒方式。例程设置等待一段时间后,系统自动进入低功耗模式下。在串口助手发送任意字符可以唤醒MCU。 - void Delay(void);
- void USART_WakeUp_Init(void);
- int main(void)
- {
- volatile uint8_t i = 10;
- APM_MINI_LEDInit(LED2);
-
- USART_WakeUp_Init();
-
- while(1)
- {
- APM_MINI_LEDToggle(LED2);
- Delay();
- if(i)
- {
- i--;
- if(i == 0)
- {
- PMU_EnterWaitMode();
- }
- }
- }
- }
-
例程中给出是否进入低功耗信号:LED灯是否闪烁。进入等待模式后,CPU停止,代码运行停止在进入低功耗这句指令后。唤醒后,从该指令后开始继续执行。所以,记得在进入低功耗之前对串口进行配置,设置好唤醒方式。在中断服务函数中,等待标志位后,只进行了清除操作。 - void USART1_RX_IRQHandler(void)
- {
- if(USART_ReadIntFlag(USART1,USART_INT_FLAG_RX) == SET)
- {
- USART_ClearIntFlag(USART1,USART_INT_FLAG_RX);
- }
- }
这个例程前期没有加入再次进入低功耗的处理。如果平时正常使用,可以在前面加入一个按键,在按键按下时,进入睡眠模式。串口接收数据时,唤醒CPU。唤醒后需要进入睡眠模式,再次按下按键即可。 2、2 F003活跃停机模式下通过WUPT唤醒 活跃停机分为快速活跃停机和慢速活跃停机模式,快速活跃停机模式唤醒时间在低功耗唤醒时间里最短。(为啥?如果是因为主电压调节器,那睡眠模式下主电压调节器也开着啊?) 例程使用WUPT,在一定的延时后产生一个内部唤醒事件,延迟时间可由编程设置。编程中发现标准库里有WUPT延时设置封装好的函数,直接使用。 - #include "main.h"
- void Delay(void);
- int main(void)
- {
- volatile uint8_t i = 10;
- APM_MINI_LEDInit(LED2);
-
- while(1)
- {
- APM_MINI_LEDToggle(LED2);
- Delay();
- i--;
- if(i == 0)
- {
- i = 10;
- APM_MINI_LEDOff(LED2);
- WUPT_Config(AWU_TIMEBASE_2S);
- NVIC_EnableIRQRequest(WUPT_IRQn,0X01);
- PMU_EnterHaltModeWFI();
- }
- }
- }
- void Delay(void)
- {
- volatile uint32_t delaytime = 0xfffff;
- while(delaytime--);
- }
其中WUPT_Config()为 - void WUPT_Config(WUPT_TIMEBASE_T timeBase)
- {
- WUPT->TBC = (uint32_t)g_timeBaseTab[(uint32_t)timeBase];
- WUPT->DIV = (uint32_t)g_dividerTab[(uint32_t)timeBase];
- WUPT->CSTS_B.WUPTEN = BIT_SET;
- }
2.3 F072待机模式下使用WAKEUP_PIN唤醒 待机模式下所有外设都关闭,CPU与主电压调节器都关闭。例程为按下按键产生中断,在中断中进入待机模式。进入待机模式前,使能WAKEPIN。WAKEUP_PIN对应引脚查找数据手册引脚分布图。
- void Delay(uint32_t count);
- int main(void)
- {
- APM_MINI_LEDInit(LED2);
- APM_MINI_LEDInit(LED3);
- APM_MINI_PBInit(BUTTON_KEY2, BUTTON_MODE_EINT);
- APM_MINI_COMInit(COM1);
- PMU_Reset();
- RCM_EnableAPB1PeriphClock(RCM_APB1_PERIPH_PMU);
- /* Enable PC13 as system WakeUp pin for standby mode */
- PMU_EnableWakeUpPin(PMU_WAKEUPPIN_2);
- printf("\r\nSystem is Init\r\n");
- printf("Press KEY2 : ENTER StandBy Mode\r\n");
- for (;;)
- {
- Delay(0xfffff);
- APM_MINI_LEDToggle(LED2);
- APM_MINI_LEDToggle(LED3);
- printf("\r\nSystem is running\r\n");
- }
- }
- void APM_MINI_PB_PMU_Isr()
- {
- if (EINT_ReadStatusFlag(EINT_LINE0) == SET)
- {
- printf("\r\nSystem have entered STANDBY mode\r\n");
- printf("now, LED2 and LED3 is off\r\n");
- printf("please give PC13 a rising edge or reset System to recover System\r\n\r\n");
- /* Clear flag bit to prevent repeated entry interrupt*/
- PMU_ClearStatusFlag(PMU_FLAG_STDBYF);
- PMU_ClearStatusFlag(PMU_FLAG_WUPF);
- /* Enter StandBy Mode*/
- PMU_EnterSTANDBYMode();
- EINT_ClearStatusFlag(EINT_LINE0);
- }
- }
- void Delay(uint32_t count)
- {
- volatile uint32_t delay = count;
- while (delay--);
- }
2.4 F103停止模式下通过按键唤醒 这个例程可以通过选择是否定义KEY1_WAKEUP来决定是否需要使用按键唤醒,同时,可以通过定义REGULATOR_ON/LowPower选择停止模式下电压调节器的模式。前面对IO的配置用于满足低功耗模式功耗测试的要求。 - #define DEBUG_USART USART1
- /*choose which condition of STANDBY MODE to enter*/
- #define REGULATOR_ON
- //#define REGULATOR_OFF
- /*choose if need key1 to wake up*/
- #define KEY1_WAKEUP
- void Delay(uint32_t count);
- int main(void)
- {
- GPIO_Config_T gpioConfig;
- /* Disable clock to reduce current consumption*/
- RCM_DisableHSI();
-
- /*Disable LSE to reduce current consumption*/
- RCM_EnableAPB1PeriphClock((RCM_APB1_PERIPH_T)(RCM_APB1_PERIPH_PMU | RCM_APB1_PERIPH_BAKR));
- PMU->CTRL_B.BPWEN = 0X01;
- RCM_ConfigLSE(RCM_LSE_CLOSE);
- RCM_DisableAPB1PeriphClock(RCM_APB1_PERIPH_BAKR);
-
- /* Configure all GPIO as analog to reduce current consumption on non used IOs */
- RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_GPIOA | RCM_APB2_PERIPH_GPIOB | RCM_APB2_PERIPH_GPIOC |
- RCM_APB2_PERIPH_GPIOD | RCM_APB2_PERIPH_GPIOE | RCM_APB2_PERIPH_GPIOF | RCM_APB2_PERIPH_GPIOG) ;
-
- gpioConfig.mode = GPIO_MODE_ANALOG;
- gpioConfig.pin = GPIO_PIN_ALL;
- GPIO_Config(GPIOA,&gpioConfig);
- GPIO_Config(GPIOB,&gpioConfig);
- GPIO_Config(GPIOC,&gpioConfig);
- GPIO_Config(GPIOD,&gpioConfig);
- GPIO_Config(GPIOE,&gpioConfig);
- GPIO_Config(GPIOF,&gpioConfig);
- GPIO_Config(GPIOG,&gpioConfig);
-
- RCM_DisableAPB2PeriphClock(RCM_APB2_PERIPH_GPIOA | RCM_APB2_PERIPH_GPIOB | RCM_APB2_PERIPH_GPIOC |
- RCM_APB2_PERIPH_GPIOD | RCM_APB2_PERIPH_GPIOE | RCM_APB2_PERIPH_GPIOF | RCM_APB2_PERIPH_GPIOG);
-
- #ifdef KEY1_WAKEUP
- /* Config KEY1 to wake up cpu from stop mode*/
- APM_MINI_PBInit(BUTTON_KEY1, BUTTON_MODE_EINT);
- #endif
- /* Enable PMU Periph Clock */
- RCM_EnableAPB1PeriphClock(RCM_APB1_PERIPH_PMU);
- PMU_Reset();
-
- Delay(0x6fffff);
-
- #ifdef REGULATOR_ON
- PMU_EnterSTOPMode(PMU_REGULATOR_ON,PMU_STOP_ENTRY_WFI);
- #elif defined REGULATOR_LowPower
- PMU_EnterSTOPMode(PMU_REGULATOR_LOWPOWER,PMU_STOP_ENTRY_WFI);
- #endif
-
- APM_MINI_LEDInit(LED2);
- while(1)
- {
- APM_MINI_LEDToggle(LED2);
- Delay(0xfffff);
- }
- }
- void Eint1_Isr(void)
- {
- if (EINT_ReadIntFlag(KEY1_BUTTON_EINT_LINE) != RESET)
- {
- SystemInit();
- EINT_ClearIntFlag(KEY1_BUTTON_EINT_LINE);
- }
- }
3、总结 在低功耗学习中,我尝试测试进入低功耗模式下的功耗,编写了相应满足测试条件的代码。测出的数据没办法达到手册理想值,后面了解到数据手册上的理想值为测试部门使用专门的功耗版,放置裸片测试的结果。如果我们测试想要达到理想数值,那么需要对照原理图,把相关影响项断开,进行测试。制作小玩意时,可以尝试进入睡眠模式,通过语音唤醒等外部事件进行唤醒,降低产品使用的功耗。
|