92人参与 • 2026-10-02 • rust

cortex-m、cortex-m-rt库进行arm裸机开发,实现gpio操作、串口通信、中断处理💡 三大核心难点:
core、alloc库管理内存,避免内存泄漏cortex-m库实现中断函数和临界区保护⚠️ 三大高频错误点:
嵌入式系统是一种以应用为中心、以计算机技术为基础、软件硬件可裁剪、适应应用系统对功能、可靠性、成本、体积、功耗严格要求的专用计算机系统。嵌入式系统的核心特点是:
嵌入式系统的架构通常分为以下几种:
rust作为一门系统编程语言,非常适合嵌入式开发,其优势包括:
使用rustup安装arm和risc-v的交叉编译工具链:
# 安装arm cortex-m0/m3/m4的交叉编译工具链 rustup target add thumbv6m-none-eabi rustup target add thumbv7m-none-eabi rustup target add thumbv7em-none-eabi rustup target add thumbv8m.base-none-eabi rustup target add thumbv8m.main-none-eabi rustup target add thumbv8m.main-none-eabihf # 安装risc-v的交叉编译工具链 rustup target add riscv32imc-unknown-none-elf rustup target add riscv64gc-unknown-none-elf
openocd是开源的调试器和编程器,支持多种调试接口(jtag、swd)。
⌨️ ubuntu/debian安装openocd:
sudo apt-get install openocd
⌨️ windows安装openocd:
下载openocd的windows版本,解压后添加到系统path中。
gdb是gnu调试器,支持arm和risc-v架构的调试。
⌨️ ubuntu/debian安装arm gdb:
sudo apt-get install gdb-multiarch
⌨️ windows安装arm gdb:
下载arm gdb的windows版本,解压后添加到系统path中。
安装以下vs code扩展:
使用cargo generate创建一个新的rust裸机项目:
# 安装cargo generate cargo install cargo-generate # 使用cortex-m-quickstart模板创建项目 cargo generate --git https://github.com/rust-embedded/cortex-m-quickstart --name stm32f411re-demo
在cargo.toml中添加依赖:
[dependencies] cortex-m = "0.7" cortex-m-rt = "0.7" panic-halt = "0.2" [dependencies.stm32f4xx-hal] version = "0.18" features = ["stm32f411", "rt"]
在memory.x文件中配置flash和ram的地址和大小:
/* linker script for stm32f411re nucleo */
memory
{
flash : origin = 0x08000000, length = 512k
ram : origin = 0x20000000, length = 128k
}
在src/main.rs文件中编写led闪烁的代码:
#![no_std]
#![no_main]
use cortex_m_rt::entry;
use panic_halt as _;
use stm32f4xx_hal::gpio::*;
use stm32f4xx_hal::pac;
use stm32f4xx_hal::prelude::*;
use stm32f4xx_hal::timer::*;
#[entry]
fn main() -> ! {
// 获取硬件抽象层(hal)
let dp = pac::peripherals::take().unwrap();
let cp = cortex_m::peripherals::take().unwrap();
// 配置系统时钟
let rcc = dp.rcc.constrain();
let clocks = rcc.cfgr.sysclk(84.mhz()).freeze();
// 配置gpio
let gpioc = dp.gpioc.split();
let mut led = gpioc.pc13.into_push_pull_output();
// 配置定时器
let mut timer = dp.tim2.timer(&clocks).start_ticker();
// 配置系统定时器(systick)
let mut systick = cp.syst.counter_us(&clocks);
// led闪烁
loop {
led.toggle();
systick.delay(500_000); // 延迟500ms
}
}
在src/main.rs文件中添加串口通信的代码:
use stm32f4xx_hal::serial::*;
#[entry]
fn main() -> ! {
// 获取硬件抽象层(hal)
let dp = pac::peripherals::take().unwrap();
let cp = cortex_m::peripherals::take().unwrap();
// 配置系统时钟
let rcc = dp.rcc.constrain();
let clocks = rcc.cfgr.sysclk(84.mhz()).freeze();
// 配置gpio
let gpioa = dp.gpioa.split();
let tx = gpioa.pa2.into_alternate();
let rx = gpioa.pa3.into_alternate();
// 配置串口
let mut serial = dp.usart2.serial((tx, rx), 9600.bd(), &clocks).unwrap();
serial.listen(event::rxne);
// 发送数据
serial.write_str("hello, rust embedded!\n").unwrap();
// 接收数据
loop {
if let ok(byte) = nb::block!(serial.read()) {
serial.write(byte).unwrap();
}
}
}
使用cargo build命令编译项目:
# 编译为arm cortex-m4架构 cargo build --target thumbv7em-none-eabihf --release
使用openocd烧录程序:
# 连接开发板 openocd -f interface/stlink.cfg -f target/stm32f4x.cfg # 在另一个终端中使用gdb烧录 gdb-multiarch target/thumbv7em-none-eabihf/release/stm32f411re-demo (gdb) target remote :3333 (gdb) monitor reset halt (gdb) load (gdb) monitor reset run
rtic(real-time interrupt-driven concurrency)是rust社区开发的实时操作系统框架,它基于中断驱动的并发模型,支持:
resource宏实现互斥访问interrupt宏实现中断函数channel宏实现任务间通信使用cargo generate创建一个新的rtic项目:
cargo generate --git https://github.com/rtic-rs/cortex-m-quickstart --name rtic-demo
在src/main.rs文件中编写rtic代码:
#![no_std]
#![no_main]
use panic_halt as _;
use rtic::app;
use stm32f4xx_hal::gpio::*;
use stm32f4xx_hal::pac;
use stm32f4xx_hal::prelude::*;
use stm32f4xx_hal::serial::*;
use stm32f4xx_hal::timer::*;
#[app(device = stm32f4xx_hal::pac, peripherals = true)]
const app: () = {
struct resources {
led: gpioc::pc13<output<pushpull>>,
timer: timer<pac::tim2>,
serial: serial<pac::usart2, (gpioa::pa2<alternate<af7>>, gpioa::pa3<alternate<af7>>), 9600>,
}
#[init]
fn init(cx: init::context) -> init::lateresources {
// 获取硬件抽象层(hal)
let dp = cx.device;
let cp = cx.core;
// 配置系统时钟
let rcc = dp.rcc.constrain();
let clocks = rcc.cfgr.sysclk(84.mhz()).freeze();
// 配置gpio
let gpioc = dp.gpioc.split();
let led = gpioc.pc13.into_push_pull_output();
let gpioa = dp.gpioa.split();
let tx = gpioa.pa2.into_alternate();
let rx = gpioa.pa3.into_alternate();
// 配置串口
let serial = dp.usart2.serial((tx, rx), 9600.bd(), &clocks).unwrap();
serial.listen(event::rxne);
// 配置定时器
let timer = dp.tim2.timer(&clocks).start_ticker();
// 发送初始化信息
serial.write_str("rtic demo initialized!\n").unwrap();
init::lateresources { led, timer, serial }
}
#[task(binds = tim2, resources = [led, timer])]
fn timer_interrupt(cx: timer_interrupt::context) {
// 清除定时器中断标志
cx.resources.timer.clear_interrupt(timerinterrupt::update);
// 切换led状态
cx.resources.led.toggle();
}
#[task(binds = usart2, resources = [serial])]
fn serial_interrupt(cx: serial_interrupt::context) {
// 清除串口中断标志
cx.resources.serial.clear_interrupt(event::rxne);
// 接收数据
if let ok(byte) = nb::block!(cx.resources.serial.read()) {
// 发送数据
cx.resources.serial.write(byte).unwrap();
}
}
};
💡 场景分析:需要使用stm32f411re nucleo板连接dht11温湿度传感器,读取温湿度数据,并通过串口发送到电脑。
| stm32f411re | dht11 |
|---|---|
| 5v | vcc |
| gnd | gnd |
| pb12 | data |
在src/main.rs文件中添加温湿度传感器数据读取的代码:
#![no_std]
#![no_main]
use panic_halt as _;
use rtic::app;
use stm32f4xx_hal::gpio::*;
use stm32f4xx_hal::pac;
use stm32f4xx_hal::prelude::*;
use stm32f4xx_hal::serial::*;
use stm32f4xx_hal::timer::*;
// 定义dht11传感器类型
struct dht11 {
pin: gpiob::pb12<input<floating>>,
}
impl dht11 {
// 初始化dht11传感器
fn new(pin: gpiob::pb12<input<floating>>) -> self {
dht11 { pin }
}
// 读取温湿度数据
fn read(&mut self) -> option<(u8, u8)> {
let mut data: [u8; 5] = [0; 5];
// 发送启动信号
let mut pin = self.pin.into_push_pull_output();
pin.set_low();
cortex_m::asm::delay(18000); // 延迟18ms
pin.set_high();
cortex_m::asm::delay(30); // 延迟30us
// 等待dht11响应
let pin = pin.into_floating_input();
while pin.is_high() {}
while pin.is_low() {}
while pin.is_high() {}
// 读取数据
for i in 0..5 {
let mut byte = 0;
for j in 0..8 {
while pin.is_low() {}
cortex_m::asm::delay(40); // 延迟40us
if pin.is_high() {
byte |= 1 << (7 - j);
}
while pin.is_high() {}
}
data[i] = byte;
}
// 校验数据
let checksum = data[0] + data[1] + data[2] + data[3];
if data[4] == checksum {
some((data[0], data[2]))
} else {
none
}
}
}
#[app(device = stm32f4xx_hal::pac, peripherals = true)]
const app: () = {
struct resources {
dht11: dht11,
serial: serial<pac::usart2, (gpioa::pa2<alternate<af7>>, gpioa::pa3<alternate<af7>>), 9600>,
timer: timer<pac::tim3>,
}
#[init]
fn init(cx: init::context) -> init::lateresources {
// 获取硬件抽象层(hal)
let dp = cx.device;
let cp = cx.core;
// 配置系统时钟
let rcc = dp.rcc.constrain();
let clocks = rcc.cfgr.sysclk(84.mhz()).freeze();
// 配置gpio
let gpiob = dp.gpiob.split();
let dht11 = dht11::new(gpiob.pb12.into_floating_input());
let gpioa = dp.gpioa.split();
let tx = gpioa.pa2.into_alternate();
let rx = gpioa.pa3.into_alternate();
// 配置串口
let serial = dp.usart2.serial((tx, rx), 9600.bd(), &clocks).unwrap();
serial.listen(event::rxne);
// 配置定时器
let timer = dp.tim3.timer(&clocks).start_ticker();
init::lateresources { dht11, serial, timer }
}
#[task(binds = tim3, resources = [dht11, serial])]
fn timer_interrupt(cx: timer_interrupt::context) {
// 清除定时器中断标志
cx.resources.timer.clear_interrupt(timerinterrupt::update);
// 读取温湿度数据
if let some((temperature, humidity)) = cx.resources.dht11.read() {
// 发送温湿度数据
let message = format!("温度: {}°c, 湿度: {}%\n", temperature, humidity);
cx.resources.serial.write_str(&message).unwrap();
} else {
cx.resources.serial.write_str("读取温湿度数据失败\n").unwrap();
}
}
#[task(binds = usart2, resources = [serial])]
fn serial_interrupt(cx: serial_interrupt::context) {
// 清除串口中断标志
cx.resources.serial.clear_interrupt(event::rxne);
// 接收数据
if let ok(byte) = nb::block!(cx.resources.serial.read()) {
// 发送数据
cx.resources.serial.write(byte).unwrap();
}
}
};
问题现象:程序崩溃,调试器显示“hardfault”。
解决方案:
memory.x文件中修改ram的大小或调整链接器脚本alloc库进行堆分配问题现象:硬件功能无法正常实现。
解决方案:
问题现象:i2c/spi通信时,数据传输错误。
解决方案:
✅ 理解了嵌入式开发基础:深入掌握了嵌入式系统的定义、特点、架构,对比了rust与传统嵌入式开发语言的优势
✅ 搭建了rust嵌入式开发环境:安装了交叉编译工具链、调试工具,配置了vs code开发环境
✅ 掌握了rust裸机编程:使用cortex-m、cortex-m-rt库进行arm裸机开发,实现了gpio操作、串口通信、中断处理
✅ 学习了rtos开发:使用rtic实现了多任务编程,理解了任务调度、资源共享、中断管理
✅ 实战了嵌入式项目:结合stm32f4xx系列开发板,实现了led闪烁、温湿度传感器数据读取、串口通信
✅ 优化与调试:学习了rust嵌入式代码的优化方法,使用gdb/openocd进行硬件调试
到此这篇关于rust嵌入式开发入门教程:从裸机编程到rtos实战项目详解的文章就介绍到这了,更多相关rust嵌入式开发入门教程内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
您想发表意见!!点此发布评论
版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。
发表评论