03-GPIO输入.md 6.2 KB

03-GPIO输入

按键原理

graph LR
    subgraph KEY_CIRCUIT
        VCC["3.3V"] --> R_PULL["上拉电阻\n(10kΩ)"]
        R_PULL --> KEY_PIN["GPIO Pin"]
        KEY_PIN --> BUTTON["按键\n(按下→GND)"]
        BUTTON --> GND["GND"]
    end
    
    subgraph SIGNAL_FLOW
        KEY_PRESSED["按下"] --> LOW["低电平 (0V)"]
        KEY_RELEASED["松开"] --> HIGH["高电平 (3.3V)"]
    end

机械抖动

阶段 时间 电平状态
按下 ~1ms 多次跳动(振荡)
稳定 >5ms 稳定低电平
松开 ~1ms 多次跳动(振荡)

消抖方式

方式 电路/代码 延时
硬件消抖 RC 低通滤波 (R=10kΩ, C=100nF, τ=1ms) 无软件延时
软件消抖 检测到变化后 Delay 10~20ms 再读一次 占用 CPU

软件消抖流程:

检测电平变化
  → Delay_ms(15)
  → 再次读取
  → 确认电平一致 → 有效按键

传感器模块原理

graph TD
    subgraph SENSOR_MODULE
        LIGHT_DEP["光敏电阻"] --> DIVIDER["分压电路"]
        THERMISTOR["热敏电阻"] --> DIVIDER
        MIC["麦克风+放大"] --> DIVIDER
        DIVIDER --> COMPARATOR["LM393 电压比较器"]
        REF["电位器设定阈值"] --> COMPARATOR
        COMPARATOR --> DO["DO (数字输出)"]
        COMPARATOR --> AO["AO (模拟输出)"]
    end
    
    DO --> MCU_PIN["STM32 GPIO"]

LM393 比较器:同相端(+) > 反相端(-) → 输出高电平(开漏,需上拉)。

API 表格

GPIO 输入函数

函数 原型 说明
GPIO_ReadInputDataBit uint8_t GPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin) 读取单个引脚电平
GPIO_ReadInputData uint16_t GPIO_ReadInputData(GPIO_TypeDef* GPIOx) 读取整个 IDR 寄存器
GPIO_ReadOutputDataBit uint8_t GPIO_ReadOutputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin) 读取 ODR 位
GPIO_ReadOutputData uint16_t GPIO_ReadOutputData(GPIO_TypeDef* GPIOx) 读取整个 ODR

GPIO 输入模式配置

// 上拉输入(常用 — 按键接 GND 适用)
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;   // 上拉输入
GPIO_Init(GPIOB, &GPIO_InitStructure);

// 下拉输入(按键接 VCC 适用)
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;   // 下拉输入
GPIO_Init(GPIOB, &GPIO_InitStructure);

完整代码示例

按键控制 LED (PB0 → PC13)

#include "stm32f10x.h"
#include "Delay.h"

int main(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    
    // 开启时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
    
    // PC13 推挽输出 (LED)
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_Init(GPIOC, &GPIO_InitStructure);
    
    // PB0 上拉输入 (按键 → GND)
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
    GPIO_Init(GPIOB, &GPIO_InitStructure);
    
    // LED 初始熄灭 (板载低电平亮)
    GPIO_SetBits(GPIOC, GPIO_Pin_13);
    
    uint8_t KeyFlag = 0;        // 按键释放标志
    uint8_t LedState = 0;       // LED 状态
    
    while (1)
    {
        // 检测按键按下 (PB0 到 GND, 低电平)
        if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_0) == 0)
        {
            Delay_ms(15);       // 软件消抖
            if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_0) == 0 && KeyFlag == 0)
            {
                KeyFlag = 1;    // 标记按下
                LedState = !LedState;
                
                if (LedState)
                    GPIO_ResetBits(GPIOC, GPIO_Pin_13);  // 亮
                else
                    GPIO_SetBits(GPIOC, GPIO_Pin_13);     // 灭
            }
        }
        else
        {
            KeyFlag = 0;        // 松手重置
        }
    }
}

光敏传感器控制蜂鸣器

传感器 DO 接 PA0,检测到光强低于阈值时(DO=低电平)蜂鸣器响。

#include "stm32f10x.h"
#include "Delay.h"

int main(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
    
    // PC9 推挽输出 (蜂鸣器)
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_Init(GPIOC, &GPIO_InitStructure);
    
    // PA0 上拉输入 (光敏 DO, 未触发=高, 触发=低)
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    
    GPIO_ResetBits(GPIOC, GPIO_Pin_9);  // 蜂鸣器初始关闭
    
    while (1)
    {
        if (GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0) == 0)
        {
            // 光线不足 → 蜂鸣器
            GPIO_SetBits(GPIOC, GPIO_Pin_9);
        }
        else
        {
            GPIO_ResetBits(GPIOC, GPIO_Pin_9);
        }
        Delay_ms(50);   // 防抖采样间隔
    }
}

常见坑点/注意事项

  1. 浮空输入 (IN_FLOATING) 电平不确定 — 引脚悬空时电平振荡,建议用 IPU/IPD 或外接上拉/下拉
  2. 按键抖动造成多次触发 — 必须软件消抖(10~20ms 延时再读)或硬件 RC 滤波
  3. 传感器模块 DO 引脚电平 — 多数模块 DO 高电平表示未触发(比较器输出开路需板上拉),读取时注意逻辑
  4. GPIO_ReadInputDataBit 返回值 — 返回 Bit_SET(1)Bit_RESET(0),可直接和 0/1 比较
  5. LED 极性 — 确认板载 LED 是低电平亮还是高电平亮,否则效果相反
  6. 上拉/下拉输入读取的是外部电平 — 和 GPIO_ReadOutputDataBit 读 ODR 不同
  7. 按键按下无反应 — 检查按键连接:一端接 GND,另一端接 GPIO;用万用表测按下时引脚对地电阻
  8. 按键悬空时误触发 — 内部上拉电阻约 30kΩ~50kΩ,若环境干扰强需外接 10kΩ 上拉/下拉