美文网首页单片机学习程序员
嵌入式开发系列教程(五) 嵌入式系统软件设计(上)

嵌入式开发系列教程(五) 嵌入式系统软件设计(上)

作者: qianlihu | 来源:发表于2017-04-07 10:28 被阅读144次
embedded.png

正如上图所示,一般来讲,嵌入式软件都是接受到一个事件,然后处理。简单的可以是一个按键点灯程序。检测到按键便是一个事件,点灯便是事件的处理。

用代码可以这样表达

static void LedOn()   \\点亮一个LED
{
    ...  
}
static int isKeyDown() \\检测按键是否按下
{
    ...
}

int main()
{
    while(1){
        if(isKeyDown())  //事件检测  
            LedOn();     //事件处理
    }
}

可是如果我们要为刚刚的软件实现再添加一个温度过高预警功能呢?

static void LedOn()   \\点亮一个LED
{
    ...  
}
static int isKeyDown() \\检测按键是否按下
{
    ...
}

static void Alarm()  \\预警
{
    ...
}
static int isTemperatureHigh()检测温度是否过高
{
    ...
}

int main()
{
    while(1){
        if(isKeyDown())           //事件检测  
            LedOn();             //事件处理
        if(isTemperatureHigh())  //事件检测  
            Alarm();             //事件处理
    }
}

我们看到,随着事件的增多,main函数里面的内容势必越来越多,代码的可读性越来越差。我们先给出一个解决方案。


typedef void (*eventHandler)(); //函数指针的声明

eventHandler findEventHandler(int event) //根据event编号,寻找eventHandler 
{
    ...
}

int Event()
{
    if(...)
        return event  //有事件产生,返回事件编号
    return -1; //没有事件产生,返回-1
}

int main()
{
    int event;
    eventHandler func;
    while(1){
        event = Event();     //事件检测
        if(event != -1){
            func = findEventHandler(event);  //事件匹配
            func();                           //事件处理
        }
    }
}

现在问题的难点,变成了怎么样实现event和eventHandler的绑定。

typedef void (*eventHandler)(); //函数指针的声明

static int EVENT = 0;   //int为16bit

static int firstBitEqualOne(int event) //返回event中第一个等于1的bit位
{
    ...
}
static void setBit(int event,int pos) //将event的第pos位置1
{
    ....
}

void keyDownEvent()    //在中断中实现
{
    if(isKeyDown())
        setBit(EVENT,KEYDONW);   //设置事件
}

static void LedOn()   \\点亮一个LED
{
    ...  
}

#define KEYDOWN     3   //按键按下的事件为3
static eventHandler[16] = {NULL,NULL,NULL,LedOn,NULL ....};//LedOn的数组下标为3



eventHandler findEventHandler(int event) //根据event编号,寻找eventHandler 
{
    return eventHandler[event];
}

int Event()
{
    if(EVENT != 0)
        return firstBitEqualOne(EVENT)  //有事件产生,返回事件编号
    return -1; //没有事件产生,返回-1
}

int main()
{
    int event;
    eventHandler func;
    while(1){
        event = Event();     //事件检测,可以检测到按键按下
        if(event != -1){
            func = findEventHandler(event);  //事件匹配,可以匹配到LedOn函数
            func();                           //事件处理,调用LedOn函数
        }
    }
}

这种匹配方案比较节省资源,写起来也比较简单。我们对比一下有无事件处理两种框架的实现方式

static void LedOn()   \\点亮一个LED,有无事件处理框架,代码都一样
{
    ...  
}

static int isKeyDown() \\检测按键是否按下,需要在中断中配合标志位
{
    ...
}

void keyDownEvent()    //在中断中实现 ,事件某种程度上实现了标志位的功能。
{
    if(isKeyDown())
        setBit(EVENT,KEYDONW);   //设置事件
}

//带有事件处理框架的程序,多了一步事件注册的代码,如下
#define KEYDOWN     3   //按键按下的事件为3
static eventHandler[16] = {NULL,NULL,NULL,LedOn,NULL ....};//LedOn的数组下标为3

//无事件处理框架
int main()
{
    while(1){
        if(isKeyDown())  //事件检测  
            LedOn();     //事件处理
        if(...)         //其他事件,每添加一个事件都需要修改main的执行流,容易产生错误
            ...
    }
}
//事件处理框架,main函数不用改动
int main()
{
    int event;
    eventHandler func;
    while(1){
        event = Event();     //事件检测,可以检测到按键按下
        if(event != -1){
            func = findEventHandler(event);  //事件匹配,可以匹配到LedOn函数
            func();                           //事件处理,调用LedOn函数
        }
    }
}

至此,我们已经完成了一个简单的事件处理框架,可是,温度采集等定时采集任务怎么实现?事件处理函数中能够产生新事件么?,如果能要怎么处理,框架会在中断执行流和主执行流中执行,怎么保证数据的同步?这些问题后续文章我们再做介绍。

这是一个免费,开源的教程,如果你喜欢可以转发,也可以打赏奖励。 欢迎关注微信公众号小站练兵

相关文章

网友评论

    本文标题:嵌入式开发系列教程(五) 嵌入式系统软件设计(上)

    本文链接:https://www.haomeiwen.com/subject/lzacattx.html