本帖最后由 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、总结 在低功耗学习中,我尝试测试进入低功耗模式下的功耗,编写了相应满足测试条件的代码。测出的数据没办法达到手册理想值,后面了解到数据手册上的理想值为测试部门使用专门的功耗版,放置裸片测试的结果。如果我们测试想要达到理想数值,那么需要对照原理图,把相关影响项断开,进行测试。制作小玩意时,可以尝试进入睡眠模式,通过语音唤醒等外部事件进行唤醒,降低产品使用的功耗。
|