潘多拉 RT-Thread 低功耗
实验概述
随着物联网(IoT)的兴起,产品对功耗的需求越来越强烈。作为数据采集的传感器节点通常需要在电池供电时长期工作,而作为联网的 SOC 也需要有快速的响应功能和较低的功耗。
因此,本实验将使用 WK_UP 按键唤醒处于休眠状态的 MCU,让开发者了解嵌入式设备低功耗涉及的思路和做法。
电源管理框架
在产品开发的起始阶段,首先考虑是尽快完成产品的功能开发。在产品功能逐步完善之后,就需要加入电源管理功能。为了适应 IoT 的这种需求,RT-Thread 提供了电源管理框架。电源管理框架的理念是尽量透明,使得产品加入低功耗功能更加轻松。
PM 组件有以下特点:
- PM 组件是基于模式来管理功耗
- PM 组件可以根据模式自动更新设备的频率配置,确保在不同的运行模式都可以正常工作
- PM 组件可以根据模式自动管理设备的挂起和恢复,确保在不同的休眠模式下可以正确的挂起和恢复
- PM 组件支持可选的休眠时间补偿,让依赖 OS Tick 的应用可以透明使用
- PM 组件向上层提供设备接口,如果使用了设备文件系统组件,那么也可以用文件系统接口来访问
本例程演示 RT-Thread 的电源管理组件 (Power Management,以下简称 PM 组件) 的使用。基于 PM 组件,用户可以很轻松地完成低功耗的开发。
硬件连接
潘多拉 IoT Board 的 WK_UP 按键被连接到单片机的 7 引脚(PC13),该引脚同时也是作为单片机在休眠模式下的 WAKEUP_PIN2 引脚。
示例代码
参考《潘多拉 IoT Board 开发环境》创建工程,在 applications/main.c 中输入如下代码。
我们的目标是使用 WK_UP 按键来唤醒处于休眠模式的 MCU。一般情况下,在 MCU 处于比较深度的休眠模式,只能通过特定的方式唤醒。MCU 被唤醒之后,会触发相应的中断。以下程序使用 WK_UP 按键从 Timer MODE 唤醒 MCU,并点亮 LED 之 2 秒后,再次进入休眠状态。
applications/main.c
#include <rtthread.h>
#include <rtdevice.h>
#include <drv_wakeup.h>
#include <board.h>
#include <stm32l4xx.h>
#define WAKEUP_APP_THREAD_STACK_SIZE 1024
#define WAKEUP_APP__THREAD_PRIORITY RT_THREAD_PRIORITY_MAX / 3
#define WAKEUP_EVENT_BUTTON (1 << 0)
static rt_event_t wakeup_event;
static void _pin_as_analog(void)
{
GPIO_InitTypeDef GPIOInitstruct = {0};
GPIOInitstruct.Pin = GPIO_PIN_7;
GPIOInitstruct.Mode = GPIO_MODE_ANALOG;
GPIOInitstruct.Pull = GPIO_NOPULL;
GPIOInitstruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOE, &GPIOInitstruct);
}
static void led_app(void)
{
rt_pm_request(PM_SLEEP_MODE_NONE);
rt_pin_mode(PIN_LED_R, PIN_MODE_OUTPUT);
rt_pin_write(PIN_LED_R, 0);
rt_thread_mdelay(2000);
rt_pin_write(PIN_LED_R, 1);
_pin_as_analog();
rt_pm_release(PM_SLEEP_MODE_NONE);
}
static void wakeup_callback(void)
{
rt_event_send(wakeup_event, WAKEUP_EVENT_BUTTON);
}
static void wakeup_init(void)
{
/* 唤醒事件的初始化 */
wakeup_event = rt_event_create("wakup", RT_IPC_FLAG_FIFO);
RT_ASSERT(wakeup_event != RT_NULL);
/* 唤醒按键中断回调函数的初始化 */
bsp_register_wakeup(wakeup_callback);
}
static void pm_mode_init(void)
{
rt_pm_request(PM_SLEEP_MODE_DEEP);
}
int main(void)
{
/* 唤醒回调函数初始化 */
wakeup_init();
/* 电源管理初始化 */
pm_mode_init();
while (1)
{
/* 等待唤醒事件 */
if (rt_event_recv(wakeup_event, WAKEUP_EVENT_BUTTON,
RT_EVENT_FLAG_AND | RT_EVENT_FLAG_CLEAR,
RT_WAITING_FOREVER, RT_NULL) == RT_EOK)
{
led_app();
}
}
}