飞机Telegram算计机器人 按键接到 STM32 后:GPIO 输入到底读到了什么
---
按键接到 STM32 后:GPIO 输入到底读到了什么
2026 年 9 月 22 日 | 作者:Zw-awa
---
核心洞察
按键没有把"我被按了一次"直接送进芯片,它只改变了 GPIO 引脚上的电平。 芯片读到的是高电平或低电平,不是"按钮"或"按了一次"这些带有含义的动作。[citation:72.48]
---
一、按键的物理接线
最基础的接法:
PB11 ──┬── 按键 ── GND
│
[内部上拉电阻] → VCC(3.3V)
| 按键状态 | 电气连接 | GPIO 读到的电平 |
|:--------:|:---------|:--------------:|
| 松开 | 内部上拉维持高电平 | 1 |
| 按下 | 通过按键接到 GND | 0 |
没有"按下=1"的规定。 1 和 0 只描述引脚电平,哪个代表"按下"由接线方式决定。当前接法是低电平有效。[citation:72.48]
---
二、GPIO 输入配置
#include "stm32f10x.h"
void Key_Init(void)
{
GPIOInitTypeDef GPIOInitStructure;
RCCAPB2PeriphClockCmd(RCCAPB2Periph_GPIOB, ENABLE);
GPIOInitStructure.GPIOMode = GPIOModeIPU; // 上拉输入
GPIOInitStructure.GPIOPin = GPIOPin1 | GPIOPin11;
GPIOInitStructure.GPIOSpeed = GPIOSpeed50MHz;
GPIOInit(GPIOB, &GPIOInitStructure);
}
GPIOModeIPU 的作用:在按键松开、外部没把引脚拉到地时,给引脚一个确定的默认高电平。 [citation:72.48]
---
三、读取电平 vs 翻译成"按下"
读电平——只回答"这一刻是高还是低"
uint8t KeyA_ReadLevel(void)
{
return (uint8t)GPIOReadInputDataBit(GPIOB, GPIOPin11);
}
翻译成"按下"
uint8t KeyA_IsPressed(void)
{
return KeyAReadLevel() == Bit_RESET;
}
电路细节留在按键模块里面,主循环只需要判断 KeyAIsPressed()。[citation:72.48]
---
四、从"当前电平"到"一次按键"
直接读电平的问题是:按住按键时,函数会一直返回"按下"。实际工程通常需要把"持续的低电平"整理成"一次按下事件":
uint8t KeyGetNum(void)
{
uint8_t KeyNum = 0;
volatile uint32_t i;
if (GPIOReadInputDataBit(GPIOB, GPIOPin1) == BitRESET)
{
// 消抖延时
for (i = 0; i < 72000U; i++) { }
// 等松手
while (GPIOReadInputDataBit(GPIOB, GPIOPin1) == BitRESET) { }
// 松手消抖
for (i = 0; i < 72000U; i++) { }
KeyNum = 1;
}
return KeyNum;
}
关键:确认按下 → 小延时 → 等松手 → 再延时 → 返回编号。避免手指一直按着时反复返回同一个值。[citation:72.48]
---
五、四种输入模式
| 模式 | 引脚内部 | 什么时候用 |
|:----|:---------|:-----------|
| GPIOModeIPU 上拉输入 | 内部接上拉电阻,没人驱动时读到高 | 按键另一端接 GND(最常见) |
| GPIOModeIPD 下拉输入 | 内部接下拉电阻,没人驱动时读到低 | 按键另一端接 VCC |
| GPIOModeIN_FLOATING 浮空输入 | 内部什么都不接,完全由外部决定 | 外部已有明确上拉/下拉,或由推挽输出驱动 |
| GPIOModeAIN 模拟输入 | 关掉数字输入通路 | ADC 采样模拟电压 |
浮空输入的陷阱
把 GPIOModeIPU 改成 GPIOModeIN_FLOATING,松开按键时 PB11 就没有内部上拉提供默认电平。此时引脚既没有明确接高也没有明确接低——周围的电线、手指和电磁干扰都可能影响它。 [citation:72.48]
浮空输入不是"自动随机数",而是电路没有为引脚规定稳定的 0 或 1。输入模式的选择必须和接线一起看。
---
六、常见排查链路
当按键读值不对时,按这条链路检查:[citation:72.48]
① 按键有没有把引脚接到正确的位置?
② 输入有没有配置默认上拉或下拉?
③ 读取的引脚是否和接线一致?
④ 上层动作有没有重复执行?(消抖处理了吗?)
---
七、关键差异速查
| 方向 | 芯片做的事 | 典型对象 |
|:----:|:----------|:---------|
| GPIO 输出 | 芯片主动改变引脚电平 | LED、继电器使能、电机方向 |
| GPIO 输入 | 芯片读取引脚当前电平 | 按键、开关、传感器 DO |
同一个引脚不能只看代码里的函数名判断功能,最终还要看它连接的电路。 [citation:72.48]
---
八、一句话总结
GPIO 输入读到的是瞬时电平,不是按键事件。 把电平翻译成"按下/松开"是程序的工作——上拉输入给引脚一个确定的默认状态,消抖逻辑把机械噪声过滤成干净的事件,状态机把连续电平整理成单次触发。读值不对先查接线和输入模式,不要盲目调代码。[citation:72.48]