本帖最后由 Alden 于 2023-8-24 18:24 编辑
#技术资源# #申请原创#
部分应用中,会有功耗要求,在功耗要求比较高的场景,要提高使用电池供电设备的待机时间。
就需要关闭耗电高的器件、比如LCD屏幕、LED灯等,MCU也可以配置到低功耗状态来进一步降低。
APM32F103系列低功耗模式有三种:睡眠模式、停止模式和待机模式。通过关闭内核、时钟源、设置调压器来降低功耗。
每种低功耗模式的功耗、唤醒启动时间、唤醒方式、唤醒后数据的保存存在差异;功耗越低,唤醒时间越长,唤醒方式越少,唤醒后保存的数据越少,用户可以根据需求选择最合适的低功耗模式。下图是三种低功耗模式的差异
APM32F103系列查看数据手册,可以看到各工作模式下的功耗差异。
根据主频和外设使用情况的不同:
Run mode:19.4~32.9mA
Sleep mode:5.2~21.5mA
Stop mode:20uA左右
Standby mode:4uA左右
可以看到各低功耗模式的功耗差异还是非常大的,特别的是standby模式,可以满足绝大部分低功耗需求。
Standby模式功耗最低,但待机时内核停止工作,外设也停止工作,内核寄存器、内存的数据会丢失。唤醒后相当于程序复位从头开始执行。
唤醒的方式可以通过WKUP 引脚的上升沿, RTC 闹钟、唤醒、入侵事件或 NRST 引脚外部复位及 IWDT
一般常用的就是通过WKUP 引脚或RTC来唤醒MCU。接下来简单测试下这两种方式。
WKUP唤醒的配置比较简单,只需要配置PMU_CSTS的WKUPCFG位即可。
对应库函数为: PMU_EnableWakeUpPin();
然后在进入standby前清除唤醒标志位,避免标志位干扰即可:
PMU_ClearStatusFlag(PMU_FLAG_WUE);
PMU_EnterSTANDBYMode();
而RTC的唤醒首先需要对RTC进行初始化。
void RTC_Init(void)
{
if(PMU_ReadStatusFlag(PMU_FLAG_SB) == SET)
{
APM_MINI_LEDOn(LED3);
PMU_ClearStatusFlag(PMU_FLAG_SB);
RTC_WaitForSynchro();
}
else
{
BAKPR_Reset();
RCM_EnableLSI();
while(RCM_ReadStatusFlag(RCM_FLAG_LSIRDY) == RESET);
RCM_ConfigRTCCLK(RCM_RTCCLK_LSI);
RCM_EnableRTCCLK();
RTC_WaitForSynchro();
RTC_ConfigPrescaler(40000);
RTC_WaitForLastTask();
}
}
这里使用LSI作为时钟源,Standby唤醒虽然主程序会从头运行,但RTC的配置不受影响,所以根据PMU_CSTS的待机标志,可以不用重复配置RTC,节省初始化时间。
再配置SysTick中断和按键PA1的中断,分别做系统运行闪烁指示和按键进入Standby的判断。
同时在EINT1_IRQHandler中进入standby前,进行RTC闹钟配置,让MCU进standby唤醒3秒后自动唤醒。
void SysTick_Handler(void)
{
APM_MINI_LEDToggle(LED2);
}
void EINT1_IRQHandler(void)
{
if(EINT_ReadIntFlag(KEY1_BUTTON_EINT_LINE) != RESET)
{
EINT_ClearIntFlag(KEY1_BUTTON_EINT_LINE);
APM_MINI_LEDOn(LED2);
RTC_ClearStatusFlag(RTC_FLAG_SEC);
while(RTC_ReadStatusFlag(RTC_FLAG_SEC) == RESET);
RTC_ConfigAlarm(RTC_ReadCounter()+ 3);
RTC_WaitForLastTask();
PMU_ClearStatusFlag(PMU_FLAG_WUE);
PMU_EnterSTANDBYMode();
}
}
对应main中进行初始化配置。
int main(void)
{
RCM_EnableAPB1PeriphClock((RCM_APB1_PERIPH_T)(RCM_APB1_PERIPH_PMU | RCM_APB1_PERIPH_BAKR));
APM_MINI_LEDInit(LED2);
APM_MINI_LEDInit(LED3);
APM_MINI_PBInit(BUTTON_KEY1, BUTTON_MODE_EINT);
APM_MINI_LEDOn(LED2);
APM_MINI_LEDOff(LED3);
PMU_EnableWakeUpPin();
PMU_EnableBackupAccess();
RTC_Init();
SysTick_Init();
while(1)
{
if(PMU_ReadStatusFlag(PMU_FLAG_WUE) == SET)
{
APM_MINI_LEDOn(LED3);
}
else
{
APM_MINI_LEDOff(LED3);
}
}
}
运行效果为:
上电LED2闪烁 ,表示MCU在运行状态。
按下PA1的按键,LED2熄灭,MCU进入standby模式。
3秒后MCU自动唤醒,或者给PA0一个上升沿信号也可以唤醒。
唤醒后,LED2继续闪烁,LED3常亮,表示进入过了standby模式。
而我main中多了一句:
if(PMU_ReadStatusFlag(PMU_FLAG_WUE) == SET)
{
APM_MINI_LEDOn(LED3);
}
这是为了验证用户手册说的:
实测也是运行状态下,如果PA0也就是WKUP引脚是高电平,这个标志位就会置位,并且由于标志位一直置位,如果保持PA0一直是高电平的状态进入standby,RTC闹钟无法唤醒MCU,需要PA0有个上升沿型号才行。
所以,应用中使用WUKP需要保持空闲状态低电平,需要唤醒时拉高,避免标志位不对。
补充下standby模式下的功耗,只有3uA,还是相当不错的。
|
@21小跑堂 :补充了低功耗电流哈
基于APM32F103的Standby模式的进入与唤醒,既然测试了低功耗的进入与唤醒,最好可以加测一下低功耗的电流消耗,二姨觉得会更好。