1. 事件驱动架构概述
各位同学好。我是老周,做了十几年嵌入式开发。今天咱们聊聊事件驱动架构——这个听起来有点玄乎,其实每天都在用的东西。
先问个问题:你写的单片机程序,是不是经常这样——
while(1) {
if(按键按下) { 处理按键 }
if(定时器到) { 处理定时 }
if(串口收到) { 处理数据 }
// 再检查一堆标志位
}
这种写法,我管它叫「轮询地狱」。项目小的时候还好说,功能一多,代码就乱成一锅粥。我在2015年做过一个智能家居网关项目,8个传感器、3路PWM、2路串口,全用轮询写。结果呢?加一个新功能,改了三天,还引入两个bug。从那以后,我开始认真研究事件驱动。
1.1 什么是事件驱动
事件驱动,说白了就是:系统不主动干活,等事情发生了再响应。
你想想看,现实世界就是事件驱动的。你坐在工位上,不会每秒钟检查一遍「有没有人找我」。而是等手机响了、有人喊你名字、或者邮件弹窗了,你才去处理。嵌入式系统也一样。
事件驱动架构的核心就三个东西:
- 事件源:谁产生事件?按键、定时器、串口中断、传感器触发……
- 事件队列:事件来了先排队,不丢不抢
- 事件处理器:谁负责处理?一个函数,或者一个状态机
核心思想:系统平时处于低功耗空闲状态,只有事件发生时,才唤醒CPU去处理。处理完继续睡。这才是嵌入式该有的样子。
我习惯把事件驱动比作「急诊室分诊台」。病人(事件)来了,护士(调度器)根据病情严重程度(优先级)安排就诊顺序。医生(处理函数)只看自己负责的病人。没有病人时,大家休息。高效、清晰、不浪费资源。
1.2 裸机 vs RTOS:一个真实的对比
很多初学者纠结:到底用裸机还是RTOS?我直接给你看数据。
| 对比维度 | 裸机轮询 | 裸机事件驱动 | RTOS |
|---|---|---|---|
| 代码复杂度 | 低,但功能多了就乱 | 中等,结构清晰 | 高,需要学API |
| 实时性 | 差,轮询周期决定 | 好,事件来了就处理 | 很好,优先级抢占 |
| 内存占用 | 极小,几百字节 | 小,1-2KB | 大,至少4-8KB堆栈 |
| 任务数量 | 3-5个还行 | 10-20个轻松 | 几十个没问题 |
| 调试难度 | 简单,单线程 | 中等,注意事件顺序 | 高,要处理优先级反转 |
| 功耗控制 | 差,CPU一直跑 | 好,空闲可休眠 | 好,有IDLE任务 |
| 学习成本 | 零 | 低,一天上手 | 高,至少一周 |
我个人的经验是:RAM小于4KB、任务少于10个、对实时性要求不是变态高的项目,裸机事件驱动完全够用。RTOS不是万能的,它带来的上下文切换开销和调试复杂度,在小项目里反而是负担。
我的建议:先学会裸机事件驱动,再去碰RTOS。你想想看,连事件队列都管理不好,怎么去理解消息队列和信号量?基础打牢了,上层建筑才稳。
1.3 为什么选择事件驱动
我直接说结论:事件驱动是裸机程序从「能跑」到「好维护」的分水岭。
给你讲个真实案例。2018年我做一款手持仪表,MCU是STM32F030,64KB Flash、8KB RAM。功能包括:按键扫描、LCD刷新、ADC采集、串口通信、蜂鸣器报警、电池管理。一共6个模块。
第一版用轮询写,main函数里一个200行的while循环。加一个「长按关机」功能,改了4个文件,测试发现ADC采样率被按键扫描拖慢了。为什么?因为轮询里按键去抖用了delay,把整个循环卡住了。
第二版改成事件驱动。按键按下只发一个事件,ADC采集完成发一个事件,串口收到数据发一个事件。main函数变成这样:
while(1) {
event_t evt;
if(event_queue_get(&evt)) {
event_dispatch(&evt);
} else {
// 没有事件,进入休眠
__WFI();
}
}
代码量从2000行降到1200行。加功能?加一个新的事件类型就行,不影响其他模块。功耗从15mA降到3mA,因为大部分时间CPU在睡觉。
这就是事件驱动的价值:
- 解耦:模块之间不直接调用,通过事件通信
- 可扩展:加功能不加复杂度
- 低功耗:没事就睡,有事才醒
- 可测试:每个事件处理器可以单独测试
注意:事件驱动不是银弹。如果你的系统有严格的时间同步需求(比如电机控制PWM周期精确到微秒),或者任务之间有复杂的依赖关系,那还是得上RTOS或者干脆上实时Linux。选型要因地制宜,别为了用而用。
1.4 事件驱动架构全景图
下面这张图,是我画的事件驱动裸机架构的核心结构。你看一遍,心里有个谱就行,后面每一章都会展开讲。
你看这个结构,数据流是单向的。事件源只管产生事件,丢进队列就走。调度器只管分发,不关心业务逻辑。处理器只管干活,不关心事件从哪来。每个模块各司其职,这就是架构的魅力。
嗯,第一章就到这里。记住一句话:事件驱动不是技术,是思维方式。后面每一章,我都会带着你从零搭一套完整的事件驱动框架。准备好了吗?