前言
在低功耗项目中因为单片机资源不是很丰富,选择了rtthread-nano,rtthread有一个低功耗PM组件,但是这个组件是在标准版,看了一下PM实现的过程和代码,打算模仿实现一个自己的PM组件,下面分三步来介绍:
1.实现思路
2.API使用
3.注意事项
1.实现思路
首先了解一下官方PM组件的实现方法 https://www.rt-thread.org/document/site/#/rt-thread-version/rt-thread-standard/programming-manual/pm/pm?id=api-%e4%bb%8b%e7%bb%8d
我的理解就是有三个注意的地方,1.注册设备为低功耗设备–>也就是调用他们的API,参数为自己在进入低功耗模式前后的回调,2.在执行一些需要等待时的操作,需要调用他们的API,实现对电源的锁定,完事之后需要释放这个锁,也就是调用释放电源的API
所以模仿了他们的实现方式,过程为
1.创建一个低功耗线程,优先级比其他线程都高,的过程为,每1000ms进入此线程,判断电源是否上锁,没有的话则倒计时,当倒计时结束先执行进入之前的计划,然后进入,当有中断被唤醒,则执行退出之后的计划,线程设为最高优先级的目的就是,在执行中断之后第一时间转回这里执行退出之后的操作
2.创建一个表,用于存储进出低功耗模式的回调,提供一个注册低功耗设备的函数,给其他模块调用,参数就是进出低功耗模式的回调
3.提供两个函数,一个电源上锁函数,一个电源解锁函数,当需要执行时间较长的操作时,就需要调用这个函数,一定要成对出现
2.API使用
我在网上找像这种资料时,希望的是直接给我一个.c和.h文件,然后告诉我怎么用就行了,下面就根据怎么用来说一下
1.就是创建一个低功耗线程了,线程入口函数,创建时记得优先级设置为最高
/*
电源控制线程入口函数
*/
void power_control_entry(void *param)
{
while(1)
{
rt_thread_mdelay(1000);
if(power_param.lock) continue;
if(power_param.mdelay_cnt-- <= 0)
{
rt_kprintf("进入低功耗\n");
power_param.mdelay_cnt = power_param.mdelay_cnt_max;
enter_stop1_model();
rt_kprintf("退出低功耗\n");
}
rt_kprintf("倒计时-->%d\n",power_param.mdelay_cnt);
}
}
还有执行进入和退出低功耗的函数
/*
执行进入低功耗前的计划
*/
static void execute_plan_before_enter(void)
{
for(uint8_t i = 0;i < SUPPORT_LP_DEV_MAX;i++)
{
if( lp_dev_table[i].plan_before_entering != NULL)
lp_dev_table[i].plan_before_entering();
}
}
/*
执行退出低功耗之后的计划
*/
static void execute_plan_after_exit(void)
{
for(uint8_t i = 0;i < SUPPORT_LP_DEV_MAX;i++)
{
if( lp_dev_table[i].plan_after_exit != NULL)
lp_dev_table[i].plan_after_exit();
}
}
进入低功耗模式函数
/*
进入低功耗模式
*/
void enter_stop1_model(void)
{
__HAL_RCC_PWR_CLK_ENABLE();
__HAL_PWR_CLEAR_FLAG(PWR_FLAG_WUF);
__HAL_PWR_CLEAR_FLAG(PWR_FLAG_WUFI);
execute_plan_before_enter();
HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI); // 停止1,等待中断
extern void SystemClock_Config(void);
SystemClock_Config();
execute_plan_after_exit();
}
2.提供注册成低功耗设备的函数
/*
低功耗设备注册
*/
void lowpower_dev_register(void (*plan_before_entering)(void),void (*plan_after_exit)(void))
{
for(uint8_t i = 0;i < SUPPORT_LP_DEV_MAX;i++)
{
if(lp_dev_table[i].plan_before_entering == NULL)
{
lp_dev_table[i].plan_before_entering = plan_before_entering;
lp_dev_table[i].plan_after_exit = plan_after_exit;
break;
}
}
}
在.h文件创建两个结构体,一个是用于描述进出低功耗模式的回调函数,一个用于保存电源锁的一些状态
#define MDELAY_CNT_MAX 1 /*进入延迟最大值*/
/*
电源管理的一些数据
*/
typedef struct
{
int mdelay_cnt; /*延迟进入计数值*/
int mdelay_cnt_max; /*延时进入最大值*/
int32_t lock; /*电源锁*/
}PowerStruct;
/*
低功耗设备管理
*/
typedef struct
{
void (*plan_before_entering)(void); /*进入之前的准备*/
void (*plan_after_exit)(void); /*退出之后的计划*/
}lowPowerDEVStruct;
在.c就创建一个表,这里直接用数组实现了,缺点是需要自己确定有几个需要注册的低功耗设备,用链表能解决这个问题,但是麻烦点
#define SUPPORT_LP_DEV_MAX 4 /*支持的低功耗设备数量*/
lowPowerDEVStruct lp_dev_table[SUPPORT_LP_DEV_MAX] = {0};
PowerStruct power_param =
{
.mdelay_cnt = MDELAY_CNT_MAX, /*初始值*/
.mdelay_cnt_max = MDELAY_CNT_MAX, /*初始最大值*/
};
3.提供电源上锁和解锁接口函数
/*
电源上锁
参数:钥匙,最大31
返回值:1上锁成功 ,0上锁失败
*/
uint8_t power_lock_with_key(uint32_t key)
{
if(!((power_param.lock >> key ) & 1))
{
power_param.mdelay_cnt = power_param.mdelay_cnt_max;
power_param.lock |= 1 << key;
return 1;
}
return 0;
}
/*
电源解锁
参数:钥匙
返回值: 1成功解锁,0解锁失败
*/
uint8_t power_unlock_with_key(uint32_t key)
{
if((power_param.lock >> key ) & 1)
{
power_param.lock ^= 1 << key;
return 1;
}
return 0;
}
总的来说,使用过程就是,其他文件开机的时候调用注册函数,然后在需要等待的地方使用上锁和解锁函数就行了
3.注意事项
1.这个只实现了一个模式,就是单片机的停止1模式,因为待机模式会把ram清空
2.属于延时等待而不是立即进入,延时等待进入时间也是可以设置的,就多 写一个函数修改实例化的最大值成员就行了