目标:读取按键和传感器模块电平,实现按键控制 LED、光敏传感器控制蜂鸣器
按键是最简单的输入设备,按下导通,松手断开。由于内部采用机械弹簧片,按下和松手瞬间会产生抖动(5-10ms 的不稳定电平):
理想波形: 高‾‾‾‾‾‾‾‾‾‾‾\_\_\_\_\_‾‾‾‾‾‾‾‾‾‾‾
实际波形: 高‾‾‾‾\_‾\_‾\_‾\_\_\_\_\_\_‾\_‾\_‾‾‾‾‾
↑按下 ↑稳定 ↑松手
抖动区 低电平 抖动区
软件消抖:检测到电平变化后,延时 10ms 再次读取确认。
传感器模块内部结构:
传感器(光敏/热敏/红外) ──┬── 定值电阻 ─── VCC
│
└── 分压输出(模拟) ── 电压比较器(LM393) ── DO(数字输出)
↑
参考电压(电位器分压)
| 函数 | 说明 |
|---|---|
HAL_GPIO_ReadPin(GPIOx, GPIO_PIN_x) |
读取引脚电平,返回 GPIO_PIN_SET(1) 或 GPIO_PIN_RESET(0) |
/* 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);
}
}