嵌入式C語言輕量級程序架構內核編寫

1.瞭解程序架構概念和作用

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

  • 1、產品功能需要很多不同的延時效果,又不能用delay死延時,比方說按鍵檢測、led不同閃爍效果。
  • 2、程序功能一多起來,整個腦子就混亂瞭,不知道這麼整合起來。
  • 3、不同功能區域的除瞭共享全局變量或數組以外不知道該怎麼做。

實時操作系統rtosucoslinux系統,都是好的程序架構,它們就為開發者提供瞭系統實時性好、可靠性高、可移植性強等保障。工程師不需要研究復制的數據結構和算法,比如任務分配、任務調度、內存管理、消息機制等等,隻需要學習使用系統就夠瞭。

2.瞭解單片機常見的程序架構

  • 1、傳統順序執行的程序架構

最多的時候,單片機程序都是使用while死循環,然後順序執行各種函數,這種程序設計比較簡單。

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

缺點就是隻適合做小項目,程序大瞭以後邏輯一定會非常混亂,實時性,穩定性,移植性差。

  • 2、實時操作系統

比如ucosrtos,用戶使用這些系統就隻需要把系統移植好能跑起來就行。這種架構的優點就是它自身就是一個穩定性、實時性高的,有的甚至提供瞭圖形gui和網絡tcp/ip等強大的功能。

缺點就是占用內存資源比較嚴重,移植起來比較復雜,應用以後如果不去深耕,系統架構的工作原理出瞭問題就會無從下手。所以這種系統一般針對大型項目,對某些功能有需要,比如帶屏幕的需要做大量界面的,或者帶網絡通信的。

  • 3、輕量級的程序架構

這個程序架構的定位是能夠應用在大多數的中低端單片機,占用單片機內存資源比較少,在1kb左右。

3.輕量級程序架構設計思想

主要分為兩個部分:

  • 1、程序架構系統內核
  • 2、任務通訊

系統內核用於任務的統一分配管理。

任務通信就是不同模塊間的通信,比如說硬件層和應用層的數據傳遞,這個就是通過回調函數來實現的。

本文的重點就是為瞭編寫一個有任務分配、任務調度的系統內核代碼。能滿足移植性高,穩定性強,實時性好的特點。

4.程序架構內核代碼的實現原理

內核代碼主要是用來分配任務和任務調度的,任務就是各功能模塊輪詢的處理函數。分配任務就是創建任務,把各功能模塊處理函數加入到任務管理列表裡。

任務調度就是定時喚醒和休眠任務列表裡的任務。

這裡的喚醒就是調用,休眠就是把任務掛起,不讓它執行。

程序架構的系統內核工作流程:

任務初始化:包括硬件的初始化,如gpio的配置,定時器初始化,串口初始化等等。然後任務的創建和任務執行函數的初始化。

任務調度:即我們傳統的while(1)循環裡面輪詢的函數,隻是我們為每一個任務提供不一樣的時間節拍,還可以讓任意一個任務進入休眠。

5.掌握輕量級程序架構內核編寫

系統內核說白瞭就是寫一個任務的管理程序,通過這個程序可以更加靈活控制整個程序的允許狀態,特別是需要做低功耗的產品來說。

系統內核主要完成以下工作:

  • 1、任務創建        
  • 2、任務調度
  • 3、任務掛起
  • 4、任務休眠

優點:

  • 1、可以為每個任務提供不同時鐘節拍。
  • 2、可以靈活控制每個任務的執行狀態。
  • 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;
 
 
/********************************************************************************************************
*  @函數名   OS_CPUInterruptCBSRegister                                                                                   
*  @描述     註冊CPU中斷控制函數                                                                     
*  @參數     pCPUInterruptCtrlCBS-CPU中斷控制回調函數地址
*  @返回值   無   
*  @註意     無
********************************************************************************************************/
void OS_CPUInterruptCBSRegister(CPUInterrupt_CallBack_t pCPUInterruptCtrlCBS)
{
    if(CPUInterrupptCtrlCBS == 0)
    {
        CPUInterrupptCtrlCBS = pCPUInterruptCtrlCBS;
    }
}
 
/********************************************************************************************************
*  @函數名   OS_TaskInit                                                                               
*  @描述     系統任務初始化                                                                 
*  @參數     無
*  @返回值   無
*  @註意     無
********************************************************************************************************/
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    : 創建任務 
* Input          : - ID:任務ID
*                    - (*proc)() 用戶函數入口地址 
*                    - TimeDly 任務執行頻率,單位ms
*                     - flag 任務就緒狀態  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;
    }
}
 
 
/********************************************************************************************************
*  @函數名   OS_ClockInterruptHandle                                                                                   
*  @描述     系統任務調度函數                                                                     
*  @參數     無
*  @返回值   無   
*  @註意     為瞭保證任務實時性,這個必須放在10ms的定時器或系統時鐘中斷函數裡
********************************************************************************************************/
void OS_ClockInterruptHandle(void)
{
    unsigned char i;
    for(i=0; i<OS_TASK_SUM; i++)    //這個循環是對所有的任務執行一次以下操作。
    {
        if(OS_Task[i].task)    //通過task函數指針指向不等於0來判斷任務是否被創建
        {                    
            OS_Task[i].RunTimer++;
            if(OS_Task[i].RunTimer > OS_Task[i].RunPeriod)    //判斷計時器值是否到達任務需要執行的時間
            {
                OS_Task[i].RunTimer = 0;
                OS_Task[i].RunFlag = OS_RUN;//把任務的狀態設置成執行,任務調度函數會一直判斷這個變量的值,如果是OS_RUN就會執行task指向的函數。
            }
            
        }
    }
    
}
 
/*******************************************************************************
* Function Name  : void OS_Start(void)
* Description    : 開始任務 
* 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    : 喚醒一個任務
* Input          : - taskID:需要被喚醒任務的ID
* Output         : None
* Return         : None
* Attention         : None
*******************************************************************************/
void OS_TaskGetUp(OS_TaskIDTypeDef taskID)
{    
    unsigned char IptStatus;
    if(CPUInterrupptCtrlCBS != 0)
    {
        CPUInterrupptCtrlCBS(CPU_ENTER_CRITICAL,&IptStatus);//在這裡關閉單片機總中斷
    }
    OS_Task[taskID].RunFlag = OS_RUN;    
    if(CPUInterrupptCtrlCBS != 0)
    {
        CPUInterrupptCtrlCBS(CPU_EXIT_CRITICAL,&IptStatus);//在這裡開啟單片機總中斷
    }
}
 
/*******************************************************************************
* Function Name  : void OS_TaskSleep(OS_TaskIDTypeDef taskID)
* Description    : 掛起一個任務,讓一個任務進入睡眠狀態,該函數暫時沒用到
* Input          : - taskID:需要被掛起任務的ID
* Output         : None
* Return         : None
* Attention         : None
*******************************************************************************/
void OS_TaskSleep(OS_TaskIDTypeDef taskID)
{
    unsigned char IptStatus;
    if(CPUInterrupptCtrlCBS != 0)
    {
        CPUInterrupptCtrlCBS(CPU_ENTER_CRITICAL,&IptStatus);//在這裡關閉單片機總中斷
    }
    OS_Task[taskID].RunFlag = OS_SLEEP;
    if(CPUInterrupptCtrlCBS != 0)
    {
        CPUInterrupptCtrlCBS(CPU_EXIT_CRITICAL,&IptStatus);//在這裡開啟單片機總中斷
    }
}
 typedef enum
{
    CPU_ENTER_CRITICAL,        //CPU進入臨界
    CPU_EXIT_CRITICAL,        //CPU退出臨界
}CPU_EA_TYPEDEF;
 
//定義一個CPU中斷控制回調函數指針,別名CPUInterrupt_CallBack_t,
typedef void (*CPUInterrupt_CallBack_t)(CPU_EA_TYPEDEF cmd,unsigned char *pSta);
 
 
//系統任務ID
typedef enum
{
    OS_TASK1,
    OS_TASK_SUM    
}OS_TaskIDTypeDef;
 
 
//系統任務運行狀態,暫時沒用到
typedef enum
{
    OS_SLEEP,            //任務休眠
    OS_RUN=!OS_SLEEP    //任務運行
}OS_TaskStatusTypeDef;
 
//系統任務結構體
typedef struct
{
    void (*task)(void);                    //任務函數指針
    OS_TaskStatusTypeDef RunFlag;        //任務運行狀態
    unsigned short    RunPeriod;            //任務調度頻率
    unsigned short RunTimer;            //任務調度計時器
}OS_TaskTypeDef;
 
 
/*    函數聲明 */ 
/*******************************************************************************/
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.掌握輕量級程序架構內核移植

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

  • 1、把OS_ClockInterruptHandle()函數放到單片機定時器中斷處理函數裡,定時頻率10ms
  • 2、重寫單片機總中斷開關
  • 3、通過OS_CPUInterruptCBSRegister()函數把內核中斷處理函數指針指向單片機總中斷開關處理函數。

到此這篇關於嵌入式C語言輕量級程序架構內核編寫的文章就介紹到這瞭,更多相關C語言輕量級程序內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!

推薦閱讀: