嵌入式事件调度框架简单实现

在嵌入式开发中,事件调度、消息分发是非常核心的开发思想。无论是按键检测、串口消息、传感器数据上报,还是外设中断处理,本质都是「产生事件 - 匹配处理函数 - 执行逻辑」的流程。

很多新手写代码习惯用大量 if-elseswitch-case 堆砌事件逻辑,代码臃肿、扩展性极差,新增事件就要改主逻辑,极易出错。


一、框架整体设计思路

这套事件调度框架的核心逻辑只有三步:

  1. 定义事件:枚举所有系统需要的事件(event0~event9)
  2. 绑定处理函数:每个事件对应一个独立的处理函数
  3. 统一调度分发:通过总调度函数,根据事件类型自动匹配、执行对应逻辑

彻底告别冗长的 switch-case,做到高内聚、低耦合,新增事件只需要加枚举、写处理函数、注册数组即可,无需改动核心调度逻辑。


二、完整源码展示

以下是可直接编译运行的完整嵌入式事件调度代码,适配单片机、RTOS、裸机开发场景:

#include <stdio.h>
#include <stdint.h>
#define maxHandler 10

typedef enum {
	event0 = 0,
	event1,
	event2,
	event3,
	event4,
	event5,
	event6,
	event7,
	event8,
	event9
} Event;

// 事件结构体:存储事件所有信息
typedef struct Event_struct {
	Event event_t;		// 事件类型
	uint32_t timestamp;	// 事件时间戳
	uint16_t datalen;	// 事件数据长度
	void *data;			// 事件私有数据指针
};
// 事件处理函数指针类型
typedef void (*Handler)(Event_struct *Es);

// ------------------- 各个事件处理函数 -------------------
static void event0_handler(Event_struct *Es) {
	printf("--------------[event0]--------------\n");
	printf(" key=%d\n", Es->event_t);
	printf(" timestamp=%d\n", Es->timestamp);
	printf(" datalen=%d\n", Es->datalen);
}

static void event1_handler(Event_struct *Es) {
	printf("--------------[event1]--------------\n");
	printf(" key=%d\n", Es->event_t);
	printf(" timestamp=%d\n", Es->timestamp);
	printf(" datalen=%d\n", Es->datalen);
}

static void event2_handler(Event_struct *Es) {
	printf("--------------[event2]--------------\n");
	printf(" key=%d\n", Es->event_t);
	printf(" timestamp=%d\n", Es->timestamp);
	printf(" datalen=%d\n", Es->datalen);
}

static void event3_handler(Event_struct *Es) {
	printf("--------------[event3]--------------\n");
	printf(" key=%d\n", Es->event_t);
	printf(" timestamp=%d\n", Es->timestamp);
	printf(" datalen=%d\n", Es->datalen);
}

static void event4_handler(Event_struct *Es) {
	printf("--------------[event4]--------------\n");
	printf(" key=%d\n", Es->event_t);
	printf(" timestamp=%d\n", Es->timestamp);
	printf(" datalen=%d\n", Es->datalen);
}

static void event5_handler(Event_struct *Es) {
	printf("--------------[event5]--------------\n");
	printf(" key=%d\n", Es->event_t);
	printf(" timestamp=%d\n", Es->timestamp);
	printf(" datalen=%d\n", Es->datalen);
}

static void event6_handler(Event_struct *Es) {
	printf("--------------[event6]--------------\n");
	printf(" key=%d\n", Es->event_t);
	printf(" timestamp=%d\n", Es->timestamp);
	printf(" datalen=%d\n", Es->datalen);
}

static void event7_handler(Event_struct *Es) {
	printf("--------------[event7]--------------\n");
	printf(" key=%d\n", Es->event_t);
	printf(" timestamp=%d\n", Es->timestamp);
	printf(" datalen=%d\n", Es->datalen);
}

static void event8_handler(Event_struct *Es) {
	printf("--------------[event8]--------------\n");
	printf(" key=%d\n", Es->event_t);
	printf(" timestamp=%d\n", Es->timestamp);
	printf(" datalen=%d\n", Es->datalen);
}

static void event9_handler(Event_struct *Es) {
	printf("--------------[event9]--------------\n");
	printf(" key=%d\n", Es->event_t);
	printf(" timestamp=%d\n", Es->timestamp);
	printf(" datalen=%d\n", Es->datalen);
}

// 事件-处理函数 映射表(核心数组)
Handler Handler_function_arr[maxHandler] = {
	[event0] = event0_handler,
	[event1] = event1_handler,
	[event2] = event2_handler,
	[event3] = event3_handler,
	[event4] = event4_handler,
	[event5] = event5_handler,
	[event6] = event6_handler,
	[event7] = event7_handler,
	[event8] = event8_handler,
	[event9] = event9_handler
};

// 统一事件调度分发函数
void dispatch(Event_struct *Es) {
	// 边界校验,防止非法事件
	if (Es == NULL || Es->event_t < 0 || Es->event_t > maxHandler) {
		printf("[dispatch] 无效事件类型 %d\n", Es->event_t);
	}
	// 根据事件类型,直接调用对应处理函数
	Handler_function_arr[Es->event_t](Es);
}



int main() {
	Event_struct es;
	es.datalen = 12;
	es.event_t = event0;
	es.timestamp = 1324759;
	dispatch(&es);

	return 0;
}

三、核心代码逐块解析

1. 事件枚举定义

通过枚举统一管理所有事件,让事件类型标准化、可读性极强,杜绝魔法数字:

定义了 event0~event9 共10个事件,可根据项目需求自由增删。

2. 事件信息结构体

Event_struct 是事件的载体,存储一次事件的所有完整信息:

  • event_t:事件类型(对应枚举)
  • timestamp:事件触发时间戳,用于时序判断、日志排查
  • datalen:自定义数据长度
  • data:万能数据指针,可传递任意类型自定义数据(传感器值、报文数据等)

这是嵌入式事件框架的标准结构体设计,兼容性极强。

3. 函数指针封装

typedef void (*Handler)(Event_struct *Es)

定义事件处理函数的统一格式,所有事件处理函数必须遵循「入参为事件结构体、无返回值」的规范,保证调度统一。

4. 事件处理函数

每个事件独立对应一个 xxx_handler 函数,各司其职:

  • 逻辑解耦:不同事件的业务逻辑完全隔离,互不干扰
  • 方便维护:修改某一个事件逻辑,不会影响其他功能
  • 便于调试:每个事件独立日志,问题定位精准

5. 核心:函数映射数组

这是整个框架的灵魂!

通过数组下标和事件枚举一一对应,实现事件ID → 处理函数的精准映射。

相比 switch-case 判断,这种方式:

  • 执行效率更高(直接数组下标寻址,O(1)复杂度)
  • 扩展性拉满,新增事件只需新增枚举、新增函数、注册数组
  • 代码整洁,逻辑清晰

6. 统一调度函数 dispatch

所有事件的入口,承担分发和安全校验功能:

  • 做非空判断、事件范围校验,防止非法参数导致程序崩溃
  • 根据事件类型,自动调用对应的处理函数

业务层只需要「填充事件结构体 + 调用dispatch」,无需关心具体执行哪个函数。


四、代码运行效果

编译运行程序后,输出结果如下:

 --------------[event0]--------------
  key=0
  timestamp=1324759
  datalen=12

成功匹配 event0 事件,并打印事件所有参数。


五、框架核心优势(嵌入式开发刚需)

1. 彻底解耦,扩展性极强

传统写法:新增事件 → 修改switch主逻辑 → 容易改错、漏改。

本框架:新增事件 → 加枚举、写handler、注册数组 → 零侵入修改

2. 执行效率更高

switch-case 是分支判断(O(n)),函数数组是直接下标寻址(O(1)),事件越多,优势越明显。

3. 安全性高

自带空指针、非法事件校验,有效避免裸机、RTOS中常见的指针崩溃、越界问题。

4. 适配多数嵌入式场景

可直接用于:按键事件、串口报文、CAN总线消息、传感器中断、定时器事件、APP状态交互等所有场景。


六、总结

事件调度是嵌入式高级编程的核心思想,从裸机开发到RTOS、Linux嵌入式开发,这种「枚举+结构体+函数指针数组」的分发模型无处不在。

摒弃臃肿的 if/switch 分支,用标准化的事件框架写代码,不仅代码更优雅,项目可维护性、稳定性都会大幅提升,也是面试高频考点!

Hits: 0

    暂无评论

    发送评论 编辑评论

    
    				
    |´・ω・)ノ
    ヾ(≧∇≦*)ゝ
    (☆ω☆)
    (╯‵□′)╯︵┴─┴
     ̄﹃ ̄
    (/ω\)
    ∠( ᐛ 」∠)_
    (๑•̀ㅁ•́ฅ)
    →_→
    ୧(๑•̀⌄•́๑)૭
    ٩(ˊᗜˋ*)و
    (ノ°ο°)ノ
    (´இ皿இ`)
    ⌇●﹏●⌇
    (ฅ´ω`ฅ)
    (╯°A°)╯︵○○○
    φ( ̄∇ ̄o)
    ヾ(´・ ・`。)ノ"
    ( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
    (ó﹏ò。)
    Σ(っ °Д °;)っ
    ( ,,´・ω・)ノ"(´っω・`。)
    ╮(╯▽╰)╭
    o(*////▽////*)q
    >﹏<
    ( ๑´•ω•) "(ㆆᴗㆆ)
    😂
    😀
    😅
    😊
    🙂
    🙃
    😌
    😍
    😘
    😜
    😝
    😏
    😒
    🙄
    😳
    😡
    😔
    😫
    😱
    😭
    💩
    👻
    🙌
    🖕
    👍
    👫
    👬
    👭
    🌚
    🌝
    🙈
    💊
    😶
    🙏
    🍦
    🍉
    😣
    Source: github.com/k4yt3x/flowerhd
    颜文字
    Emoji
    小恐龙
    花!
    上一篇