3. GPIO中断检测按键事件
任务说明
本案例实现按键控制LED:读取一个按键的输入状态,按下时点亮LED,松开时熄灭。使用STM32F103最小系统板(Blue Pill)作为目标硬件,通过Rust Embedded HAL编写裸机程序,不依赖任何操作系统。
硬件连接
- 按键:一端接PA0,另一端接GND(PA0内部上拉,按下为低电平)
- LED:正极经220Ω电阻接PC13,负极接GND(PC13输出低电平点亮)
实现代码
// Cargo.toml 依赖
// [dependencies]
// cortex-m = "0.7"
// cortex-m-rt = "0.7"
// panic-halt = "0.2"
// stm32f1xx-hal = { version = "0.10", features = ["stm32f103", "rt"] }
use cortex_m_rt::entry;
use panic_halt as _;
use stm32f1xx_hal::{
gpio::{gpioc::PC13, gpioa::PA0, Input, Output, PullUp, PushPull},
pac,
prelude::*,
};
#[entry]
fn main() -> ! {
// 获取外设访问权限
let dp = pac::Peripherals::take().unwrap();
let cp = cortex_m::Peripherals::take().unwrap();
// 初始化时钟(8MHz外部晶振,系统时钟72MHz)
let mut flash = dp.FLASH.constrain();
let mut rcc = dp.RCC.constrain();
let clocks = rcc.cfgr.use_hse(8.mhz()).sysclk(72.mhz()).freeze(&mut flash.acr);
// 初始化GPIO
let mut gpioa = dp.GPIOA.split(&mut rcc.apb2);
let mut gpioc = dp.GPIOC.split(&mut rcc.apb2);
// PA0配置为输入,内部上拉(按键按下时接地,读到低电平)
let button: PA0<Input<PullUp>> = gpioa.pa0.into_pull_up_input(&mut gpioa.crl);
// PC13配置为推挽输出(LED阳极接PC13,低电平点亮)
let mut led: PC13<Output<PushPull>> = gpioc.pc13.into_push_pull_output(&mut gpioc.crh);
// 初始化延时(用于按键消抖)
let mut delay = cp.SYST.delay(&clocks);
loop {
// 读取按键状态(按下为低电平)
if button.is_low() {
// 消抖延时
delay.delay_ms(20u16);
// 再次确认按键仍处于按下状态
if button.is_low() {
// 点亮LED(输出低电平)
led.set_low();
// 等待按键释放
while button.is_low() {
// 空循环等待
}
}
} else {
// 松开时熄灭LED(输出高电平)
led.set_high();
}
}
}
代码说明
程序初始化系统时钟为72MHz,将PA0配置为带上拉输入的按键引脚,PC13配置为推挽输出的LED引脚。主循环中持续读取按键状态:当检测到PA0为低电平(按键按下)时,先进行20ms延时消抖,再次确认按下状态后点亮LED,并等待按键释放;当PA0为高电平(按键松开)时,LED熄灭。消抖逻辑确保机械按键的抖动不会导致LED闪烁。
编译与烧录
# 编译(在项目根目录执行)
cargo build --release
# 烧录(使用OpenOCD + ST-Link)
openocd -f interface/stlink-v2.cfg -f target/stm32f1x.cfg -c "program target/thumbv7m-none-eabi/release/button_led verify reset exit"
验证方法
将编译生成的固件烧录到STM32F103开发板后,观察以下行为:
- 初始状态(未按键):LED保持熄灭
- 按下按键并保持:LED点亮
- 松开按键:LED熄灭
- 快速连续按动按键:LED状态跟随按键变化,无异常闪烁
判定标准:LED亮灭状态与按键按下/松开状态一一对应,且按键过程中无抖动导致的闪烁现象,即视为验证通过。