3. 按键控制LED
任务目标
本案例使用 Rust 在嵌入式开发板上实现按键控制 LED:通过轮询方式读取按键 GPIO 电平,检测到按下动作时切换 LED 的亮灭状态。核心学习点为 GPIO 输入模式配置、电平读取以及轮询逻辑。
硬件与依赖
- 开发板:STM32F103C8T6(Blue Pill)或兼容开发板
- 按键:一端接 PA0,另一端接 GND(按下为低电平)
- LED:正极经 220Ω 电阻接 PC13,负极接 GND(低电平点亮)
- Cargo 依赖:
cortex-m、cortex-m-rt、panic-halt、embedded-hal、stm32f1xx-hal
完整代码
#![no_std]
#![no_main]
use panic_halt as _;
use stm32f1xx_hal::{pac, prelude::*, timer::Timer};
#[cortex_m_rt::entry]
fn main() -> ! {
let dp = pac::Peripherals::take().unwrap();
let cp = cortex_m::Peripherals::take().unwrap();
let mut flash = dp.FLASH.constrain();
let mut rcc = dp.RCC.constrain();
let mut gpioa = dp.GPIOA.split(&mut rcc.apb2);
let mut gpioc = dp.GPIOC.split(&mut rcc.apb2);
// 配置 PC13 为推挽输出(LED 低电平点亮)
let mut led = gpioc.pc13.into_push_pull_output(&mut gpioc.crh);
led.set_high(); // 初始熄灭
// 配置 PA0 为浮空输入(按键按下接地)
let button = gpioa.pa0.into_floating_input(&mut gpioa.crl);
// 简单延时定时器(用于消抖)
let mut timer = Timer::syst(cp.SYST, &rcc.clocks).start_count_down(10.hz());
let mut last_state = button.is_high();
let mut led_on = false;
loop {
let current_state = button.is_high();
// 检测下降沿:从高电平变为低电平(按下)
if last_state && !current_state {
// 消抖延时
timer.wait();
// 再次确认按键仍处于按下状态
if button.is_low() {
led_on = !led_on;
if led_on {
led.set_low(); // 点亮
} else {
led.set_high(); // 熄灭
}
}
}
last_state = current_state;
timer.wait();
}
}
运行与验证
- 创建新工程并添加上述依赖,将代码写入
src/main.rs。 - 连接硬件:按键一端接 PA0、另一端接 GND;LED 正极经电阻接 PC13、负极接 GND。
- 编译并烧录:
cargo build --release,使用cargo flash或openocd烧录生成的.elf文件。 - 验证标准:按下按键时 LED 状态翻转(亮变灭或灭变亮);松开后状态保持;再次按下再次翻转。连续快速按动时,每次按下只翻转一次(消抖生效)。
关键说明
- 按键按下时 PA0 被拉低,读取为
false(低电平);释放时因浮空输入状态不确定,但本案例中按键仅在按下时接地,释放时引脚悬空。若需稳定电平,可在 PA0 与 VCC 之间加 10kΩ 上拉电阻,并将引脚配置改为into_pull_up_input。 - 消抖采用定时器延时约 100ms(10Hz 周期),在检测到下降沿后延时并二次确认电平,避免机械抖动导致多次翻转。
- 轮询周期由
timer.wait()控制,每次循环约 100ms,足以响应普通按键操作。