介紹
一種無OS的MCU實用軟件框架,包括任務輪詢管理,命令管理器、低功耗管理、環形緩沖區等實用模塊。系統中廣泛利用自定義段技術減少各個模塊間的耦合關系,大大提供程序的可維護性。
主要功能
- 支持模塊自動化管理,并提供不同優先等級初始化聲明接口。
- 支持任務輪詢管理,通過簡單的宏聲明即可實現,不需要復雜的聲明調用。
- 支持低功耗管理,休眠與喚醒通知。
- 支持命令行解析,命令注冊與執行。
- blink設備支持,統一管理LED、震動馬達、蜂鳴器
使用說明
完整的代碼可以參考工程文件,系統開發平臺如下:
MCU:STM32F401RET6
IDE:IAR 7.4或者Keil MDK 4.72A
任務初始化及任務輪詢管理(module)
使用此模塊前需要系統提供滴答定時器,用于驅動任務輪詢作業。(參考platform.c)
//定時器中斷(提供系統滴答)
void SysTick_Handler(void)
{
systick_increase(SYS_TICK_INTERVAL); //增加系統節拍
}
注冊初始化入口及任務(參考自key_task.c)
static void key_init(void)
{
/*do something*/
}
static void key_scan(void)
{
/*do something*/
}
module_init("key", key_init); //注冊按鍵初始化接口
driver_register("key", key_scan, 20); //注冊按鍵任務(20ms輪詢1次)
命令管理器(cli)
適用于在線調試、參數配置等(參考使用cli_task.c),用戶可以通過串口輸出命令行控制設備行為、查詢設備狀態等功能。
命令格式
cli支持的命令行格式如下:
< param1> < param2> < paramn> < \\r\\n > ,< param1>, < param2>, < paramn>, < \\r\\n >
每行命令包含一個命令名稱+命令參數(可選),命令名稱及參數可以通過空格或者','進行分隔。
系統默認命令
cli系統自帶了2條默認命令,分別是"?"與"help"命令,輸入他們可以列出當前系統包含的命令列表,如下所示:
? - alias for 'help'
help - list all command.
pm - Low power control command
reset - reset system
sysinfo - show system infomation.
適配命令管理器
完整的例子可以參考cli_task.c.
static cli_obj_t cli; /*命令管理器對象 */
/*
* @brief 命令行任務初始化
* @return none
*/
static void cli_task_init(void)
{
cli_port_t p = {tty.write, tty.read}; /*讀寫接口 */
cli_init(&cli, &p); /*初始化命令行對象 */
cli_enable(&cli);
cli_exec_cmd(&cli,"sysinfo"); /*顯示系統信息*/
}
/*
* @brief 命令行任務處理
* @return none
*/
static void cli_task_process(void)
{
cli_process(&cli);
}
module_init("cli", cli_task_init);
task_register("cli", cli_task_process, 10); /*注冊命令行任務*/
命令注冊
以復位命令為例(參考cmd_devinfo.c):
#include "cli.h"
//...
/*
* @brief 復位命令
*/
int do_cmd_reset(struct cli_obj *o, int argc, char *argv[])
{
NVIC_SystemReset();
return 0;
}cmd_register("reset",do_cmd_reset, "reset system");
低功耗管理器(pm)
控制間歇運行,降低系統功耗。其基本的工作原理是通過輪詢系統中各個模塊是否可以允許系統進入低功耗。實際上這是一種判決機制,所有模塊都具有有票否決權,即只要有一個模塊不允許休眠,那么系統就不會進入休眠狀態。pm模塊在休眠前會統計出各個模塊會返回最小允許休眠時長,并以最小休眠時長為單位進行休眠。
如何適配
使用前需要通過pm_init進行初始化適配,并提供當前系統允許的最大休眠時間,進入休眠的函數接口,基本的接口定義如下:
/*低功耗適配器 ---------------------------------------------------------*/
typedef struct {
/**
* @brief 系統最大休眠時長(ms)
*/
unsigned int max_sleep_time;
/**
* @brief 進入休眠狀態
* @param[in] time - 期待休眠時長(ms)
* @retval 實際休眠時長
* @note 休眠之后需要考慮兩件事情,1個是需要定時起來給喂看門狗,否則會在休眠
* 期間發送重啟.另外一件事情是需要補償休眠時間給系統滴答時鐘,否則會
* 造成時間不準。
*/
unsigned int (*goto_sleep)(unsigned int time);
}pm_adapter_t;
void pm_init(const pm_adapter_t *adt);
void pm_enable(void);
void pm_disable(void);
void pm_process(void);
完成的使用例子可以參考platform-lowpower.c,默認情況下是禁用低功耗功能的,讀者可以去除工程中原來不帶低功耗版本的platform.c,并加入platform-lowpower.c文件進行編譯即可使用。
注冊低功耗設備
以按鍵掃描為例,正常情況下,如果按鍵沒有按下,那么系統休眠可以進入休眠狀態,對按鍵功能是沒有影響的。如果按鍵按下時,那么系統需要定時喚醒并輪詢按鍵任務。
所以在一個低功耗系統下,為了不影響按鍵實時性需要處理好兩個事情:
- 系統休眠狀態下,如果有按鍵按下,那系統系統應立即喚醒,以便處理接下來的掃描工作。
- 如果按鍵按下時,系統可以進入休眠,但需要定時喚醒起來輪詢按鍵任務。
對于第一種情況,將按鍵配置為邊沿中斷喚醒即可,以STM32F4為例(參考key_task.c),它支持外部中斷喚醒功能。
/*
* @brief 按鍵 io初始化
* PC0 - > key;
* @return none
*/
static void key_io_init(void)
{
/* Enable GPIOA clock */
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
gpio_conf(GPIOC, GPIO_Mode_IN, GPIO_PuPd_UP, GPIO_Pin_0);
//低功耗模式下,為了能夠檢測到按鍵,配置為中斷喚醒
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);
SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOC, EXTI_PinSource0);
exti_conf(EXTI_Line0, EXTI_Trigger_Falling, ENABLE);
nvic_conf(EXTI0_IRQn, 0x0F, 0x0F);
key_create(&key, readkey, key_event); /*創建按鍵*/
}
對于第二種情況,可以通過pm_dev_register來處理,當系統請求休眠時,如果此時按鍵按下,則返回下次喚醒時間即可,如下面的例子所示。
//參考key_task.c
#include "pm.h"
/*
* @brief 休眠通知
*/
static unsigned int key_sleep_notify(void)
{
return key_busy(&key) || readkey() ? 20 : 0; /* 非空閑時20ms要喚醒1次*/
} pm_dev_register("key", NULL, key_sleep_notify, NULL);
blink模塊
具有閃爍特性(led, motor, buzzer)的設備(led, motor, buzzer)管理
使用步驟:
- 需要系統提供滴答時鐘,blick.c中是通過get_tick()接口獲取,依賴module模塊
- 需要在任務中定時進行輪詢
或者通過"module"模塊的任務注冊來實現
task_register("blink", blink_dev_process, 50); //50ms輪詢1次
LED驅動
blink_dev_t led; //定義led設備
/*
*@brief 紅色LED控制(GPIOA.8)
*@param[in] on - 亮滅控制
*/
static void led_ctrl(int on)
{
if (on)
GPIOA- >ODR |= (1 < < 8);
else
GPIOA- >ODR &= ~(1 < < 8);
}
/*
*@brief led初始化程序
*/
void led_init(void)
{
led_io_init(void); //led io初始化
blink_dev_create(&led, led_ctrl); //創建led設備
blink_dev_ctrl(&led, 50, 100, 0); //快閃(50ms亮, 100ms滅)
}
按鍵管理模塊
類似blink模塊,使用之前有兩個注意事項:
- 需要系統提供滴答時鐘,key.c中是通過get_tick()接口獲取,依賴module模塊
- 需要在任務中定時進行輪詢
key_t key; //定義按鍵管理器
/*
*@brief 按鍵事件
*@param[in] type - 按鍵類型(KEY_PRESS, KEY_LONG_DOWN, KEY_LONG_UP)
*@param[in] duration - 長按持續時間
*/
void key_event(int type, unsigned int duration)
{
if (type == KEY_PRESS) { //短按
} else if (type == KEY_LONG_DOWN) { //長按
}
}
//讀取鍵值(假設按鍵輸出口為STM32 MCU PA8)
int read_key(void)
{
return GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_8) == Bit_RESET;
}
/*
*@brief 按鍵初始化
*/
void key_init(void)
{
//打開GPIO 時鐘
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
//配置成輸入模式
gpio_conf(GPIOA, GPIO_Mode_IN, GPIO_PuPd_NOPULL, GPIO_Pin_8);
//創建1個按鍵
key_create(&key, read_key, key_event);
}
-
mcu
+關注
關注
146文章
17123瀏覽量
350992 -
接口
+關注
關注
33文章
8575瀏覽量
151019 -
軟件框架
+關注
關注
0文章
21瀏覽量
9864
發布評論請先 登錄
相關推薦
評論