嵌入式C語(yǔ)言輕量級(jí)程序架構(gòu)內(nèi)核編寫(xiě)
1.了解程序架構(gòu)概念和作用
在寫(xiě)單片機(jī)程序的時(shí)候往往會(huì)遇見(jiàn)下面的情況
- 1、產(chǎn)品功能需要很多不同的延時(shí)效果,又不能用delay死延時(shí),比方說(shuō)按鍵檢測(cè)、
led
不同閃爍效果。 - 2、程序功能一多起來(lái),整個(gè)腦子就混亂了,不知道這么整合起來(lái)。
- 3、不同功能區(qū)域的除了共享全局變量或數(shù)組以外不知道該怎么做。
實(shí)時(shí)操作系統(tǒng)rtos
、ucos
、linux
系統(tǒng),都是好的程序架構(gòu),它們就為開(kāi)發(fā)者提供了系統(tǒng)實(shí)時(shí)性好、可靠性高、可移植性強(qiáng)等保障。工程師不需要研究復(fù)制的數(shù)據(jù)結(jié)構(gòu)和算法,比如任務(wù)分配、任務(wù)調(diào)度、內(nèi)存管理、消息機(jī)制等等,只需要學(xué)習(xí)使用系統(tǒng)就夠了。
2.了解單片機(jī)常見(jiàn)的程序架構(gòu)
- 1、傳統(tǒng)順序執(zhí)行的程序架構(gòu)
最多的時(shí)候,單片機(jī)程序都是使用while死循環(huán),然后順序執(zhí)行各種函數(shù),這種程序設(shè)計(jì)比較簡(jiǎn)單。
#include <stdio.h> ? int main() { ?? ?keys = KeyScan(); ? ? while(1) ? ? { ?? ? ? ?if (keys ==1) ?? ? ? ?{ ?? ??? ?// ?? ? ? ?} ? ? } ? ? return 0; }
缺點(diǎn)就是只適合做小項(xiàng)目,程序大了以后邏輯一定會(huì)非常混亂,實(shí)時(shí)性,穩(wěn)定性,移植性差。
- 2、實(shí)時(shí)操作系統(tǒng)
比如ucos
、rtos
,用戶使用這些系統(tǒng)就只需要把系統(tǒng)移植好能跑起來(lái)就行。這種架構(gòu)的優(yōu)點(diǎn)就是它自身就是一個(gè)穩(wěn)定性、實(shí)時(shí)性高的,有的甚至提供了圖形gui和網(wǎng)絡(luò)tcp/ip等強(qiáng)大的功能。
缺點(diǎn)就是占用內(nèi)存資源比較嚴(yán)重,移植起來(lái)比較復(fù)雜,應(yīng)用以后如果不去深耕,系統(tǒng)架構(gòu)的工作原理出了問(wèn)題就會(huì)無(wú)從下手。所以這種系統(tǒng)一般針對(duì)大型項(xiàng)目,對(duì)某些功能有需要,比如帶屏幕的需要做大量界面的,或者帶網(wǎng)絡(luò)通信的。
- 3、輕量級(jí)的程序架構(gòu)
這個(gè)程序架構(gòu)的定位是能夠應(yīng)用在大多數(shù)的中低端單片機(jī),占用單片機(jī)內(nèi)存資源比較少,在1kb左右。
3.輕量級(jí)程序架構(gòu)設(shè)計(jì)思想
主要分為兩個(gè)部分:
- 1、程序架構(gòu)系統(tǒng)內(nèi)核
- 2、任務(wù)通訊
系統(tǒng)內(nèi)核用于任務(wù)的統(tǒng)一分配管理。
任務(wù)通信就是不同模塊間的通信,比如說(shuō)硬件層和應(yīng)用層的數(shù)據(jù)傳遞,這個(gè)就是通過(guò)回調(diào)函數(shù)來(lái)實(shí)現(xiàn)的。
本文的重點(diǎn)就是為了編寫(xiě)一個(gè)有任務(wù)分配、任務(wù)調(diào)度的系統(tǒng)內(nèi)核代碼。能滿足移植性高,穩(wěn)定性強(qiáng),實(shí)時(shí)性好的特點(diǎn)。
4.程序架構(gòu)內(nèi)核代碼的實(shí)現(xiàn)原理
內(nèi)核代碼主要是用來(lái)分配任務(wù)和任務(wù)調(diào)度的,任務(wù)就是各功能模塊輪詢的處理函數(shù)。分配任務(wù)就是創(chuàng)建任務(wù),把各功能模塊處理函數(shù)加入到任務(wù)管理列表里。
任務(wù)調(diào)度就是定時(shí)喚醒和休眠任務(wù)列表里的任務(wù)。
這里的喚醒就是調(diào)用,休眠就是把任務(wù)掛起,不讓它執(zhí)行。
程序架構(gòu)的系統(tǒng)內(nèi)核工作流程:
任務(wù)初始化:包括硬件的初始化,如gpio
的配置,定時(shí)器初始化,串口初始化等等。然后任務(wù)的創(chuàng)建和任務(wù)執(zhí)行函數(shù)的初始化。
任務(wù)調(diào)度:即我們傳統(tǒng)的while(1)
循環(huán)里面輪詢的函數(shù),只是我們?yōu)槊恳粋€(gè)任務(wù)提供不一樣的時(shí)間節(jié)拍,還可以讓任意一個(gè)任務(wù)進(jìn)入休眠。
5.掌握輕量級(jí)程序架構(gòu)內(nèi)核編寫(xiě)
系統(tǒng)內(nèi)核說(shuō)白了就是寫(xiě)一個(gè)任務(wù)的管理程序,通過(guò)這個(gè)程序可以更加靈活控制整個(gè)程序的允許狀態(tài),特別是需要做低功耗的產(chǎn)品來(lái)說(shuō)。
系統(tǒng)內(nèi)核主要完成以下工作:
- 1、任務(wù)創(chuàng)建
- 2、任務(wù)調(diào)度
- 3、任務(wù)掛起
- 4、任務(wù)休眠
優(yōu)點(diǎn):
- 1、可以為每個(gè)任務(wù)提供不同時(shí)鐘節(jié)拍。
- 2、可以靈活控制每個(gè)任務(wù)的執(zhí)行狀態(tài)。
- 3、實(shí)時(shí)性更高
- 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?? ??? ??? ??? ??? ??? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?? * ?@描述 ? ? 注冊(cè)CPU中斷控制函數(shù)?? ??? ??? ??? ??? ??? ??? ??? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?? * ?@參數(shù) ? ? pCPUInterruptCtrlCBS-CPU中斷控制回調(diào)函數(shù)地址 * ?@返回值 ? 無(wú) ?? * ?@注意 ? ? 無(wú) ********************************************************************************************************/ void OS_CPUInterruptCBSRegister(CPUInterrupt_CallBack_t pCPUInterruptCtrlCBS) { ?? ?if(CPUInterrupptCtrlCBS == 0) ?? ?{ ?? ??? ?CPUInterrupptCtrlCBS = pCPUInterruptCtrlCBS; ?? ?} } ? /******************************************************************************************************** * ?@函數(shù)名 ? OS_TaskInit?? ??? ??? ??? ??? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?? * ?@描述 ? ? 系統(tǒng)任務(wù)初始化?? ??? ??? ??? ??? ??? ??? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?? * ?@參數(shù) ? ? 無(wú) * ?@返回值 ? 無(wú) * ?@注意 ? ? 無(wú) ********************************************************************************************************/ 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-運(yùn)行? * 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ú) * ?@返回值 ? 無(wú) ?? * ?@注意 ? ? 為了保證任務(wù)實(shí)時(shí)性,這個(gè)必須放在10ms的定時(shí)器或系統(tǒng)時(shí)鐘中斷函數(shù)里 ********************************************************************************************************/ void OS_ClockInterruptHandle(void) { ?? ?unsigned char i; ?? ?for(i=0; i<OS_TASK_SUM; i++)?? ?//這個(gè)循環(huán)是對(duì)所有的任務(wù)執(zhí)行一次以下操作。 ?? ?{ ?? ??? ?if(OS_Task[i].task)?? ?//通過(guò)task函數(shù)指針指向不等于0來(lái)判斷任務(wù)是否被創(chuàng)建 ?? ??? ?{?? ??? ??? ??? ??? ? ?? ??? ??? ?OS_Task[i].RunTimer++; ?? ??? ??? ?if(OS_Task[i].RunTimer > OS_Task[i].RunPeriod)?? ?//判斷計(jì)時(shí)器值是否到達(dá)任務(wù)需要執(zhí)行的時(shí)間 ?? ??? ??? ?{ ?? ??? ??? ??? ?OS_Task[i].RunTimer = 0; ?? ??? ??? ??? ?OS_Task[i].RunFlag = OS_RUN;//把任務(wù)的狀態(tài)設(shè)置成執(zhí)行,任務(wù)調(diào)度函數(shù)會(huì)一直判斷這個(gè)變量的值,如果是OS_RUN就會(huì)執(zhí)行task指向的函數(shù)。 ?? ??? ??? ?} ?? ??? ??? ? ?? ??? ?} ?? ?} ?? ? } ? /******************************************************************************* * Function Name ?: void OS_Start(void) * Description ? ?: 開(kāi)始任務(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 ? ?: 喚醒一個(gè)任務(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);//在這里開(kāi)啟單片機(jī)總中斷 ?? ?} } ? /******************************************************************************* * Function Name ?: void OS_TaskSleep(OS_TaskIDTypeDef taskID) * Description ? ?: 掛起一個(gè)任務(wù),讓一個(gè)任務(wù)進(jìn)入睡眠狀態(tài),該函數(shù)暫時(shí)沒(méi)用到 * 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);//在這里開(kāi)啟單片機(jī)總中斷 ?? ?} }
?typedef enum { ?? ?CPU_ENTER_CRITICAL,?? ??? ?//CPU進(jìn)入臨界 ?? ?CPU_EXIT_CRITICAL,?? ??? ?//CPU退出臨界 }CPU_EA_TYPEDEF; ? //定義一個(gè)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ù)運(yùn)行狀態(tài),暫時(shí)沒(méi)用到 typedef enum { ?? ?OS_SLEEP,?? ??? ??? ?//任務(wù)休眠 ?? ?OS_RUN=!OS_SLEEP?? ?//任務(wù)運(yùn)行 }OS_TaskStatusTypeDef; ? //系統(tǒng)任務(wù)結(jié)構(gòu)體 typedef struct { ?? ?void (*task)(void);?? ??? ??? ??? ??? ?//任務(wù)函數(shù)指針 ?? ?OS_TaskStatusTypeDef RunFlag;?? ??? ?//任務(wù)運(yùn)行狀態(tài) ?? ?unsigned short?? ?RunPeriod;?? ??? ??? ?//任務(wù)調(diào)度頻率 ?? ?unsigned short RunTimer;?? ??? ??? ?//任務(wù)調(diào)度計(jì)時(shí)器 }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.掌握輕量級(jí)程序架構(gòu)內(nèi)核移植
了解ucos
或者其他操作系統(tǒng)的朋友都知道,單片機(jī)想要跑這些實(shí)時(shí)操作系統(tǒng),必須進(jìn)行系統(tǒng)的移植,移植就是把單片機(jī)的硬件資源,比如說(shuō)中斷的打開(kāi)和關(guān)閉,定時(shí)器,堆棧的處理等和ucos系統(tǒng)的內(nèi)核關(guān)聯(lián)起來(lái),比如說(shuō)我們這個(gè)內(nèi)核文件需要關(guān)閉中斷了,那么它是不知道你是用什么單片機(jī),要怎么關(guān)閉單片機(jī)中斷的,只要靠你來(lái)寫(xiě)一個(gè)關(guān)閉中斷的函數(shù),然后把這個(gè)函數(shù)地址賦值給它們的相關(guān)函數(shù)指針變量。同樣的,我們這個(gè)系統(tǒng)內(nèi)核也是需要用到單片機(jī)一些資源的,比如說(shuō)10ms的定時(shí)時(shí)間,打開(kāi)和關(guān)閉中斷。所以我們單片機(jī)來(lái)實(shí)現(xiàn)這個(gè)過(guò)程就叫移植,那么我們這個(gè)內(nèi)核移植非常簡(jiǎn)單,大家可以通過(guò)這個(gè)來(lái)理解一些操作系統(tǒng)的移植原理也會(huì)比較容易,移植的流程:
- 1、把
OS_ClockInterruptHandle()
函數(shù)放到單片機(jī)定時(shí)器中斷處理函數(shù)里,定時(shí)頻率10ms - 2、重寫(xiě)單片機(jī)總中斷開(kāi)關(guān)
- 3、通過(guò)
OS_CPUInterruptCBSRegister()
函數(shù)把內(nèi)核中斷處理函數(shù)指針指向單片機(jī)總中斷開(kāi)關(guān)處理函數(shù)。
到此這篇關(guān)于嵌入式C語(yǔ)言輕量級(jí)程序架構(gòu)內(nèi)核編寫(xiě)的文章就介紹到這了,更多相關(guān)C語(yǔ)言輕量級(jí)程序內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C語(yǔ)言陷阱與缺陷之?dāng)?shù)組越界訪問(wèn)詳解
這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言的數(shù)組越界訪問(wèn),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來(lái)幫助2022-02-02判斷整數(shù)序列是否為二元查找樹(shù)的后序遍歷結(jié)果的解決方法
本篇文章是對(duì)判斷整數(shù)序列是否為二元查找樹(shù)的后序遍歷結(jié)果的解決方法進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-05-05C++詳細(xì)實(shí)現(xiàn)紅黑樹(shù)流程詳解
今天我要跟大家介紹二叉搜索樹(shù)中的另一顆樹(shù)——紅黑樹(shù),它主要是通過(guò)控制顏色來(lái)控制自身的平衡,但它的平衡沒(méi)有AVL樹(shù)的平衡那么嚴(yán)格2022-06-06C語(yǔ)言實(shí)現(xiàn)小小圣誕樹(shù)源代碼
圣誕節(jié)當(dāng)然要有個(gè)圣誕樹(shù)了,今天給你們用C語(yǔ)言編寫(xiě)一個(gè)雪夜圣誕樹(shù),這篇文章主要給大家介紹了關(guān)于C語(yǔ)言實(shí)現(xiàn)小小圣誕樹(shù)的相關(guān)資料,需要的朋友可以參考下2023-12-12C++模板基礎(chǔ)之函數(shù)模板與類模板實(shí)例詳解
C++ 除了支持函數(shù)模板,還支持類模板(Class Template),所以下面這篇文章主要給大家介紹了關(guān)于C++模板基礎(chǔ)之函數(shù)模板與類模板的相關(guān)資料,需要的朋友可以參考下2021-06-06數(shù)據(jù)結(jié)構(gòu)之AVL樹(shù)詳解
這篇文章主要介紹了數(shù)據(jù)結(jié)構(gòu)之AVL樹(shù)詳解,本文非常細(xì)致的講解了AVL樹(shù)的基礎(chǔ)知識(shí)、AVL樹(shù)的旋轉(zhuǎn)操作、AVL數(shù)的插入和刪除操作等,需要的朋友可以參考下2014-08-08