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 比较器:同相端(+) > 反相端(-) → 输出高电平(开漏,需上拉)。
| 函数 | 原型 | 说明 |
|---|---|---|
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 |
// 上拉输入(常用 — 按键接 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);
#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); // 防抖采样间隔
}
}
IN_FLOATING) 电平不确定 — 引脚悬空时电平振荡,建议用 IPU/IPD 或外接上拉/下拉GPIO_ReadInputDataBit 返回值 — 返回 Bit_SET(1) 或 Bit_RESET(0),可直接和 0/1 比较GPIO_ReadOutputDataBit 读 ODR 不同