3. 按键输入检测

任务目标

在MCU上实现一个按键输入检测程序:通过轮询方式读取按键GPIO状态,检测按下与释放动作,并控制LED的亮灭切换。每次按下按键时LED状态翻转一次,松开时不重复触发。

硬件连接

  • 按键一端接GPIO(本例使用PA0),另一端接GND(低电平有效)
  • LED正极经限流电阻接GPIO(本例使用PC13),负极接GND
  • MCU内部启用PA0上拉电阻,未按下时读到高电平,按下时读到低电平

完整代码(STM32 HAL库)

// main.c 核心逻辑(基于STM32F103C8T6,HAL库)
#include "main.h"

GPIO_InitTypeDef GPIO_InitStruct = {0};

void GPIO_Init(void) {
    __HAL_RCC_GPIOA_CLK_ENABLE();
    __HAL_RCC_GPIOC_CLK_ENABLE();

    // PA0 按键输入,上拉
    GPIO_InitStruct.Pin = GPIO_PIN_0;
    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
    GPIO_InitStruct.Pull = GPIO_PULLUP;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    // PC13 LED输出
    GPIO_InitStruct.Pin = GPIO_PIN_13;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

    HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_SET); // 初始LED灭
}

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

    uint8_t last_button_state = 1;  // 上一次按键状态(1=未按下)
    uint8_t current_button_state;

    while (1) {
        current_button_state = HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0);

        // 检测下降沿:未按下(1) → 按下(0)
        if (last_button_state == 1 && current_button_state == 0) {
            HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13);
        }

        last_button_state = current_button_state;
        HAL_Delay(10);  // 简单消抖,10ms轮询间隔
    }
}

编译与烧录

  1. 使用STM32CubeIDE新建项目,选择芯片STM32F103C8T6
  2. 将上述代码替换main.c中对应内容(保留HAL_Init和时钟配置)
  3. 编译生成.hex文件,通过ST-Link烧录到开发板

验证方法

  • 初始状态:上电后LED处于熄灭状态
  • 按下按键:LED应立即点亮;松开按键,LED保持点亮
  • 再次按下:LED熄灭;松开后保持熄灭
  • 判定通过:每次按下按键LED状态翻转一次,且按住不松开时不会连续翻转(仅触发一次)

关键说明

  • 轮询间隔10ms兼作软件消抖,可滤除大部分机械抖动;若按键抖动明显,可增大到20ms
  • 检测下降沿(1→0)而非电平本身,确保一次按下只触发一次翻转
  • 若按键接法为高电平有效(另一端接VCC),需将Pull改为GPIO_PULLDOWN,并将检测条件改为上升沿(0→1)