前言
在这篇文章中,简单介绍了过长的if-else判断解决办法,里面提到了一个方法——函数表驱动法。由于本人在单片机开发中经常需要用到状态机轮询,这里可以使用switch-case和函数表驱动。下面给出一个在VS2013环境下编译通过的示例,方便以后移植。
代码清单
#include "stdafx.h"
//事件
/****************************************/
enum user_event{
EVENT_A,
EVENT_B,
EVENT_C,
EVENT_D,
};
//保存当前的事件状态
static user_event cur;
void setEvent(user_event c)
{
cur = c;
}
user_event getEvent(void)
{
return cur;
}
/******************************************/
//函数指针
typedef void (*EventFuncHandlePtr)(void);
//驱动表类型
// ev:事件
// phandle:事件处理函数指针
// next_ev:设置下一个事件状态
typedef struct
{
user_event ev;
EventFuncHandlePtr phandle;
user_event next_ev;
}EventTableType;
//事件处理函数
/*************************************/
void a_HandleFunc(void)
{
printf("A\r\n");
}
void b_HandleFunc(void)
{
printf("B\r\n");
}
void c_HandleFunc(void)
{
printf("C\r\n");
}
void d_HandleFunc(void)
{
printf("D\r\n");
}
/***************************************/
//函数驱动表
static EventTableType eventMap[] =
{
{ EVENT_A, a_HandleFunc, EVENT_B },
{ EVENT_B, b_HandleFunc, EVENT_D },
{ EVENT_C, c_HandleFunc, EVENT_A },
{ EVENT_D, d_HandleFunc, EVENT_D },
};
void funcSwitchCase(void)
{
switch (getEvent())
{
case EVENT_A:
a_HandleFunc();
setEvent(EVENT_B);
break;
case EVENT_B:
b_HandleFunc();
setEvent(EVENT_D);
break;
case EVENT_C:
c_HandleFunc();
setEvent(EVENT_A);
break;
case EVENT_D:
d_HandleFunc();
setEvent(EVENT_D);
break;
default:
break;
}
}
//函数驱动,替代switch-case
void funcTableDevice(void)
{
int i;
for (i = 0; i < sizeof(eventMap) / sizeof(eventMap[0]); i++){
if (getEvent() == eventMap[i].ev){
//事件处理函数
eventMap[i].phandle();
//设置下一个事件状态
setEvent(eventMap[i].next_ev);
break; //跳出
}
}
}
//主函数
/********************************************/
int main(int argc, _TCHAR* argv[])
{
//事件顺序:C-A-B-D
setEvent(EVENT_C);
//如果事件D没发生,循环执行
while (getEvent() != EVENT_D)
{
//funcSwitchCase();
funcTableDevice();
}
return 0;
}
编译运行后会打印输出:
C
A
B
请按任意键继续…