2. 按键控制LED

任务目标

使用ESP32开发板读取按键状态,实现每次按下按键时LED亮灭状态切换。通过本案例掌握GPIO数字输入配置、按键消抖处理以及基本的电平检测逻辑。

硬件准备

  • ESP32开发板(如ESP32-DevKitC)
  • 1个LED(推荐红色或蓝色)
  • 1个轻触按键
  • 1个220Ω限流电阻(LED用)
  • 1个10kΩ下拉电阻(按键用)
  • 面包板及杜邦线若干

电路连接

  • LED阳极 → GPIO2(通过220Ω电阻)
  • LED阴极 → GND
  • 按键一端 → GPIO4
  • 按键另一端 → 3.3V
  • GPIO4 → 10kΩ电阻 → GND(下拉电阻,确保未按下时读到低电平)

完整代码

#include <stdio.h>
#include "driver/gpio.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"

#define LED_GPIO      GPIO_NUM_2
#define BUTTON_GPIO   GPIO_NUM_4
#define DEBOUNCE_MS   20

void app_main(void)
{
    // 配置LED引脚为推挽输出
    gpio_config_t led_conf = {
        .pin_bit_mask = (1ULL << LED_GPIO),
        .mode = GPIO_MODE_OUTPUT,
        .pull_up_en = GPIO_PULLUP_DISABLE,
        .pull_down_en = GPIO_PULLDOWN_DISABLE,
        .intr_type = GPIO_INTR_DISABLE
    };
    gpio_config(&led_conf);

    // 配置按键引脚为输入,启用内部下拉(可替代外部下拉电阻)
    gpio_config_t btn_conf = {
        .pin_bit_mask = (1ULL << BUTTON_GPIO),
        .mode = GPIO_MODE_INPUT,
        .pull_up_en = GPIO_PULLUP_DISABLE,
        .pull_down_en = GPIO_PULLDOWN_ENABLE,
        .intr_type = GPIO_INTR_DISABLE
    };
    gpio_config(&btn_conf);

    bool led_state = false;
    int last_level = 0;
    int stable_level = 0;
    TickType_t last_change_time = 0;

    gpio_set_level(LED_GPIO, 0);

    while (1) {
        int current_level = gpio_get_level(BUTTON_GPIO);
        TickType_t now = xTaskGetTickCount();

        // 消抖:仅在电平变化持续超过DEBOUNCE_MS后确认状态
        if (current_level != stable_level) {
            if (now - last_change_time > pdMS_TO_TICKS(DEBOUNCE_MS)) {
                stable_level = current_level;
                // 检测到按下沿(从低到高)
                if (stable_level == 1 && last_level == 0) {
                    led_state = !led_state;
                    gpio_set_level(LED_GPIO, led_state ? 1 : 0);
                }
                last_level = stable_level;
            }
        } else {
            last_change_time = now;
        }

        vTaskDelay(pdMS_TO_TICKS(5));
    }
}

代码说明

代码采用软件消抖方式:按键状态变化后,等待20ms确认电平是否稳定,避免机械抖动导致误触发。仅在检测到按键从低电平变为高电平(按下动作)时翻转LED状态。GPIO4配置为输入并启用内部下拉电阻,因此未按下时读到低电平,按下时读到高电平。

编译与烧录

# 在项目目录下执行
idf.py set-target esp32
idf.py build
idf.py -p /dev/ttyUSB0 flash monitor

将/dev/ttyUSB0替换为实际串口设备名(Windows下为COMx)。

验证方法

  1. 烧录成功后,观察LED初始状态为熄灭。
  2. 按下按键并松开,LED应点亮。
  3. 再次按下并松开,LED应熄灭。
  4. 快速连续按动按键,每次按下LED状态都应可靠切换,无跳变或闪烁。

若LED状态切换不稳定或一次按下多次切换,可适当增大DEBOUNCE_MS值(如改为30或50)后重新编译烧录。