裸機軟件架構的實踐
對於一些應用場景要求不高的場合,跑裸機也是能夠徹底知足需求,雖然如今的單片機性能愈來愈好,可是8bit的單片機,像stc8051/stc8052這些仍是應用在不少消費電子的領域,主要是成本便宜,操做簡單,只要軟件架構設計的合理,也是能夠知足大部分應用需求的,下面就來聊一聊裸機的軟件架構設計。架構
架構的組成
時間片輪詢法函數
時間片輪詢,是裸機中經常採用的一個軟件架構,顧名思義是在某一個時間段調用一個子任務,經過定時器定時來不停的輪詢。首先須要將一個大而雜的任務集,按照不一樣的功能來劃分紅不一樣的子任務,而後須要佔用MCU一個Timer資源,用於定時輪詢,依據具體的需求,來給每個子任務來分配不一樣的Task_Flag(即實時性較高的子任務,能夠設置10ms調用一次,實時性較低的子任務,能夠設置1000ms調用一次)。時間片輪詢法的好處是能夠合理的利用MCU的資源,不會讓一些實時性較低的子任務頻繁佔用MCU的資源,從而提升軟件系統的總體實時性。性能
分層設計思想ui
咱們先來看看通常分哪幾個層,這裏畫了一個UML圖,大體分爲如下幾個層:硬件驅動層、功能模塊層、業務邏輯處理層、應用層,層與層應該是相互獨立的,經過相應的調用接口來調用下一層的函數,從而實現層與層之間的解耦。spa
必備的C語言知識架構設計
函數指針、指針函數、結構體、位域、枚舉、指針、函數調用、函數傳參等設計
架構的實現
時間片輪詢法的僞代碼實現3d
typedef unsigned char uint8_t; typedef enum { Timer1ms_Cnt = 1, Timer10ms_Cnt = 10, Timer20ms_Cnt = 20, }eTimerCnt; volatile struct TimFlg { uint8_t TimFlg; uint8_t Timer1ms_Flg; uint8_t Timer10ms_Flg; uint8_t Timer20ms_Flg; }sTimFlg; void TimFlgInit(void) { uint8_t *pTimFlg = (uint8_t*)&sTimFlg; for(uint8_t i = 0; i < sizeof(sTimFlg)/sizeof(uint8_t); i++) { pTimFlg[i] = 0x00; } } void TaskFunc(void) { static uint8_t cnt1 = 0; static uint8_t cnt2 = 0; static uint8_t cnt3 = 0; if(1 == sTimFlg.TimFlg) { if(++cnt1 >= Timer1ms_Cnt) { sTimFlg.Timer1ms_Flg = 0x01; cnt1 = 0; } else { //do nothing; } if(++cnt2 >= Timer10ms_Cnt) { sTimFlg.Timer10ms_Flg = 0x01; cnt2 = 0; } else { //do nothing; } if(++cnt3 >= Timer20ms_Cnt) { sTimFlg.Timer20ms_Flg = 0x01; cnt3 = 0; } else { //do nothing; } sTimFlg.TimFlg = 0x00; } else { //do nothing; } } void TimerInit(void) { //programming code; } void TimerISR(void) { if(TRUE == InterruptEvent()) { sTimFlg.TimFlg = 0x01; //1ms的定時器 clear(InterruptFlg); } else { //do nothing; } }
分層設計的僞代碼實現指針
這裏用ADC採集來舉一個例子吧,玩過單片機的同窗應該都知道,ADC是單片機一個經常使用的外設資源,用來採集其餘設備輸入的電壓,若是涉及到幾路電壓同時採集的狀況,此時就須要開啓單片機的DMA功能,才能同時將幾個通道的電壓值存入到ADC的數據寄存器中,這裏就不過多描述,不懂的能夠去了解下,下面主要來看看軟件如何分層,在C語言程序設計中主要是用函數指針來實現層與層之間的解耦,分層設計的好處是當涉及到某一層代碼的變動,咱們只須要改當前層的函數,對其餘層的調用並無任何影響。code
/********************************Hw Driver Layer************************/ void HwCallBack(void); void AdcDmaInit(void); void AdcConvert(void); void HwCallBack(void) { AdcConvert(); } void AdcModuleInit(void) { AdcInit(); AdcDmaInit(); } void AdcInit(void) { ADC_GPIO_Init(); ADC_DMA_Enable(); ADC_Enable(); ADC_Calib(); } void AdcDmaInit(void) { DMA_Init(); DMA_Enable(); } void AdcConvert(void) { ADC_StartConvert(); while(!DMA_Trans()) { clear(DMA_Flg); } } /****************************************************************/ ---------------------------------------------------------------------------- /********************************Func Module Layer************************/ #define OK 1 #define ERR 0 void ReadBatCallBack(void); void ReadSenrCallBack(void); uint8_t ReadBatVol(void); uint8_t ReadSenrVol(void); void FmHanderFunc((void)(*CallBack)(void)) { if(NULL != CallBack) { CallBack(); } else { //do nothing; } } void ReadBatCallBack(void) { ReadBatVol(); } void ReadSenrCallBack(void) { ReadSenrVol(); } uint8_t ReadBatVol(void) { uint8_t BatVolSts; FmHanderFunc(HwCallBack); //do something; return BatVolSts; } uint8_t ReadSenrVol(void) { uint8_t SerVolSts; FmHanderFunc(HwCallBack); //do something; return SerVolSts; } /****************************************************************/ ---------------------------------------------------------------------------- /********************************Logical Business Layer************************/ #define LOWVOL 1 void WarningEvent(void); uint8_t LbHanderFunc(void (*CallBack)(void)) { uint8_t res; if(NULL != CallBack) { res = CallBack(); } else { res = ERR; } return res; } void WarningEvent(void) { uint8_t BatVolSts = 0; if(ERR != LbHanderFunc(ReadBatCallBack)) { BatVolSts = LbHanderFunc(ReadBatCallBack); if(LOWVOL == BatVolSts) { WarningLamp(); } else { //do nothing; } } else { //do nothing; } } /****************************************************************/ ---------------------------------------------------------------------------- /*********************************Application Layer*************************/ void AppHanderFuc(void (*CallBack)(void), uint8_t* TimerFlg) { if(NULL != CallBack) { if(1 == (*TimerFlg)) { CallBack(); *TimerFlg = 0; } else { //do nothing; } } else { //do nothing; } } int main(void) { SystemInit(); while(1) { AppHanderFuc(WarningEvent, (uint8_t*)&sTimFlg.Timer10ms_Flg); //... } } /****************************************************************/