03-GPIO输入.md 4.0 KB

03 GPIO 输入(HAL)

目标:读取按键和传感器模块电平,实现按键控制 LED、光敏传感器控制蜂鸣器

原理简述

按键

按键是最简单的输入设备,按下导通,松手断开。由于内部采用机械弹簧片,按下和松手瞬间会产生抖动(5-10ms 的不稳定电平):

理想波形: 高‾‾‾‾‾‾‾‾‾‾‾\_\_\_\_\_‾‾‾‾‾‾‾‾‾‾‾
实际波形: 高‾‾‾‾\_‾\_‾\_‾\_\_\_\_\_\_‾\_‾\_‾‾‾‾‾
          ↑按下       ↑稳定      ↑松手
          抖动区      低电平     抖动区

软件消抖:检测到电平变化后,延时 10ms 再次读取确认。

传感器模块

传感器模块内部结构:

传感器(光敏/热敏/红外) ──┬── 定值电阻 ─── VCC
                        │
                        └── 分压输出(模拟) ── 电压比较器(LM393) ── DO(数字输出)
                                                    ↑
                                              参考电压(电位器分压)
  • 敏感电阻随外界物理量变化 → 分压变化 → 比较器二值化 → DO 输出数字信号(0/1)
  • AO 输出原始模拟电压(需 ADC 读取)

电路连接

  • KEY1(轻触按键):一端接 GND,一端接 PB0,内部上拉
    • 按下:PB0 = 低电平
    • 松开:PB0 = 高电平(上拉)
  • 光敏传感器模块
    • VCC → 3.3V, GND → GND
    • DO → PA0(数字输出)
    • AO → PA1(模拟输出,暂不接)

CubeMX 配置

  • PB0 → GPIO_Input,Pull-up
  • PA0 → GPIO_Input,Pull-up(传感器 DO)
  • 保持其他默认,不需要任何中断

关键 HAL API

函数 说明
HAL_GPIO_ReadPin(GPIOx, GPIO_PIN_x) 读取引脚电平,返回 GPIO_PIN_SET(1) 或 GPIO_PIN_RESET(0)

完整代码

按键控制 LED

/* main.c */
int main(void)
{
    HAL_Init();
    SystemClock_Config();
    MX_GPIO_Init();     // PB0_Input + PC13_Output

    uint8_t key_flag = 0;   // 防止一次按下触发多次

    while (1)
    {
        /* 检测按键按下(低电平有效) */
        if (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_0) == GPIO_PIN_RESET)
        {
            HAL_Delay(10);                      // 消抖
            if (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_0) == GPIO_PIN_RESET)
            {
                if (key_flag == 0)
                {
                    HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13);
                    key_flag = 1;               // 防止重复触发
                }
            }
        }
        else
        {
            key_flag = 0;                       // 松手后清零
        }
    }
}

松手沿检测(另一种更可靠的写法):

uint8_t pre_key = 1, cur_key = 1;

while (1)
{
    pre_key = cur_key;
    cur_key = (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_0) == GPIO_PIN_RESET) ? 0 : 1;

    if (pre_key != cur_key)         // 电平变化
    {
        HAL_Delay(10);              // 消抖
        if (cur_key == 1)           // 松手沿:上一次按下,这一次松开
        {
            HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13);
        }
    }
}

光敏传感器控制蜂鸣器

/* PA0(DO) 读取传感器输出 */
while (1)
{
    if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_RESET)
    {
        // 光线暗 → DO 输出低电平 → 蜂鸣器响
        HAL_GPIO_WritePin(GPIOC, GPIO_PIN_9, GPIO_PIN_RESET);  // 低电平驱动
    }
    else
    {
        // 光线亮 → DO 输出高电平 → 蜂鸣器关
        HAL_GPIO_WritePin(GPIOC, GPIO_PIN_9, GPIO_PIN_SET);
    }
}

常见坑点

  • ⚠️ 机械按键必须消抖,否则一次按下可能触发多次
  • ⚠️ GPIO 浮空输入时引脚悬空会导致电平不确定,务必使用上拉/下拉
  • ⚠️ 传感器模块的 DO/AO 区别:DO 是数字开关量,AO 是模拟电压(需要 ADC)
  • ⚠️ 按键按下为低电平是因为 GND 导通,设计电路时注意按键接法