Rust嵌入式开发实战
基于Rust嵌入式开发的实用
以下是基于Rust嵌入式开发的实用示例,涵盖硬件交互、外设控制及典型应用场景,适合不同开发板(如STM32、Raspberry Pi Pico等)。内容以功能分类呈现,代码基于embedded-hal
抽象层和常见库(如cortex-m
、stm32f4xx-hal
)。
基础GPIO控制
LED闪烁(无延时库)
use stm32f4xx_hal::{pac, prelude::*};fn main() -> ! {let dp = pac::Peripherals::take().unwrap();let rcc = dp.RCC.constrain();let clocks = rcc.cfgr.freeze();let gpioa = dp.GPIOA.split();let mut led = gpioa.pa5.into_push_pull_output();loop {led.toggle();cortex_m::asm::delay(clocks.sysclk().0 / 2); // 粗略延时}
}
Rust GPIO 实用指南
基础设置
在 Rust 项目中启用 GPIO 功能通常需要依赖硬件抽象层库,如 embedded-hal
和平台特定库(如 rppal
用于树莓派)。在 Cargo.toml
中添加依赖:
[dependencies]
rppal = "0.14" # 树莓派GPIO库
embedded-hal = "1.0" # 嵌入式硬件抽象层
初始化GPIO引脚
使用 rppal
库初始化树莓派的 GPIO 引脚:
use rppal::gpio::Gpio;fn main() -> Result<(), Box<dyn std::error::Error>> {let gpio = Gpio::new()?;let mut pin = gpio.get(17)?.into_output(); // 将GPIO17设置为输出模式Ok(())
}
读取输入信号
配置引脚为输入模式并读取状态:
let input_pin = gpio.get(27)?.into_input(); // GPIO27为输入模式
if input_pin.is_high() {println!("检测到高电平");
}
输出控制
通过 set_high()
和 set_low()
控制输出:
pin.set_high(); // 输出高电平
std::thread::sleep(std::time::Duration::from_secs(1));
pin.set_low(); // 输出低电平
中断处理
为输入引脚设置边沿触发中断:
use rppal::gpio::Trigger;let input_pin = gpio.get(27)?.into_input_pullup();
input_pin.set_interrupt(Trigger::Rising)?; // 上升沿触发loop {if let Ok(Some(level)) = input_pin.poll_interrupt(false, None) {println!("中断触发,电平: {:?}", level);}
}
PWM输出
使用硬件 PWM 控制引脚输出脉冲宽度调制信号:
use rppal::pwm::{Pwm, Channel};let pwm = Pwm::with_frequency(Channel::Pwm0, 50.0, 0.5, 0.0, true)?; // 50Hz频率,50%占空比
跨平台兼容性
通过 embedded-hal
抽象实现跨平台代码:
use embedded_hal::digital::v2::{OutputPin, InputPin};fn toggle_pin<P: OutputPin>(pin: &mut P) {pin.set_high().unwrap();pin.set_low().unwrap();
}
注意事项
- 需要目标平台权限(如树莓派的
gpio
用户组)。 - 引脚编号可能因开发板而异(BCM/物理编号)。
- 实时性要求高的场景建议使用
linux-embedded-hal
或直接寄存器操作。
完整示例:LED闪烁
以下代码实现 GPIO 控制的 LED 闪烁:
use std::thread::sleep;
use std::time::Duration;
use rppal::gpio::Gpio;fn main() -> Result<(), Box<dyn std::error::Error>> {let gpio = Gpio::new()?;let mut led = gpio.get(17)?.into_output();loop {led.set_high();sleep(Duration::from_millis(500));led.set_low();sleep(Duration::from_millis(500));}
}
进阶功能
- 多线程控制:使用
Arc<Mutex<>>
共享 GPIO 句柄。 - 嵌入式RTOS:与
RTIC
或embassy
框架集成。 - 性能优化:直接内存访问(DMA)操作 GPIO 寄存器。
通过合理选择库和抽象层,Rust 能提供从简单脚本到硬实时系统开发的完整 GPIO 解决方案。
按键输入检测
let gpioc = dp.GPIOC.split();
let button = gpioc.pc13.into_pull_up_input();
if button.is_low().unwrap() {led.set_high().unwrap();
}
定时器与中断
定时器中断触发
use stm32f4xx_hal::timer::Timer;let mut timer = Timer::tim2(dp.TIM2, 1.hz(), clocks);
timer.listen(Event::TimeOut);
loop {if timer.wait().is_ok() {led.toggle();}
}
PWM输出控制LED亮度
let pwm = dp.TIM2.pwm_hz(gpioa.pa0.into_alternate(), 1.khz(), clocks);
let mut pwm_channel = pwm.split();
pwm_channel.set_duty(50); // 50%占空比
pwm_channel.enable();
通信协议
UART串口通信
let tx = gpioa.pa2.into_alternate();
let rx = gpioa.pa3.into_alternate();
let serial = Serial::usart2(dp.USART2, (tx, rx), 115_200.bps(), clocks);
let (mut tx, mut rx) = serial.split();nb::block!(tx.write(b'A')).unwrap();
let received = nb::block!(rx.read()).unwrap();
I2C读取传感器(如BME280)
let i2c = I2c::i2c1(dp.I2C1, (scl, sda), 100.khz(), clocks);
let mut bme280 = BME280::new_primary(i2c);
let measurements = bme280.measure().unwrap();
SPI驱动OLED屏幕
let spi = Spi::spi1(dp.SPI1, (sck, miso, mosi), Mode::MODE_0, 1.mhz(), clocks);
let dc = gpioa.pa4.into_push_pull_output(); // 数据/命令选择
let mut disp = Display::new(spi, dc);
disp.draw(&bitmap).unwrap();
高级功能
RTIC实时任务调度
#[rtic::app(device = stm32f4xx_hal::pac)]
mod app {#[init]fn init(cx: init::Context) {cx.schedule.foo(1.secs()).unwrap();}#[task]fn foo(_: foo::Context) {led.toggle();}
}
DMA传输加速内存拷贝
let dma = dp.DMA1.split();
let buf = &[1, 2, 3];
let mut dest = [0; 3];
let transfer = dma1.chan1.transfer(buf, &mut dest);
transfer.wait().unwrap();
传感器与执行器
读取ADC温度传感器
let adc = Adc::adc1(dp.ADC1, &mut delay);
let temp_sensor = adc.enable_temperature();
let temp = adc.read(&temp_sensor).unwrap();
步进电机控制
let mut stepper = Stepper::new(in1, in2, in3, in4);
stepper.step(Direction::Forward, 100); // 步进100步
低功耗与优化
进入睡眠模式
cortex_m::asm::wfi(); // 等待中断唤醒
内存优化技巧
#[inline(never)] // 避免函数内联
#[link_section = ".fastcode"] // 指定代码段
fn critical_function() { /* ... */ }
基于Rust实现的实时操作系统(RTOS)
以下是基于Rust实现的实时操作系统(RTOS)或嵌入式开发相关的30个实例资源,涵盖不同框架、硬件平台和应用场景。内容整合自开源项目、教程和社区实践:
Rust嵌入式基础实例
-
Blinky(LED闪烁)
使用cortex-m-rt
和embedded-hal
库在STM32上控制LED,经典入门项目。#[entry] fn main() -> ! {let mut led = gpioa.pa5.into_push_pull_output();loop {led.toggle();delay.delay_ms(1000_u32);} }
-
串口通信(UART)
通过usart
模块实现与PC的串口数据收发,需配置波特率和引脚。 -
按键中断
利用cortex-m
的中断机制检测按键按下事件,结合NVIC
配置。 -
PWM输出
使用stm32f4xx-hal
生成PWM信号控制舵机或电机。 -
ADC读取传感器数据
通过模拟数字转换读取温度或光敏传感器数值。
RTOS框架实例
-
FreeRTOS Rust绑定
使用freertos-rust
库创建任务和队列,示例包含任务优先级配置。 -
RTIC(Real-Time Interrupt-driven Concurrency)
资源管理与中断处理的轻量级框架:#[rtic::app(device = stm32f4xx_hal::stm32)] mod app {#[init]fn init(cx: init::Context) -> init::LateResources {// 初始化硬件} }
-
Embassy异步RTOS
基于async/await
的嵌入式运行时,示例包括定时器和SPI通信。 -
Tock OS应用
在Tock OS上编写Capsule驱动,如GPIO控制。
通信协议实例
-
I2C传感器驱动
实现BME280温度传感器的I2C读取,使用embedded-hal
trait。 -
SPI屏幕驱动
通过SPI接口驱动OLED显示屏,示例包含图形缓冲区管理。 -
CAN总线通信
使用can-rs
库实现STM32的CAN报文收发。 -
无线LoRa通信
基于SX1276模块的LoRa数据传输,需配置RF参数。
多任务与同步
-
互斥锁(Mutex)保护共享资源
在RTIC或FreeRTOS中保护全局变量。 -
信号量同步任务
使用heapless::spsc
队列实现生产者-消费者模型。 -
硬件定时器触发任务
配置TIM2定时器周期性唤醒任务。
高级应用实例
-
嵌入式Web服务器
通过smoltcp
库在ESP32上运行HTTP服务。 -
实时频谱分析
STM32H7配合ADC进行FFT计算,输出音频频谱。 -
电池管理系统(BMS)
监控电压电流,使用embedded-graphics
显示状态。 -
无人机飞控
基于NuttX和Rust的PID控制器实现。
调试与优化
-
defmt日志输出
通过SWD接口输出调试信息,替代println!
。 -
内存占用分析
使用cargo-size
检查二进制文件的Flash/RAM使用。 -
RTOS性能分析
通过ITM(Instrumentation Trace Macrocell)记录任务切换时间。
硬件平台扩展
-
Raspberry Pi Pico
使用rp2040-hal
驱动WS2812B LED灯带。 -
ESP32-C3 WiFi连接
通过esp-idf-sys
调用ESP-IDF的WiFi API。 -
Nordic nRF52低功耗蓝牙
实现BLE外设广播,使用nrf52-hal
。
安全相关
-
内存安全验证
使用cargo-geiger
检测unsafe代码比例。 -
固件加密签名
通过ring
库实现SHA-256校验。
完整项目参考
-
Rust嵌入式分类项目列表
GitHub搜索rust-embedded/awesome-embedded-rust
,包含硬件驱动和RTOS案例。 -
STM32F4 Discovery开发板综合Demo
结合传感器、显示和网络模块的完整工程模板。
以上实例可通过以下资源进一步探索:
- 官方文档:
embedded-hal
、cortex-m-rt
- 社区资源:Rust Embedded WG博客、Matrix聊天室
- 开发板支持库:如
stm32f4xx-hal
、nrf-hal
建议从硬件抽象层(HAL)开始,逐步深入RTOS特性如任务调度和资源管理。
基于 embedded-hal
的 Rust 嵌入式开发
以下是基于 embedded-hal
的 Rust 嵌入式开发实例(涵盖常见外设操作和通讯协议),按类别整理为多个实用方法:
GPIO 控制
在嵌入式开发中,GPIO 是最基础的外设之一,用于控制引脚的高低电平。
use embedded_hal::digital::OutputPin;
use stm32f1xx_hal::gpio::{gpioc::Gpio, OutputPin};
let led = gpio.pc13.into_push_pull_output(); // 配置为推挽输出
led.set_high(); // 设置高电平
led.set_low(); // 设置低电平
定时器延时
定时器用于生成精确的时间延迟,比如实现 LED 的闪烁效果。
use embedded_hal::timer::Delay;
let mut delay = Timer::new(tim6, &clocks); // 初始化定时器
delay.delay(100.ms); // 延时100毫秒
PWM 控制 LED
PWM 信号可以用于控制 LED 的亮度变化,实现呼吸灯效果。
use embedded_hal::pwm::Pwm;
let mut pwm = pwm1.configure(&clocks); // 初始化PWM
pwm.set_duty_cycle(50); // 设置占空比为50%
ADC 读取电压
ADC 模块用于将模拟电压信号转换为数字值,比如读取温度传感器的电压。
use embedded_hal::adc::Adc;
let value = adc.read(&mut delay); // 读取ADC值
let voltage = value * 3.3 / 4095; // 转换为电压值
中断处理
嵌入式系统中,中断是不可或缺的机制,用于响应外部事件。
use embedded_hal::interrupt::Interrupt;
let interrupt = NVIC::get_interrupt(); // 获取中断号
interrupt.enable(); // 使能中断
interrupt.disable(); // 禁用中断
DMA 数据传输
DMA 技术可以大幅提升数据传输效率,减轻 CPU 负担。
use dma::{dma1::Dma, Stream};
let stream = Stream::new(dma1, &clocks); // 初始化DMA流
stream.enable(); // 使能DMA流
串口通讯
串口是嵌入式系统中常用的通讯方式,用于设备间数据传输。
use serial::{Serial, Tx, Rx};
let serial = Serial::new(usart1, &clocks); // 初始化串口
serial.write(b'Hello'); // 发送数据
serial.read(&mut [0; 5]); // 读取数据
I2C 通讯
I2C 是一种同步通讯协议,用于连接多个设备。
use i2c::{I2c, Blocking};
let i2c = I2c::new(i2c1, &clocks); // 初始化I2C
i2c.write(b'Hello'); // 发送数据
i2c.read(&mut [0; 5]); // 读取数据
SPI 通讯
SPI 是一种高速全双工通讯协议,用于连接微控制器和外部设备。
use spi::{Spi, SpiMode};
let spi = Spi::new(spi1, &clocks); // 初始化SPI
spi.write(b'Hello'); // 发送数据
spi.read(&mut [0; 5]); // 读取数据
看门狗定时器
看门狗定时器用于检测系统是否正常运行,防止程序跑飞。
use watchdog::{Watchdog, Independed};
let mut watchdog = Watchdog::new(independed); // 独立模式
watchdog.start(); // 启动看门狗
watchdog.feed(); // 喂狗操作
实时时钟(RTC)
RTC 模块用于记录当前时间,便于时间管理。
use rtc::{Rtc, DateTime};
let mut rtc = Rtc::new(rtc1, &clocks); // 初始化RTC
rtc.set_time(&datetime); // 设置时间
rtc.get_time(); // 读取时间
蜂鸣器控制
蜂鸣器是一种常见的发声设备,可以通过 PWM 信号控制其频率和音量。
use buzzer::{Buzzer, Active};
let mut buzzer = Buzzer::new(active); // 初始化蜂鸣器
buzzer.beep(1000); // 响铃1秒
buzzer.stop(); // 停止
红外接收解码
红外接收头用于接收遥控器发送的红外信号,解码后执行相应功能。
use infrared::{Infrared, Nec};
let mut ir = Infrared::new(nec); // 初始化红外接收
ir.read(); // 读取红外信号
超声波测距
超声波模块通过发射和接收超声波来计算距离。
use ultrasonic::{Ultrasonic, Echo};
let mut ultrasonic = Ultrasonic::new(echo); // 初始化超声波
ultrasonic.measure_distance(); // 测量距离
温湿度传感器
温湿度传感器用于测量环境中的温度和湿度参数。
use dht22::{Dht22, Reading};
let mut dht = Dht22::new(); // 初始化传感器
dht.read_temperature(); // 读取温度
dht.read_humidity(); // 读取湿度
光照强度传感器
光照传感器用于检测环境中的光照强度,单位为勒克斯(Lux)。
use light_sensor::{LightSensor, Reading};
let mut light = LightSensor::new(); // 初始化传感器
light.read_light_level(); // 读取光照强度
加速度计读取
加速度计用于检测设备的运动状态,单位为米/秒²(m/s²)。
use accelerometer::{Accelerometer, Reading};
let mut acc = Accelerometer::new(); // 初始化传感器
acc.read_acceleration(); // 读取加速度
气压传感器
气压传感器用于检测环境中的气压变化,单位为百帕(hPa)。
use pressure_sensor::{PressureSensor, Reading};
let mut press = PressureSensor::new(); // 初始化传感器
press.read_pressure(); // 读取气压值
陀螺仪校准
陀螺仪用于检测设备的旋转状态,单位为度/秒(°/s)。
use gyroscope::{Gyroscope, Calibrate};
let mut gyro = Gy