1)实验平台:正点原子APM32E103最小系统板
2)平台购买地址:https://detail.tmall.com/item.htm?id=609294757420
3)全套实验源码+手册+视频下载地址: http://www.openedv.com/docs/boards/xiaoxitongban
本章介绍APM32E103低功耗模式中的睡眠模式,通过调用WFI命令进入睡眠模式后,ARM Corten-M3内核将停止以降低功耗,在该睡眠模式下可以被任意中断唤醒。通过本章的学习,读者将学习到低功耗模式中睡眠模式的使用。
本章分为如下几个小节:
29.1 硬件设计
29.2 程序设计
29.3 下载验证
29.1 硬件设计
29.1.1 例程功能
#define PMU_WKUP_GPIO_PORT GPIOA
#define PMU_WKUP_GPIO_PIN GPIO_PIN_0
#define PMU_WKUP_GPIO_CLK_ENABLE() do{ RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_GPIOA); }while(0)
#define PMU_WKUP_INT_IRQn EINT0_IRQn
#define PMU_WKUP_INT_IRQHandler EINT0_IRQHandler
PMU驱动中,睡眠模式唤醒按键的初始化函数,如下所示:
/**
* @brief 初始化唤醒按键
* @param 无
* @retval 无
*/
void pmu_wkup_key_init(void)
{
GPIO_Config_T gpio_init_struct;
EINT_Config_T eint_init_struct;
PMU_WKUP_GPIO_CLK_ENABLE(); /* 使能唤醒引脚端口时钟 */
RCM_EnableAPB2PeriphClock(RCM_APB1_PERIPH_PMU); /* 使能PMU时钟 */
gpio_init_struct.pin = PMU_WKUP_GPIO_PIN; /* 唤醒引脚 */
gpio_init_struct.mode = GPIO_MODE_IN_PD; /* 输入模式 */
GPIO_Config(PMU_WKUP_GPIO_PORT, &gpio_init_struct); /* 配置唤醒引脚 */
eint_init_struct.line=(EINT_LINE_T)PMU_WKUP_GPIO_PIN;/* EINT线 */
eint_init_struct.mode=EINT_MODE_INTERRUPT; /* 中断模式 */
eint_init_struct.trigger=EINT_TRIGGER_RISING; /* 上升沿 */
eint_init_struct.lineCmd=ENABLE; /* 使能 */
EINT_Config(&eint_init_struct); /* 配置EINT */
NVIC_EnableIRQRequest(PMU_WKUP_INT_IRQn, 2, 0); /* 使能中断 */
}
因为调用WFI命令进入睡眠模式后,能够被任意的中断唤醒,因此睡眠模式唤醒按键的初始化只需要配置好按键的外部中断即可。
PMU驱动中,睡眠模式唤醒按键对应的中断回调函数,如下所示:
/**
* @brief 唤醒引脚外部中断服务函数
* @param 无
* @retval 无
*/
void PMU_WKUP_INT_IRQHandler(void)
{
/* 判断唤醒引脚事件线中断标志 */
if (EINT_ReadIntFlag((EINT_LINE_T)PMU_WKUP_GPIO_PIN) == SET)
{
/* 清除唤醒引脚事件线中断标志 */
EINT_ClearIntFlag((EINT_LINE_T)PMU_WKUP_GPIO_PIN);
}
}
因为睡眠唤醒按键的中断只是为了唤醒睡眠模式,因此并不需要在中断回调函数中做任何处理。
PMU驱动中,进入睡眠模式的函数,如下所示:
/**
* @brief 进入睡眠模式
* @param 无
* @retval 无
*/
void pmu_enter_sleep(void)
{
/* 禁用SysTick的中断,防止SysTick中断唤醒 */
SysTick->CTRL &= ~SysTick_CTRL_TICKINT_Msk;
NVIC_ResetystemLowPower(NVIC_LOWPOWER_SLEEPDEEP); /* 配置为睡眠模式 */
/* 指令WFI,进入睡眠模式,等待任意中断唤醒 */
__WFI();
SysTick->CTRL |= SysTick_CTRL_TICKINT_Msk; /* 使能SysTick中断 */
}
从上面的代码中可以看出,进入睡眠模式主要就是执行WFI命令,接下来MCU便会进入睡眠模式,等待任意的中断唤醒,因此在执行WFI命令之前,需要先关闭部分中断,以免误唤醒。
29.2.2 实验应用代码
本实验的应用代码,如下所示:
int main(void)
{
uint8_t key;
uint8_t t = 0;
NVIC_ConfigPriorityGroup(NVIC_PRIORITY_GROUP_4);/* 设置中断优先级分组为组4 */
sys_apm32_clock_init(15); /* 配置系统时钟 */
delay_init(120); /* 初始化延时功能 */
usart_init(115200); /* 初始化串口 */
led_init(); /* 初始化LED */
lcd_init(); /* 初始化LCD */
key_init(); /* 初始化按键 */
pmu_wkup_key_init(); /* 初始化唤醒按键 */
lcd_show_string(30, 50, 200, 16, 16, "APM32", RED);
lcd_show_string(30, 70, 200, 16, 16, "SLEEP TEST", RED);
lcd_show_string(30, 90, 200, 16, 16, "ATOM@ALIENTEK", RED);
lcd_show_string(30, 110, 200, 16, 16, "KEY0:Enter SLEEP MODE", RED);
lcd_show_string(30, 130, 200, 16, 16, "KEY_UP:Exit SLEEP MODE", RED);
while (1)
{
key = key_scan(0);
if (key == KEY0_PRES)
{
LED1(0); /* 点亮LED1,提示进入睡眠模式 */
pmu_enter_sleep(); /* 进入睡眠模式 */
LED1(1); /* 熄灭LED1,提示退出睡眠模式 */
}
if ((t % 20) == 0)
{
LED0_TOGGLE();
}
t++;
delay_ms(10);
}
}
从上面的代码中可以看出,在完成相关的初始化操作后,并不断地扫描按键,若扫描到KEY0按键被按下,则会点亮LED1后进入睡眠模式,此时ARM Cortex-M3内核便停止了,从该睡眠模式唤醒需要有任意的中断产生,因此可以由KEY_UP按键产生外部中断来唤醒睡眠。退出睡眠模式后,LED1将被熄灭。
29.3 下载验证
在完成编译和烧录操作后,可以看到LED0闪烁提示系统程序正在运行,此时可以按下KEY0按键,可以看到LED1亮起,但LED0不再闪烁,这是因为系统已经进入睡眠模式了,此时再按下KEY_UP按键,即可从睡眠模式下唤醒,可以看到LED1熄灭,LED0继续闪烁。