正如上图所示,一般来讲,嵌入式软件都是接受到一个事件,然后处理。简单的可以是一个按键点灯程序。检测到按键便是一个事件,点灯便是事件的处理。
用代码可以这样表达
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函数
}
}
}
至此,我们已经完成了一个简单的事件处理框架,可是,温度采集等定时采集任务怎么实现?事件处理函数中能够产生新事件么?,如果能要怎么处理,框架会在中断执行流和主执行流中执行,怎么保证数据的同步?这些问题后续文章我们再做介绍。
这是一个免费,开源的教程,如果你喜欢可以转发,也可以打赏奖励。 欢迎关注微信公众号小站练兵
网友评论