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

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

作者: 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