2. LED闪烁
任务目标
在嵌入式开发板上控制一个LED以固定周期交替亮灭,通过延时函数实现循环闪烁。本案例聚焦于GPIO输出控制与延时循环的基本用法,不涉及中断或定时器外设。
环境与依赖
- 硬件:任意带LED的STM32开发板(如STM32F103C8T6 Blue Pill),LED接PC13(板上自带)或PA5
- 软件:Rust工具链(含thumbv7m-none-eabi目标)、cargo-flash或OpenOCD用于烧录
- Cargo依赖:
cortex-m、cortex-m-rt、panic-halt、embedded-hal、stm32f1xx-hal
完整实现代码
#![no_std]
#![no_main]
use panic_halt as _;
use cortex_m::peripheral::syst::SystClkSource;
use cortex_m_rt::entry;
use embedded_hal::digital::v2::OutputPin;
use stm32f1xx_hal::{pac, prelude::*, timer::Timer};
#[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:PC13推挽输出(Blue Pill板上LED)
let mut gpioc = dp.GPIOC.split(&mut rcc.apb2);
let mut led = gpioc.pc13.into_push_pull_output(&mut gpioc.crh);
// 配置SysTick作为延时源:1ms中断周期
let mut syst = cp.SYST;
syst.set_clock_source(SystClkSource::Core);
syst.set_reload(72_000_000 / 1000); // 72MHz / 1000 = 1ms
syst.clear_current();
syst.enable_counter();
syst.enable_interrupt();
// 使用TIM2作为阻塞延时(更精确,不依赖中断)
let mut timer = Timer::tim2(dp.TIM2, &clocks, &mut rcc.apb1);
timer.start(500.millis());
loop {
led.set_high().unwrap();
timer.wait();
led.set_low().unwrap();
timer.wait();
}
}
运行与烧录
- 创建新项目并添加依赖:
cargo init --name led_blink,在Cargo.toml中配置对应依赖及[profile.release]优化选项 - 编译:
cargo build --release - 烧录:
cargo flash --chip stm32f103c8 --release(需安装cargo-flash)
验证方法
烧录成功后,观察板上LED(PC13)是否以约1Hz频率(亮500ms、灭500ms)交替闪烁。若LED不亮或常亮,检查GPIO引脚编号是否与硬件连接一致;若闪烁频率异常,确认时钟配置中晶振频率是否与板载晶振匹配。
关键说明
本案例使用TIM2定时器实现阻塞延时,相比纯软件循环延时更精确且不占用CPU空转。SysTick部分代码仅作初始化示例,实际延时由TIM2完成。若需调整闪烁速度,修改timer.start()中的时长参数即可。LED引脚定义在gpioc.pc13处,更换引脚时同步修改此行及对应的GPIO端口时钟使能。