嵌入式C語言輕量級程序架構內核編寫
1.瞭解程序架構概念和作用
在寫單片機程序的時候往往會遇見下面的情況
- 1、產品功能需要很多不同的延時效果,又不能用delay死延時,比方說按鍵檢測、
led
不同閃爍效果。 - 2、程序功能一多起來,整個腦子就混亂瞭,不知道這麼整合起來。
- 3、不同功能區域的除瞭共享全局變量或數組以外不知道該怎麼做。
實時操作系統rtos
、ucos
、linux
系統,都是好的程序架構,它們就為開發者提供瞭系統實時性好、可靠性高、可移植性強等保障。工程師不需要研究復制的數據結構和算法,比如任務分配、任務調度、內存管理、消息機制等等,隻需要學習使用系統就夠瞭。
2.瞭解單片機常見的程序架構
- 1、傳統順序執行的程序架構
最多的時候,單片機程序都是使用while死循環,然後順序執行各種函數,這種程序設計比較簡單。
#include <stdio.h> int main() { keys = KeyScan(); while(1) { if (keys ==1) { // } } return 0; }
缺點就是隻適合做小項目,程序大瞭以後邏輯一定會非常混亂,實時性,穩定性,移植性差。
- 2、實時操作系統
比如ucos
、rtos
,用戶使用這些系統就隻需要把系統移植好能跑起來就行。這種架構的優點就是它自身就是一個穩定性、實時性高的,有的甚至提供瞭圖形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!