裸机的软件架构

裸机软件架构的实践

对于一些应用场景要求不高的场合,跑裸机也是能够彻底知足需求,虽然如今的单片机性能愈来愈好,可是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);
        
        //...
    }
}

/****************************************************************/
相关文章
相关标签/搜索