嵌入式开发
🎯 嵌入式Rust概述
嵌入式开发是Rust的重要应用领域之一。Rust的零成本抽象、内存安全和无运行时开销的特性使其成为嵌入式系统的理想选择。
🔧 嵌入式开发环境
工具链安装
bash
# 安装嵌入式开发工具
rustup target add thumbv7em-none-eabihf # ARM Cortex-M4F
rustup target add thumbv6m-none-eabi # ARM Cortex-M0/M0+
rustup target add thumbv7m-none-eabi # ARM Cortex-M3
# 安装调试工具
cargo install cargo-embed
cargo install cargo-flash
cargo install probe-run
# 安装交叉编译工具
sudo apt-get install gcc-arm-none-eabi # Ubuntu/Debian
项目配置
toml
# Cargo.toml
[package]
name = "embedded-example"
version = "0.1.0"
edition = "2021"
[dependencies]
cortex-m = "0.7"
cortex-m-rt = "0.7"
panic-halt = "0.2"
nb = "1.0"
# 目标特定依赖
[dependencies.stm32f4xx-hal]
version = "0.14"
features = ["stm32f401", "rt"]
[[bin]]
name = "main"
test = false
bench = false
[profile.release]
debug = true
lto = true
opt-level = "s" # 优化代码大小
toml
# .cargo/config.toml
[target.thumbv7em-none-eabihf]
runner = "probe-run --chip STM32F401RETx"
[build]
target = "thumbv7em-none-eabihf"
[env]
DEFMT_LOG = "debug"
💡 基础嵌入式程序
Hello World (LED闪烁)
rust
#![no_std]
#![no_main]
use panic_halt as _;
use cortex_m_rt::entry;
use stm32f4xx_hal::{
pac,
prelude::*,
timer::Timer,
};
#[entry]
fn main() -> ! {
// 获取设备外设
let dp = pac::Peripherals::take().unwrap();
let cp = cortex_m::Peripherals::take().unwrap();
// 配置时钟
let rcc = dp.RCC.constrain();
let clocks = rcc.cfgr.freeze();
// 配置GPIO
let gpioa = dp.GPIOA.split();
let mut led = gpioa.pa5.into_push_pull_output();
// 配置定时器
let mut timer = Timer::tim2(dp.TIM2, &clocks).counter_hz();
timer.start(1.Hz()).unwrap();
loop {
// 等待定时器
nb::block!(timer.wait()).unwrap();
// 切换LED状态
led.toggle();
}
}
串口通信
rust
#![no_std]
#![no_main]
use panic_halt as _;
use cortex_m_rt::entry;
use stm32f4xx_hal::{
pac,
prelude::*,
serial::{Config, Serial},
};
use nb::block;
#[entry]
fn main() -> ! {
let dp = pac::Peripherals::take().unwrap();
let rcc = dp.RCC.constrain();
let clocks = rcc.cfgr.freeze();
// 配置串口引脚
let gpioa = dp.GPIOA.split();
let tx_pin = gpioa.pa2.into_alternate();
let rx_pin = gpioa.pa3.into_alternate();
// 配置串口
let mut serial = Serial::new(
dp.USART2,
(tx_pin, rx_pin),
Config::default().baudrate(115200.bps()),
&clocks,
).unwrap();
let (mut tx, mut rx) = serial.split();
// 发送欢迎消息
for byte in b"Hello, Embedded Rust!\r\n" {
block!(tx.write(*byte)).unwrap();
}
loop {
// 回显接收到的字符
match block!(rx.read()) {
Ok(byte) => {
block!(tx.write(byte)).unwrap();
}
Err(_) => {
// 处理错误
}
}
}
}
🔌 硬件抽象层
GPIO操作
rust
use stm32f4xx_hal::{
pac,
prelude::*,
gpio::{Input, Output, PushPull, PullUp},
};
struct HardwareInterface {
led: stm32f4xx_hal::gpio::PA5<Output<PushPull>>,
button: stm32f4xx_hal::gpio::PC13<Input<PullUp>>,
}
impl HardwareInterface {
fn new(dp: pac::Peripherals) -> Self {
let gpioa = dp.GPIOA.split();
let gpioc = dp.GPIOC.split();
let led = gpioa.pa5.into_push_pull_output();
let button = gpioc.pc13.into_pull_up_input();
HardwareInterface { led, button }
}
fn led_on(&mut self) {
self.led.set_high();
}
fn led_off(&mut self) {
self.led.set_low();
}
fn is_button_pressed(&self) -> bool {
self.button.is_low()
}
}
// 使用示例
fn gpio_example() {
let dp = pac::Peripherals::take().unwrap();
let mut hw = HardwareInterface::new(dp);
loop {
if hw.is_button_pressed() {
hw.led_on();
} else {
hw.led_off();
}
// 防抖延迟
cortex_m::asm::delay(1000);
}
}
ADC读取
rust
use stm32f4xx_hal::{
pac,
prelude::*,
adc::{Adc, config::AdcConfig},
};
fn adc_example() -> ! {
let dp = pac::Peripherals::take().unwrap();
let rcc = dp.RCC.constrain();
let clocks = rcc.cfgr.freeze();
// 配置ADC
let gpioa = dp.GPIOA.split();
let adc_pin = gpioa.pa0.into_analog();
let mut adc = Adc::adc1(dp.ADC1, true, AdcConfig::default());
loop {
// 读取ADC值
let sample: u16 = adc.read(&adc_pin).unwrap();
// 转换为电压 (假设3.3V参考电压)
let voltage = (sample as f32 / 4095.0) * 3.3;
// 这里可以通过串口输出或其他方式显示
// 在实际应用中,避免在嵌入式系统中使用浮点运算
cortex_m::asm::delay(100_000);
}
}
⏰ 定时器和中断
定时器中断
rust
use stm32f4xx_hal::{
pac::{self, interrupt, TIM2},
prelude::*,
timer::{Timer, Event},
};
use cortex_m::peripheral::NVIC;
use core::cell::RefCell;
use cortex_m::interrupt::Mutex;
// 全局变量需要使用Mutex保护
static TIMER: Mutex<RefCell<Option<Timer<TIM2>>>> = Mutex::new(RefCell::new(None));
static LED_STATE: Mutex<RefCell<bool>> = Mutex::new(RefCell::new(false));
#[entry]
fn main() -> ! {
let dp = pac::Peripherals::take().unwrap();
let mut cp = cortex_m::Peripherals::take().unwrap();
let rcc = dp.RCC.constrain();
let clocks = rcc.cfgr.freeze();
// 配置定时器
let mut timer = Timer::tim2(dp.TIM2, &clocks).counter_hz();
timer.start(2.Hz()).unwrap();
timer.listen(Event::Update);
// 将定时器移动到全局变量
cortex_m::interrupt::free(|cs| {
TIMER.borrow(cs).replace(Some(timer));
});
// 启用定时器中断
unsafe {
NVIC::unmask(interrupt::TIM2);
}
loop {
// 主循环可以执行其他任务
cortex_m::asm::wfi(); // 等待中断
}
}
#[interrupt]
fn TIM2() {
cortex_m::interrupt::free(|cs| {
if let Some(ref mut timer) = TIMER.borrow(cs).borrow_mut().as_mut() {
timer.clear_interrupt(Event::Update);
// 切换LED状态
let mut led_state = LED_STATE.borrow(cs).borrow_mut();
*led_state = !*led_state;
// 这里应该实际控制LED
// led.set_state(*led_state);
}
});
}
📡 通信协议
SPI通信
rust
use stm32f4xx_hal::{
pac,
prelude::*,
spi::{Spi, Mode, Phase, Polarity},
};
fn spi_example() -> ! {
let dp = pac::Peripherals::take().unwrap();
let rcc = dp.RCC.constrain();
let clocks = rcc.cfgr.freeze();
// 配置SPI引脚
let gpioa = dp.GPIOA.split();
let sck = gpioa.pa5.into_alternate();
let miso = gpioa.pa6.into_alternate();
let mosi = gpioa.pa7.into_alternate();
// 配置SPI
let mut spi = Spi::new(
dp.SPI1,
(sck, miso, mosi),
Mode {
polarity: Polarity::IdleLow,
phase: Phase::CaptureOnFirstTransition,
},
1.MHz(),
&clocks,
);
loop {
// 发送数据
let tx_data = [0x01, 0x02, 0x03, 0x04];
let mut rx_data = [0u8; 4];
match spi.transfer(&mut rx_data, &tx_data) {
Ok(_) => {
// 处理接收到的数据
}
Err(_) => {
// 处理错误
}
}
cortex_m::asm::delay(1_000_000);
}
}
I2C通信
rust
use stm32f4xx_hal::{
pac,
prelude::*,
i2c::I2c,
};
fn i2c_example() -> ! {
let dp = pac::Peripherals::take().unwrap();
let rcc = dp.RCC.constrain();
let clocks = rcc.cfgr.freeze();
// 配置I2C引脚
let gpiob = dp.GPIOB.split();
let scl = gpiob.pb8.into_alternate_open_drain();
let sda = gpiob.pb9.into_alternate_open_drain();
// 配置I2C
let mut i2c = I2c::new(
dp.I2C1,
(scl, sda),
400.kHz(),
&clocks,
);
let device_address = 0x48; // 示例设备地址
loop {
// 写入数据
let write_data = [0x01, 0x02];
match i2c.write(device_address, &write_data) {
Ok(_) => {
// 写入成功
}
Err(_) => {
// 处理错误
}
}
// 读取数据
let mut read_data = [0u8; 2];
match i2c.read(device_address, &mut read_data) {
Ok(_) => {
// 处理读取的数据
}
Err(_) => {
// 处理错误
}
}
cortex_m::asm::delay(1_000_000);
}
}
🔋 电源管理
低功耗模式
rust
use stm32f4xx_hal::{
pac,
prelude::*,
pwr::{Pwr, PowerMode},
};
use cortex_m::asm;
fn power_management_example() -> ! {
let dp = pac::Peripherals::take().unwrap();
let cp = cortex_m::Peripherals::take().unwrap();
let rcc = dp.RCC.constrain();
let clocks = rcc.cfgr.freeze();
// 配置电源管理
let pwr = Pwr::new(dp.PWR);
loop {
// 执行一些工作
do_work();
// 进入低功耗模式
enter_sleep_mode(&pwr);
}
}
fn do_work() {
// 模拟工作负载
for _ in 0..1000 {
asm::nop();
}
}
fn enter_sleep_mode(pwr: &Pwr) {
// 配置唤醒源
// 例如:外部中断、定时器等
// 进入睡眠模式
asm::wfi(); // Wait For Interrupt
// 从睡眠模式唤醒后继续执行
}
🛠️ 调试和测试
调试配置
rust
// 使用defmt进行日志记录
use defmt::{info, warn};
use defmt_rtt as _;
use panic_probe as _;
#[entry]
fn main() -> ! {
info!("程序启动");
let mut counter = 0;
loop {
counter += 1;
if counter > 10000 {
warn!("计数器过高: {}", counter);
}
cortex_m::asm::delay(1000);
}
}
单元测试
rust
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_sensor_reading() {
// 模拟传感器读取
let reading = simulate_sensor_reading(100);
assert_eq!(reading, 100);
}
#[test]
fn test_data_processing() {
let input = [1, 2, 3, 4, 5];
let result = process_sensor_data(&input);
assert_eq!(result, 15); // 假设是求和
}
}
fn simulate_sensor_reading(value: u16) -> u16 {
value
}
fn process_sensor_data(data: &[u16]) -> u16 {
data.iter().sum()
}
// 运行测试
// cargo test --target x86_64-unknown-linux-gnu
📚 最佳实践
内存管理
rust
use heapless::{Vec, String, pool::{Pool, Node}};
// 使用heapless进行无堆内存管理
fn memory_management_example() {
// 固定大小的向量
let mut vec: Vec<u8, 32> = Vec::new();
vec.push(1).unwrap();
vec.push(2).unwrap();
// 固定大小的字符串
let mut string: String<64> = String::new();
string.push_str("Hello").unwrap();
// 内存池
static mut MEMORY: [Node<[u8; 64]>; 16] = [Node::new(); 16];
static POOL: Pool<[u8; 64]> = Pool::new();
// 初始化内存池
unsafe {
POOL.grow(&mut MEMORY);
}
// 从池中分配内存
if let Some(mut block) = POOL.alloc() {
block[0] = 42;
// 使用完毕后自动归还到池中
}
}
错误处理
rust
use nb;
#[derive(Debug)]
enum SensorError {
CommunicationError,
InvalidData,
Timeout,
}
fn robust_sensor_reading() -> Result<u16, SensorError> {
// 重试机制
for attempt in 0..3 {
match read_sensor_with_timeout() {
Ok(value) => {
if validate_sensor_data(value) {
return Ok(value);
} else {
return Err(SensorError::InvalidData);
}
}
Err(_) if attempt < 2 => {
// 重试前等待
cortex_m::asm::delay(10_000);
continue;
}
Err(_) => return Err(SensorError::CommunicationError),
}
}
Err(SensorError::Timeout)
}
fn read_sensor_with_timeout() -> Result<u16, ()> {
// 模拟传感器读取
Ok(42)
}
fn validate_sensor_data(value: u16) -> bool {
// 验证数据范围
value >= 0 && value <= 1000
}
嵌入式Rust开发让您能够构建安全、高效的嵌入式系统,充分发挥Rust的优势!🔌