【嵌入式外设精学】Day01|GPIO 输入:上拉、下拉、浮空怎么选
今天解决:按键和空闲线到底该上拉还是下拉?为什么悬空脚会“乱跳”?
目录
- 今天解决什么问题
- 原理
- 代码示例
- 常见误区
- 自测
- 答案
1. 今天解决什么问题
- 按键有时灵、有时不灵
- 没接东西的引脚读数乱跳
- 不知道“上拉/下拉/浮空”在电路上到底意味着什么
一句话:输入脚在空闲时必须有确定电平(高或低),不能靠运气。
2. 原理
2.1 三种输入方式
| 方式 | 空闲时脚上的电平 | 适合 |
|---|---|---|
| 上拉 | 被电阻拉到高 | 键按下接地时读到 0 |
| 下拉 | 被电阻拉到低 | 键按下接电源时读到 1 |
| 浮空 | 没人定电平 | 仅当外部一直有器件驱动 |
浮空 = 高阻抗,像一根天线,噪声会当信号,中断可能误触发。
2.2 和按键怎么配对
硬件上按键把脚短接到哪一端,输入就配相反的默认电平:
| 硬件 | 配置 | 按下 | 松开 |
|---|---|---|---|
| 键一端接地 | 上拉输入 | 读 0 | 读 1 |
| 键一端接 3.3V | 下拉输入 | 读 1 | 读 0 |
配反了:怎么按读数都不变。
2.3 内部上拉 vs 外部上拉
| 内部 | 外部 | |
|---|---|---|
| 优点 | 省元件,软件开一下就行 | 更“有力”,抗干扰好 |
| 缺点 | 电阻偏大,力偏弱 | 要焊电阻 |
| 建议 | 板载短按键 | 长线、噪声大、I2C 等 |
I2C 这类开漏总线,一般必须外部上拉,不能只靠内部。
2.4 为什么有时“阈值边上”会抖
脚电压刚好落在芯片认 0 / 认 1 的交界区时,轻微噪声就会来回判。
所以:电压要尽量靠“确定的高”或“确定的低”,并留出噪声余量。
3. 代码示例
#include"stm32f4xx.h"#include<stdbool.h>voidkey_gpio_init(void){GPIO_InitTypeDef g;GPIO_StructInit(&g);g.GPIO_Pin=GPIO_Pin_0;g.GPIO_Mode=GPIO_Mode_IN;g.GPIO_PuPd=GPIO_PuPd_UP;/* 键接地 → 上拉 */GPIO_Init(GPIOA,&g);}/* 读原始电平:1=高,0=低 */boolkey_raw_is_low(void){returnGPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0)==Bit_RESET;}/* 极性统一:1 = 按下 */boolkey_is_pressed(void){returnkey_raw_is_low();/* 上拉+接地,按下为低 */}消抖(在定时器里周期调用,不要在死循环里delay):
#include<stdbool.h>#include<stdint.h>typedefstruct{bool raw_last;bool stable;uint8_tcnt;}key_filter_t;/* 1ms 调一次;true 表示稳定按下 */boolkey_filter_update(key_filter_t*f,bool pressed_now){if(pressed_now==f->raw_last){if(f->cnt<15u){f->cnt++;}}else{f->raw_last=pressed_now;f->cnt=0u;}if(f->cnt>=10u){f->stable=f->raw_last;}returnf->stable;}4. 常见误区
| 误区 | 正解 |
|---|---|
| 空脚不用配,放着就行 | 要上下拉或设为输出确定电平 |
| 内部上拉一定能替代 I2C 上拉 | 不行 |
读键直接if(pin)就完事 | 要消抖,并统一“按下=1” |
| 5V 器件随便接 3.3V 脚 | 可能损坏,先看是否 5V-tolerant |
5. 自测
- 按键一端接 3.3V,希望松开读 0、按下读 1,输入怎么配?
- 为什么中断唤醒的键,更建议硬件上拉而不是只靠内部?
6. 答案
- 下拉输入。
- 空闲电平更确定,抗干扰更好,上电/睡眠阶段也不容易误唤醒。
作者:shuifanyu
标签:GPIO上拉下拉按键嵌入式