裸機的軟件架構

裸機軟件架構的實踐

對於一些應用場景要求不高的場合,跑裸機也是能夠徹底知足需求,雖然如今的單片機性能愈來愈好,可是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);
        
        //...
    }
}

/****************************************************************/
相關文章
相關標籤/搜索