2. 按键输入检测与消抖波形分析

任务说明

本案例实现一个基于MCU GPIO的按键输入检测程序,包含硬件消抖与软件消抖两种方式,并通过逻辑分析仪捕获按键按下/释放过程中的电平波形,验证消抖效果。核心目标:理解机械按键抖动特性,掌握软件消抖的边界条件判定方法。

硬件连接与测试拓扑

MCU STM32F103 PA0 PA1 GND SW1 (硬件消抖) SW2 (软件消抖) R1 10k VCC 3.3V R2 10k C1 100nF 逻辑分析仪 CH0 → PA0 CH1 → PA1 GND → 共地 PA0: SW1硬件消抖(RC低通) PA1: SW2软件消抖(10ms延时)

消抖原理与波形特征

机械按键在按下与释放瞬间,簧片接触会产生持续约5~20ms的不稳定抖动,表现为电平在高低之间多次跳变。硬件消抖采用RC低通滤波器(R=10kΩ,C=100nF,时间常数τ=1ms),将高频抖动分量滤除,使边沿变得平滑;软件消抖则通过延时采样,跳过抖动期后再确认电平状态。

代码实现

// main.c - 按键输入检测与消抖 (STM32F103, HAL库)
#include "stm32f1xx_hal.h"

// 按键引脚定义
#define BTN_HW_PORT   GPIOA
#define BTN_HW_PIN    GPIO_PIN_0   // PA0 - 硬件消抖按键(外部RC)
#define BTN_SW_PORT   GPIOA
#define BTN_SW_PIN    GPIO_PIN_1   // PA1 - 软件消抖按键

// 软件消抖延时(ms) - 需大于抖动周期(典型10ms)
#define DEBOUNCE_MS   10

static GPIO_InitTypeDef GPIO_InitStruct = {0};

// 按键状态枚举
typedef enum {
    KEY_RELEASED = 0,
    KEY_PRESSED
} KeyState_t;

// 软件消抖读取函数
// 返回: KEY_PRESSED(稳定按下) 或 KEY_RELEASED(稳定释放)
KeyState_t SW_Debounce_Read(GPIO_TypeDef* port, uint16_t pin) {
    // 第一次采样
    if (HAL_GPIO_ReadPin(port, pin) == GPIO_RESET) {
        // 延时跳过抖动期
        HAL_Delay(DEBOUNCE_MS);
        // 第二次采样确认
        if (HAL_GPIO_ReadPin(port, pin) == GPIO_RESET) {
            return KEY_PRESSED;
        }
    }
    return KEY_RELEASED;
}

// 硬件消抖读取函数(直接读取RC滤波后的电平)
KeyState_t HW_Debounce_Read(GPIO_TypeDef* port, uint16_t pin) {
    // RC滤波已消除抖动,直接读取即可
    return (HAL_GPIO_ReadPin(port, pin) == GPIO_RESET) ?
           KEY_PRESSED : KEY_RELEASED;
}

int main(void) {
    HAL_Init();
    __HAL_RCC_GPIOA_CLK_ENABLE();

    // 配置PA0, PA1为输入上拉
    GPIO_InitStruct.Pin = BTN_HW_PIN | BTN_SW_PIN;
    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
    GPIO_InitStruct.Pull = GPIO_PULLUP;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    // 配置PA5为LED输出(指示按键状态)
    GPIO_InitStruct.Pin = GPIO_PIN_5;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    KeyState_t hw_state, sw_state;

    while (1) {
        // 读取两个按键状态
        hw_state = HW_Debounce_Read(BTN_HW_PORT, BTN_HW_PIN);
        sw_state = SW_Debounce_Read(BTN_SW_PORT, BTN_SW_PIN);

        // 任一按键按下时点亮LED
        if (hw_state == KEY_PRESSED || sw_state == KEY_PRESSED) {
            HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET);  // LED亮
        } else {
            HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET);    // LED灭
        }
    }
}

逻辑分析仪观测点

验证方法与判定标准

  1. 编译与烧录:使用STM32CubeIDE编译工程,通过ST-Link烧录至目标板。
  2. 硬件连接:按上图连接电路,逻辑分析仪CH0接PA0,CH1接PA1,共地。
  3. 波形捕获:设置逻辑分析仪采样率≥1MHz,触发方式为下降沿,按下SW1和SW2各一次。
  4. 判定标准:
    • CH0(硬件消抖)波形:按下/释放边沿平滑,无任何毛刺跳变;
    • CH1(软件消抖)波形:存在明显抖动毛刺(5~20ms内多次跳变);
    • LED行为:每次稳定按下时点亮,释放时熄灭,无闪烁;
    • 软件消抖生效:CH1的毛刺虽存在,但程序在10ms后二次确认,LED不误触发。

预期结果:逻辑分析仪显示CH0为干净的数字波形,CH1在边沿处有毛刺;LED仅在按键稳定按下时点亮,快速抖动不会导致LED闪烁。若观察到CH0仍有毛刺,说明RC参数不足(增大C或R);若LED响应迟钝,说明DEBOUNCE_MS过大。