1. 创建第一个RTOS任务
任务定义
本案例使用RTIC(Real-Time Interrupt-driven Concurrency)框架——一个基于Rust的嵌入式RTOS——在STM32F103开发板上创建并启动一个周期任务,驱动板载LED以1Hz频率闪烁。通过该最小可运行工程,理解RTOS中“任务”作为独立调度单元的基本概念:任务由静态声明定义、由调度器按优先级自动管理、任务体在无限循环中执行周期操作。
硬件与依赖准备
目标硬件:STM32F103C8T6蓝色药丸板(板载PC13 LED)。需要以下依赖:
# Cargo.toml
[dependencies]
cortex-m = "0.7"
cortex-m-rt = "0.7"
panic-halt = "0.2"
rtic = "1.1.4"
embedded-hal = "0.2.7"
nb = "1"
cortex-m-semihosting = "0.5" # 仅调试输出用
[dependencies.stm32f1xx-hal]
version = "0.10.0"
features = ["rt", "stm32f103"]
代码实现
// src/main.rs
#![no_main]
#![no_std]
use panic_halt as _;
use rtic::app;
#[app(device = stm32f1xx_hal::pac, peripherals = true)]
const APP: () = {
// 任务资源:LED引脚句柄
struct Resources {
led: stm32f1xx_hal::gpio::gpioc::PC13<stm32f1xx_hal::gpio::Output<stm32f1xx_hal::gpio::PushPull>>,
}
// 初始化:配置时钟、GPIO、启动周期任务
#[init]
fn init(ctx: init::Context) -> init::LateResources {
// 时钟配置:使用外部8MHz晶振,系统时钟72MHz
let mut flash = ctx.device.FLASH.constrain();
let mut rcc = ctx.device.RCC.constrain();
let clocks = rcc
.cfgr
.use_hse(8.MHz())
.sysclk(72.MHz())
.pclk1(36.MHz())
.freeze(&mut flash.acr);
// GPIO配置:PC13推挽输出
let mut gpioc = ctx.device.GPIOC.split(&mut rcc.apb2);
let led = gpioc.pc13.into_push_pull_output(&mut gpioc.crh);
// 启动周期任务:每500ms触发一次(1Hz闪烁)
blink::spawn_after(500.millis()).unwrap();
init::LateResources { led }
}
// 周期任务:翻转LED状态
#[task(resources = [led])]
fn blink(ctx: blink::Context) {
ctx.resources.led.toggle();
// 重新调度自身,形成周期
blink::spawn_after(500.millis()).unwrap();
}
// 空闲任务(RTIC默认提供,此处可省略)
#[idle]
fn idle(_: idle::Context) -> ! {
loop {
cortex_m::asm::wfi(); // 等待中断,降低功耗
}
}
};
关键机制说明
RTIC框架中,任务通过#[task]属性声明,每个任务拥有独立的优先级(默认优先级为1)。init函数完成硬件初始化后,通过blink::spawn_after()将任务首次挂入调度队列。任务体执行完毕后,再次调用spawn_after()实现自我周期重调度——这是RTOS任务常用的“自触发”模式。调度器基于优先级抢占,当前单任务场景下,任务在定时器中断触发时被唤醒执行,执行完毕后CPU进入idle任务等待下一次事件。
SVG:任务调度时序与状态
构建与烧录
# 添加编译目标
rustup target add thumbv7m-none-eabi
# 构建(release模式)
cargo build --release
# 烧录(使用OpenOCD + ST-Link)
openocd -f interface/stlink.cfg -f target/stm32f1x.cfg -c "program target/thumbv7m-none-eabi/release/rtos_task1 verify reset exit"
验证方法与判定标准
运行验证:将编译固件烧录至STM32F103后,观察板载LED(PC13)是否以约1Hz频率闪烁(每500ms翻转一次)。
判定标准:
- LED持续稳定闪烁,周期误差在视觉可接受范围内(约1秒一个完整亮灭周期);
- 若使用调试器连接,在
blink任务入口处设置断点,每次触发间隔应为500ms±1ms(由定时器精度保证); - 系统不进入HardFault,空闲时CPU处于WFI低功耗状态(可通过电流表测量,空闲电流应明显低于运行电流)。
预期输出:LED以固定周期闪烁,逻辑分析仪测量PC13引脚波形为方波,高电平持续500ms,低电平持续500ms,频率1Hz。