新聞中心

EEPW首頁 > 嵌入式系統(tǒng) > 設(shè)計應(yīng)用 > 軟件框架|學會MCU實用模塊

軟件框架|學會MCU實用模塊

作者: 時間:2024-06-18 來源: 收藏

介紹

本文引用地址:http://m.butianyuan.cn/article/202406/459989.htm

一種無OS的實用,包括任務(wù)輪詢管理,命令管理器、低功耗管理、環(huán)形緩沖區(qū)等實用。系統(tǒng)中廣泛利用自定義段技術(shù)減少各個間的耦合關(guān)系,大大提供程序的可維護性。

主要功能

· 支持自動化管理,并提供不同優(yōu)先等級初始化聲明接口。

· 支持任務(wù)輪詢管理,通過簡單的宏聲明即可實現(xiàn),不需要復(fù)雜的聲明調(diào)用。

· 支持低功耗管理,休眠與喚醒通知。

· 支持命令行解析,命令注冊與執(zhí)行。

· blink設(shè)備支持,統(tǒng)一管理LED、震動馬達、蜂鳴器。

使用說明

完整的代碼可以參考工程文件,系統(tǒng)開發(fā)平臺如下:

:STM32F401RET6

IDE:IAR 7.4或者Keil MDK 4.72A

任務(wù)初始化及任務(wù)輪詢管理(module)

使用此模塊前需要系統(tǒng)提供滴答定時器,用于驅(qū)動任務(wù)輪詢作業(yè)。(參考platform.c)

//定時器中斷(提供系統(tǒng)滴答)
void SysTick_Handler(void){
    systick_increase(SYS_TICK_INTERVAL); //增加系統(tǒng)節(jié)拍
}

注冊初始化入口及任務(wù)(參考自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);      //注冊按鍵任務(wù)(20ms輪詢1次)

命令管理器(cli)

適用于在線調(diào)試、參數(shù)配置等(參考使用cli_task.c),用戶可以通過串口輸出命令行控制設(shè)備行為、查詢設(shè)備狀態(tài)等功能。

命令格式

cli支持的命令行格式如下:

< param1> < param2> < paramn>  < rn > , < param1>, < param2>, < paramn>,  < rn >

每行命令包含一個命令名稱+命令參數(shù)(可選),命令名稱及參數(shù)可以通過空格或者','進行分隔。

系統(tǒng)默認命令

cli系統(tǒng)自帶了2條默認命令,分別是"?"與"help"命令,輸入他們可以列出當前系統(tǒng)包含的命令列表,如下所示:

?         - 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       命令行任務(wù)初始化
 * @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");                   /*顯示系統(tǒng)信息*/
}
/* 
 * @brief       命令行任務(wù)處理
 * @return      none
 */
 
static void cli_task_process(void){
    cli_process(&cli);
}
module_init("cli", cli_task_init);                  
task_register("cli", cli_task_process, 10);          /*注冊命令行任務(wù)*/

命令注冊

以復(fù)位命令為例(參考cmd_devinfo.c):

#include "cli.h"
//...
/* 
 * @brief       復(fù)位命令
 */
 
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)

控制間歇運行,降低系統(tǒng)功耗。其基本的工作原理是通過輪詢系統(tǒng)中各個模塊是否可以允許系統(tǒng)進入低功耗。實際上這是一種判決機制,所有模塊都具有有票否決權(quán),即只要有一個模塊不允許休眠,那么系統(tǒng)就不會進入休眠狀態(tài)。pm模塊在休眠前會統(tǒng)計出各個模塊會返回最小允許休眠時長,并以最小休眠時長為單位進行休眠。

如何適配

使用前需要通過pm_init進行初始化適配,并提供當前系統(tǒng)允許的最大休眠時間,進入休眠的函數(shù)接口,基本的接口定義如下:

/*低功耗適配器 ---------------------------------------------------------*/
typedef struct {
    /**
     * @brief    系統(tǒng)最大休眠時長(ms)
     */
  
    unsigned int max_sleep_time;
    /**
     * @brief     進入休眠狀態(tài)
     * @param[in] time - 期待休眠時長(ms)
     * @retval    實際休眠時長
     * @note      休眠之后需要考慮兩件事情,1個是需要定時起來給喂看門狗,否則會在休眠
     *            期間發(fā)送重啟.另外一件事情是需要補償休眠時間給系統(tǒng)滴答時鐘,否則會
     *            造成時間不準。
     */
     
    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文件進行編譯即可使用。

注冊低功耗設(shè)備

以按鍵掃描為例,正常情況下,如果按鍵沒有按下,那么系統(tǒng)休眠可以進入休眠狀態(tài),對按鍵功能是沒有影響的。如果按鍵按下時,那么系統(tǒng)需要定時喚醒并輪詢按鍵任務(wù)。

所以在一個低功耗系統(tǒng)下,為了不影響按鍵實時性需要處理好兩個事情:

1. 系統(tǒng)休眠狀態(tài)下,如果有按鍵按下,那系統(tǒng)系統(tǒng)應(yīng)立即喚醒,以便處理接下來的掃描工作。

2. 如果按鍵按下時,系統(tǒng)可以進入休眠,但需要定時喚醒起來輪詢按鍵任務(wù)。

對于第一種情況,將按鍵配置為邊沿中斷喚醒即可,以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, 0x0F0x0F);
    
    key_create(&key, readkey, key_event);            /*創(chuàng)建按鍵*/
}

對于第二種情況,可以通過pm_dev_register來處理,當系統(tǒng)請求休眠時,如果此時按鍵按下,則返回下次喚醒時間即可,如下面的例子所示。

//參考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)的設(shè)備(led, motor, buzzer)管理

使用步驟:

· 需要系統(tǒng)提供滴答時鐘,blick.c中是通過get_tick()接口獲取,依賴module模塊

· 需要在任務(wù)中定時進行輪詢

或者通過"module"模塊的任務(wù)注冊來實現(xiàn)

task_register("blink", blink_dev_process, 50);  //50ms輪詢1次

LED驅(qū)動

blink_dev_t led;                             //定義led設(shè)備
/*
 *@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);   //創(chuàng)建led設(shè)備
    
    blink_dev_ctrl(&led, 501000);   //快閃(50ms亮, 100ms滅)
}

按鍵管理模塊

類似blink模塊,使用之前有兩個注意事項:

· 需要系統(tǒng)提供滴答時鐘,key.c中是通過get_tick()接口獲取,依賴module模塊

· 需要在任務(wù)中定時進行輪詢

key_t key;                             //定義按鍵管理器
/*
 *@brief     按鍵事件
 *@param[in] type     - 按鍵類型(KEY_PRESS, KEY_LONG_DOWN, KEY_LONG_UP)  
 *@param[in] duration - 長按持續(xù)時間
 */

void key_event(int type, unsigned int duration){
 if (type == KEY_PRESS) {                //短按
   
 } else if (type == KEY_LONG_DOWN) {     //長按
  
 }

//讀取鍵值(假設(shè)按鍵輸出口為STM32  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); 
    //創(chuàng)建1個按鍵
    key_create(&key, read_key, key_event);  
}

本文來源Gitee-魔羅,版權(quán)歸原作者所有。如涉及作品版權(quán)問題,請聯(lián)系進行刪除。



關(guān)鍵詞: 軟件 MCU 模塊 框架

評論


相關(guān)推薦

技術(shù)專區(qū)

關(guān)閉