ESP32-S3 IDF编程第四课:中断
ESP32-S3 IDF编程第四课:中断
上一节教程里,我们用轮询的方式读取按键状态,虽然能用,但有个挺烦人的问题——CPU得一直空转等着,白白浪费了单片机的性能。
有没有更聪明的办法?当然有,这就是咱们今天的主角:中断。
什么是中断?
打个生活中的比方你就懂了:
- 轮询:就像你每隔5秒抬头看看门口有没有人,哪怕根本没人来,你也得一直抬头、低头、抬头……累不累?
- 中断:就像门铃。平时你该看书看书、该喝茶喝茶,门铃“叮咚”一响,你再去开门。
ESP32-S3的中断就是这个意思:按键按下的瞬间,会产生一个电信号,CPU会立刻暂停手头的活儿,跑去执行一段专门处理按键的代码(这叫中断服务函数),处理完了再回来接着干刚才的事。效率直接拉满。
硬件接线
接法和上一课一模一样,不用改:
- 按键一脚接 3.3V
- 另一脚接 GPIO2
- 重要提醒:最好给GPIO2接个下拉电阻(比如10kΩ到GND),或者像我们代码里做的那样,直接启用内部下拉。不然引脚悬空,电平飘忽不定,可能会瞎触发中断。
上代码,直接看
下面就是完整的中断实现,别被代码长度吓到,核心就那几步,我慢慢拆解。
1 |
|
核心要点掰开揉碎
1. 神奇的 IRAM_ATTR
中断服务函数前面那个 IRAM_ATTR 绝对不能省。ESP32的代码通常放在外部Flash里,读取有延迟。IRAM_ATTR 就是告诉编译器:“这代码很重要,给我塞进内部RAM里,随叫随到!” 这样中断响应才够快。
2. 中断到底触发了个啥?
咱们代码里用的是 GPIO_INTR_NEGEDGE,也就是下降沿触发。结合咱们的电路(按键接3.3V,GPIO2有下拉电阻),它的工作流程是这样的:
- 没按按键时:GPIO2被下拉电阻拽到低电平(0)。
- 按下瞬间:GPIO2接通3.3V,电平从低变高(上升沿)。
- 松开瞬间:GPIO2断开3.3V,被下拉电阻重新拽回低电平(下降沿)。
所以,我们抓的就是“松开”或者“按下后弹起”的那个瞬间。如果你想在“按下”的瞬间就触发,把 GPIO_INTR_NEGEDGE 改成 GPIO_INTR_POSEDGE 就行了。
关于中断类型的更多选项,可以看这个表:
GPIO_INTR_DISABLE:关了中断,纯轮询用。GPIO_INTR_POSEDGE:上升沿触发(电平从0变1)。GPIO_INTR_NEGEDGE:下降沿触发(电平从1变0)。GPIO_INTR_ANYEDGE:不管上升还是下降,都触发。GPIO_INTR_LOW_LEVEL/HIGH_LEVEL:电平触发,会一直不停触发,新手慎用!
3. ISR里的“禁忌”
在 button_isr_handler 这个中断服务函数里,有三件事千万别干:
- ❌ 别用
printf打印东西(太慢了!)。 - ❌ 别用
vTaskDelay之类的延时函数。 - ❌ 别执行任何耗时的计算。
那我想打印怎么办?标准做法就是咱们代码里演示的——用队列 (xQueueSendFromISR) 把消息传给外面的任务,让任务去慢慢处理。专业术语叫“将中断处理推迟到任务中”。
4. 中断配置三步走,记牢了
gpio_config:设置引脚的intr_type,告诉它你要用中断了。gpio_install_isr_service:给整个芯片的中断系统“开机”(整个程序只开一次)。gpio_isr_handler_add:把你的中断服务函数和具体的引脚“拴”在一起。
等等!出问题了!怎么打印了一大堆?
当你兴冲冲编译烧录,按下按键,串口输出可能是这样的:
1 | 中断触发!按键按下了,GPIO: 2 |
哇,我就轻轻按了一下,它怎么跟疯了一样?
原因很简单:按键抖动。
我们理想中的按键波形是方方正正的:
但实际上,机械按键的触点碰撞,波形是这样的“毛刺”:
那一堆密密麻麻的毛刺,每一个都可能被我们的中断当成一次“按下”,所以才会疯狂触发。这就是传说中的抖动。
怎么治这个“多动症”?
有两种药方:软件消抖 和 硬件消抖。
方法一:软件消抖(加个状态机)
在代码里加一个简单的状态机,忽略掉那些短时间内的重复触发。
1 | typedef enum { |
逻辑解释:第一次中断进来,我们记个时间。如果在20毫秒内又来了一堆中断,我们全部忽略。直到消停20毫秒后,才认定是一次“有效按下”。
方法二:硬件消抖(最简单粗暴)
在按键两端并联一个0.1uF到1uF的小电容,利用电容的充放电特性,把那些毛刺给“吸”平。硬件一劳永逸,但需要你动动烙铁。
轮询 vs 中断,终极PK
| 对比项 | 轮询 | 中断 |
|---|---|---|
| CPU占用 | 一直占着,空转烧功耗 | 几乎为0,随叫随到 |
| 响应速度 | 看你轮询的勤快程度 | 微秒级,飞快 |
| 代码难度 | 简单直接 | 稍微复杂一点点 |
| 适合场合 | 状态需要持续监测 | 事件驱动的活儿(比如按键) |
下课小结
这节课我们成功给按键插上了“中断”的翅膀,让CPU彻底解放了。总结一下今天的干货:
- 中断原理:CPU不用空转,事件来了再处理。
- IRAM_ATTR:让中断函数跑在快车道上。
- ISR与队列:中断里只传消息,重活扔给任务干。
- 中断三步走:配置、安装、绑定。
- 按键抖动:知道了为什么按一下会触发好多次,以及怎么用软件状态机或硬件电容干掉它。
下一节课,咱们可以玩玩更有意思的,比如用定时器来做一个更优雅的消抖,或者用编码器旋钮。你觉得呢?
如果文章对你有用,欢迎随意赞赏~有问题评论区见!



