CHAPTER 06 / FIELD GUIDE

GPIO 输入:按键与消抖

从“读到电平”到“一次有效操作”。

建议用时 45 分钟先预测,再实验,再解释

没按时必须有确定电平

按键一端接 GPIO5,另一端接 GND,软件启用内部上拉。松开时输入为 1,按下时接地为 0。如果既没有上拉也没有下拉,开路输入会漂浮,读数可能不稳定。

四脚轻触按键有两组内部相连的引脚。断电时用通断档确定分组,选择按下后才互相连通的两端,不凭外形猜。

机械触点会抖动

一次按压可能在几毫秒内产生多次 0/1 变化。我们要求输入连续稳定 30 ms,才接受新状态;只有稳定状态从松开变成按下时,产生一次事件。

采样值改变 → 记录改变时间
保持同一采样值至少 30 ms → 更新稳定状态
稳定状态变成 0 → 发出一次“按下”事件

实验工程 · 03_button

每按一次翻转 LED;长按不会不停翻转。button_pressed 的完整实现位于 lab.c。

打开 main.c · 查看公共驱动 lab.c · 下载全部工程

#include "lab.h"
#include "esp_log.h"
void app_main(void) {
    led_init();
    button_init();
    bool on=false;
    for(;; ) {
        if(button_pressed()) {
            on=!on;
            gpio_set_level(LED,on);
            ESP_LOGI("button","on=%d",on);
        }
        vTaskDelay(pdMS_TO_TICKS(10));
    }
}

按顺序检查行为

  1. 慢按 10 次,检查翻转次数是否一致。
  2. 持续按住 2 秒,确认只有一次翻转。
  3. 快速按两次,观察能否区分;如果间隔短于消抖窗口,可能被合并。
  4. 把窗口改成 5 ms、100 ms,比较误触发和延迟。每次只改一个参数。
停下来想一想

为什么只写 if(gpio_get_level(5)==0) on=!on 不够?

查看推导与答案

按住期间每次循环都会翻转,还叠加机械抖动。消抖解决信号不稳定,边沿事件解决一次按压只触发一次,两件事都需要。

本章验收

本章一手资料

卡住时可以直接向我提问:附上章节号、工程名、接线和第一条错误日志。