溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

嵌入式C語言輕量級程序架構(gòu)內(nèi)核編寫的方法

發(fā)布時間:2022-03-07 09:06:39 來源:億速云 閱讀:183 作者:iii 欄目:開發(fā)技術(shù)

這篇文章主要介紹了嵌入式C語言輕量級程序架構(gòu)內(nèi)核編寫的方法的相關(guān)知識,內(nèi)容詳細(xì)易懂,操作簡單快捷,具有一定借鑒價值,相信大家閱讀完這篇嵌入式C語言輕量級程序架構(gòu)內(nèi)核編寫的方法文章都會有所收獲,下面我們一起來看看吧。

1.了解程序架構(gòu)概念和作用

在寫單片機(jī)程序的時候往往會遇見下面的情況

  • 1、產(chǎn)品功能需要很多不同的延時效果,又不能用delay死延時,比方說按鍵檢測、led不同閃爍效果。

  • 2、程序功能一多起來,整個腦子就混亂了,不知道這么整合起來。

  • 3、不同功能區(qū)域的除了共享全局變量或數(shù)組以外不知道該怎么做。

實時操作系統(tǒng)rtos、ucoslinux系統(tǒng),都是好的程序架構(gòu),它們就為開發(fā)者提供了系統(tǒng)實時性好、可靠性高、可移植性強(qiáng)等保障。工程師不需要研究復(fù)制的數(shù)據(jù)結(jié)構(gòu)和算法,比如任務(wù)分配、任務(wù)調(diào)度、內(nèi)存管理、消息機(jī)制等等,只需要學(xué)習(xí)使用系統(tǒng)就夠了。

2.了解單片機(jī)常見的程序架構(gòu)

  • 1、傳統(tǒng)順序執(zhí)行的程序架構(gòu)

最多的時候,單片機(jī)程序都是使用while死循環(huán),然后順序執(zhí)行各種函數(shù),這種程序設(shè)計比較簡單。

#include <stdio.h>
 
int main()
{
    keys = KeyScan();
    while(1)
    {
        if (keys ==1)
        {
        //
        }
    }
 
 
return 0;
}

缺點就是只適合做小項目,程序大了以后邏輯一定會非?;靵y,實時性,穩(wěn)定性,移植性差。

  • 2、實時操作系統(tǒng)

比如ucos、rtos,用戶使用這些系統(tǒng)就只需要把系統(tǒng)移植好能跑起來就行。這種架構(gòu)的優(yōu)點就是它自身就是一個穩(wěn)定性、實時性高的,有的甚至提供了圖形gui和網(wǎng)絡(luò)tcp/ip等強(qiáng)大的功能。

缺點就是占用內(nèi)存資源比較嚴(yán)重,移植起來比較復(fù)雜,應(yīng)用以后如果不去深耕,系統(tǒng)架構(gòu)的工作原理出了問題就會無從下手。所以這種系統(tǒng)一般針對大型項目,對某些功能有需要,比如帶屏幕的需要做大量界面的,或者帶網(wǎng)絡(luò)通信的。

  • 3、輕量級的程序架構(gòu)

這個程序架構(gòu)的定位是能夠應(yīng)用在大多數(shù)的中低端單片機(jī),占用單片機(jī)內(nèi)存資源比較少,在1kb左右。

3.輕量級程序架構(gòu)設(shè)計思想

主要分為兩個部分:

  • 1、程序架構(gòu)系統(tǒng)內(nèi)核

  • 2、任務(wù)通訊

系統(tǒng)內(nèi)核用于任務(wù)的統(tǒng)一分配管理。

任務(wù)通信就是不同模塊間的通信,比如說硬件層和應(yīng)用層的數(shù)據(jù)傳遞,這個就是通過回調(diào)函數(shù)來實現(xiàn)的。

本文的重點就是為了編寫一個有任務(wù)分配、任務(wù)調(diào)度的系統(tǒng)內(nèi)核代碼。能滿足移植性高,穩(wěn)定性強(qiáng),實時性好的特點。

4.程序架構(gòu)內(nèi)核代碼的實現(xiàn)原理

內(nèi)核代碼主要是用來分配任務(wù)和任務(wù)調(diào)度的,任務(wù)就是各功能模塊輪詢的處理函數(shù)。分配任務(wù)就是創(chuàng)建任務(wù),把各功能模塊處理函數(shù)加入到任務(wù)管理列表里。

任務(wù)調(diào)度就是定時喚醒和休眠任務(wù)列表里的任務(wù)。

這里的喚醒就是調(diào)用,休眠就是把任務(wù)掛起,不讓它執(zhí)行。

程序架構(gòu)的系統(tǒng)內(nèi)核工作流程:

嵌入式C語言輕量級程序架構(gòu)內(nèi)核編寫的方法

任務(wù)初始化:包括硬件的初始化,如gpio的配置,定時器初始化,串口初始化等等。然后任務(wù)的創(chuàng)建和任務(wù)執(zhí)行函數(shù)的初始化。

任務(wù)調(diào)度:即我們傳統(tǒng)的while(1)循環(huán)里面輪詢的函數(shù),只是我們?yōu)槊恳粋€任務(wù)提供不一樣的時間節(jié)拍,還可以讓任意一個任務(wù)進(jìn)入休眠。

5.掌握輕量級程序架構(gòu)內(nèi)核編寫

系統(tǒng)內(nèi)核說白了就是寫一個任務(wù)的管理程序,通過這個程序可以更加靈活控制整個程序的允許狀態(tài),特別是需要做低功耗的產(chǎn)品來說。

系統(tǒng)內(nèi)核主要完成以下工作:

  • 1、任務(wù)創(chuàng)建        

  • 2、任務(wù)調(diào)度

  • 3、任務(wù)掛起

  • 4、任務(wù)休眠

優(yōu)點:

  • 1、可以為每個任務(wù)提供不同時鐘節(jié)拍。

  • 2、可以靈活控制每個任務(wù)的執(zhí)行狀態(tài)。

  • 3、實時性更高

  • 4、程序流程更加清晰

  • 5、更適合做低功耗

OS_System.c代碼和OS_System.h代碼

#include "OS_System.h"
 
volatile OS_TaskTypeDef OS_Task[OS_TASK_SUM];
 
CPUInterrupt_CallBack_t CPUInterrupptCtrlCBS;
 
 
/********************************************************************************************************
*  @函數(shù)名   OS_CPUInterruptCBSRegister                                                                                   
*  @描述     注冊CPU中斷控制函數(shù)                                                                     
*  @參數(shù)     pCPUInterruptCtrlCBS-CPU中斷控制回調(diào)函數(shù)地址
*  @返回值   無   
*  @注意     無
********************************************************************************************************/
void OS_CPUInterruptCBSRegister(CPUInterrupt_CallBack_t pCPUInterruptCtrlCBS)
{
    if(CPUInterrupptCtrlCBS == 0)
    {
        CPUInterrupptCtrlCBS = pCPUInterruptCtrlCBS;
    }
}
 
/********************************************************************************************************
*  @函數(shù)名   OS_TaskInit                                                                               
*  @描述     系統(tǒng)任務(wù)初始化                                                                 
*  @參數(shù)     無
*  @返回值   無
*  @注意     無
********************************************************************************************************/
void OS_TaskInit(void)
{
    unsigned char i;
    for(i=0; i<OS_TASK_SUM; i++)
    {
        OS_Task[i].task = 0;
        OS_Task[i].RunFlag = OS_SLEEP;
        OS_Task[i].RunPeriod = 0;
        OS_Task[i].RunTimer = 0;
    }    
}
 
 
/*******************************************************************************
* Function Name  : void OS_CreatTask(unsigned char ID, void (*proc)(void), OS_TIME_TYPEDEF TimeDly, bool flag)
* Description    : 創(chuàng)建任務(wù) 
* Input          : - ID:任務(wù)ID
*                    - (*proc)() 用戶函數(shù)入口地址 
*                    - TimeDly 任務(wù)執(zhí)行頻率,單位ms
*                     - flag 任務(wù)就緒狀態(tài)  OS_SLEEP-休眠 OS_RUN-運行 
* Output         : None
* Return         : None
* Attention         : None
*******************************************************************************/
void OS_CreatTask(unsigned char ID, void (*proc)(void), unsigned short Period, OS_TaskStatusTypeDef flag)
{    
    if(!OS_Task[ID].task)
    {
        OS_Task[ID].task = proc;
        OS_Task[ID].RunFlag = OS_SLEEP;
        OS_Task[ID].RunPeriod = Period;
        OS_Task[ID].RunTimer = 0;
    }
}
 
 
/********************************************************************************************************
*  @函數(shù)名   OS_ClockInterruptHandle                                                                                   
*  @描述     系統(tǒng)任務(wù)調(diào)度函數(shù)                                                                     
*  @參數(shù)     無
*  @返回值   無   
*  @注意     為了保證任務(wù)實時性,這個必須放在10ms的定時器或系統(tǒng)時鐘中斷函數(shù)里
********************************************************************************************************/
void OS_ClockInterruptHandle(void)
{
    unsigned char i;
    for(i=0; i<OS_TASK_SUM; i++)    //這個循環(huán)是對所有的任務(wù)執(zhí)行一次以下操作。
    {
        if(OS_Task[i].task)    //通過task函數(shù)指針指向不等于0來判斷任務(wù)是否被創(chuàng)建
        {                    
            OS_Task[i].RunTimer++;
            if(OS_Task[i].RunTimer > OS_Task[i].RunPeriod)    //判斷計時器值是否到達(dá)任務(wù)需要執(zhí)行的時間
            {
                OS_Task[i].RunTimer = 0;
                OS_Task[i].RunFlag = OS_RUN;//把任務(wù)的狀態(tài)設(shè)置成執(zhí)行,任務(wù)調(diào)度函數(shù)會一直判斷這個變量的值,如果是OS_RUN就會執(zhí)行task指向的函數(shù)。
            }
            
        }
    }
    
}
 
/*******************************************************************************
* Function Name  : void OS_Start(void)
* Description    : 開始任務(wù) 
* Input          : None
* Output         : None
* Return         : None
* Attention         : None
*******************************************************************************/
void OS_Start(void)
{
    unsigned char i;
    while(1)
    {
        for(i=0; i<OS_TASK_SUM; i++)
        {
            if(OS_Task[i].RunFlag == OS_RUN)
            {
                OS_Task[i].RunFlag = OS_SLEEP;
         
                (*(OS_Task[i].task))();    
            }
        }    
    }
}
 
/*******************************************************************************
* Function Name  : void OS_TaskGetUp(OS_TaskIDTypeDef taskID)
* Description    : 喚醒一個任務(wù)
* Input          : - taskID:需要被喚醒任務(wù)的ID
* Output         : None
* Return         : None
* Attention         : None
*******************************************************************************/
void OS_TaskGetUp(OS_TaskIDTypeDef taskID)
{    
    unsigned char IptStatus;
    if(CPUInterrupptCtrlCBS != 0)
    {
        CPUInterrupptCtrlCBS(CPU_ENTER_CRITICAL,&IptStatus);//在這里關(guān)閉單片機(jī)總中斷
    }
    OS_Task[taskID].RunFlag = OS_RUN;    
    if(CPUInterrupptCtrlCBS != 0)
    {
        CPUInterrupptCtrlCBS(CPU_EXIT_CRITICAL,&IptStatus);//在這里開啟單片機(jī)總中斷
    }
}
 
/*******************************************************************************
* Function Name  : void OS_TaskSleep(OS_TaskIDTypeDef taskID)
* Description    : 掛起一個任務(wù),讓一個任務(wù)進(jìn)入睡眠狀態(tài),該函數(shù)暫時沒用到
* Input          : - taskID:需要被掛起任務(wù)的ID
* Output         : None
* Return         : None
* Attention         : None
*******************************************************************************/
void OS_TaskSleep(OS_TaskIDTypeDef taskID)
{
    unsigned char IptStatus;
    if(CPUInterrupptCtrlCBS != 0)
    {
        CPUInterrupptCtrlCBS(CPU_ENTER_CRITICAL,&IptStatus);//在這里關(guān)閉單片機(jī)總中斷
    }
    OS_Task[taskID].RunFlag = OS_SLEEP;
    if(CPUInterrupptCtrlCBS != 0)
    {
        CPUInterrupptCtrlCBS(CPU_EXIT_CRITICAL,&IptStatus);//在這里開啟單片機(jī)總中斷
    }
}
 typedef enum
{
    CPU_ENTER_CRITICAL,        //CPU進(jìn)入臨界
    CPU_EXIT_CRITICAL,        //CPU退出臨界
}CPU_EA_TYPEDEF;
 
//定義一個CPU中斷控制回調(diào)函數(shù)指針,別名CPUInterrupt_CallBack_t,
typedef void (*CPUInterrupt_CallBack_t)(CPU_EA_TYPEDEF cmd,unsigned char *pSta);
 
 
//系統(tǒng)任務(wù)ID
typedef enum
{
    OS_TASK1,
    OS_TASK_SUM    
}OS_TaskIDTypeDef;
 
 
//系統(tǒng)任務(wù)運行狀態(tài),暫時沒用到
typedef enum
{
    OS_SLEEP,            //任務(wù)休眠
    OS_RUN=!OS_SLEEP    //任務(wù)運行
}OS_TaskStatusTypeDef;
 
//系統(tǒng)任務(wù)結(jié)構(gòu)體
typedef struct
{
    void (*task)(void);                    //任務(wù)函數(shù)指針
    OS_TaskStatusTypeDef RunFlag;        //任務(wù)運行狀態(tài)
    unsigned short    RunPeriod;            //任務(wù)調(diào)度頻率
    unsigned short RunTimer;            //任務(wù)調(diào)度計時器
}OS_TaskTypeDef;
 
 
/*    函數(shù)聲明 */ 
/*******************************************************************************/
void OS_CPUInterruptCBSRegister(CPUInterrupt_CallBack_t pCPUInterruptCtrlCBS);
void OS_ClockInterruptHandle(void);
void OS_TaskInit(void);
void OS_CreatTask(unsigned char ID, void (*proc)(void), unsigned short TimeDly, OS_TaskStatusTypeDef flag);
void OS_Start(void);
void OS_ClockInterruptHandle(void);
void OS_TaskGetUp(OS_TaskIDTypeDef taskID);    
void OS_TaskSleep(OS_TaskIDTypeDef taskID);

6.掌握輕量級程序架構(gòu)內(nèi)核移植

了解ucos或者其他操作系統(tǒng)的朋友都知道,單片機(jī)想要跑這些實時操作系統(tǒng),必須進(jìn)行系統(tǒng)的移植,移植就是把單片機(jī)的硬件資源,比如說中斷的打開和關(guān)閉,定時器,堆棧的處理等和ucos系統(tǒng)的內(nèi)核關(guān)聯(lián)起來,比如說我們這個內(nèi)核文件需要關(guān)閉中斷了,那么它是不知道你是用什么單片機(jī),要怎么關(guān)閉單片機(jī)中斷的,只要靠你來寫一個關(guān)閉中斷的函數(shù),然后把這個函數(shù)地址賦值給它們的相關(guān)函數(shù)指針變量。同樣的,我們這個系統(tǒng)內(nèi)核也是需要用到單片機(jī)一些資源的,比如說10ms的定時時間,打開和關(guān)閉中斷。所以我們單片機(jī)來實現(xiàn)這個過程就叫移植,那么我們這個內(nèi)核移植非常簡單,大家可以通過這個來理解一些操作系統(tǒng)的移植原理也會比較容易,移植的流程:

  • 1、把OS_ClockInterruptHandle()函數(shù)放到單片機(jī)定時器中斷處理函數(shù)里,定時頻率10ms

  • 2、重寫單片機(jī)總中斷開關(guān)

  • 3、通過OS_CPUInterruptCBSRegister()函數(shù)把內(nèi)核中斷處理函數(shù)指針指向單片機(jī)總中斷開關(guān)處理函數(shù)。

關(guān)于“嵌入式C語言輕量級程序架構(gòu)內(nèi)核編寫的方法”這篇文章的內(nèi)容就介紹到這里,感謝各位的閱讀!相信大家對“嵌入式C語言輕量級程序架構(gòu)內(nèi)核編寫的方法”知識都有一定的了解,大家如果還想學(xué)習(xí)更多知識,歡迎關(guān)注億速云行業(yè)資訊頻道。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI