什么是裸机环境?
裸机环境是指没有可供使用的操作系统环境。当编译的 Rust 程序拥有 no_std 属性时,该程序无权访问上述 std 章节中提到的某些特定功能。尽管仍支持使用配网或引入复杂数据结构等功能,但实现方式将会更加复杂。 no_std 程序依赖于 Rust 所有环境中可用的核心语言特性,包括数据类型、控制结构和底层内存管理。此环境在嵌入式编程中非常实用,特别适用于内存资源有限、需要对硬件进行低级别控制的场景。
以下为在裸机环境上(不借助操作系统)运行的 blinky 示例:
https://github.com/esp-rs/esp-hal/blob/main/esp32-hal/examples/blinky.rs
(更多示例存放在 esp-hal 仓库中):
rust
#![no_std]
#![no_main]
// 导入示例所需外设
use esp32c3_hal::{
clock::ClockControl,
gpio::IO,
peripherals::Peripherals,
prelude::*,
timer::TimerGroup,
Delay,
Rtc,
};
use esp_backtrace as _;
// 设置程序执行的起始点
// 因为这是一个 `no_std` 程序,不存在主函数
#[entry]
fn main() -> ! {
// 初始化所有所需外设
let peripherals = Peripherals::take();
let mut system = peripherals.SYSTEM.split();
let clocks = ClockControl::boot_defaults(system.clock_control).freeze();
// 禁用看门狗定时器。对于 ESP32-C3 来说,包括 Super WDT、
// RTC WDT 和 TIMG WDT
let mut rtc = Rtc::new(peripherals.RTC_CNTL);
let timer_group0 = TimerGroup::new(
peripherals.TIMG0,
&clocks,
&mut system.peripheral_clock_control,
);
let mut wdt0 = timer_group0.wdt;
let timer_group1 = TimerGroup::new(
peripherals.TIMG1,
&clocks,
&mut system.peripheral_clock_control,
);
let mut wdt1 = timer_group1.wdt;
rtc.swd.disable();
rtc.rwdt.disable();
wdt0.disable();
wdt1.disable();
// 将 GPIO4 设置为输出,并将其初始状态设置为高电平
let io = IO::new(peripherals.GPIO, peripherals.IO_MUX);
// 创建一个 led 对象,将其设置为 GPIO4 引脚的输出模式
let mut led = io.pins.gpio5.into_push_pull_output();
// 启动 LED
led.set_high().unwrap();
// 初始化延迟外设,并在循环中
// 使用它来切换 LED 的状态
let mut delay = Delay::new(&clocks);
// 设置一个每 500 毫秒即切换 LED 开/关状态的无限循环
loop {
led.toggle().unwrap();
delay.delay_ms(500u32);
}
}
适用裸机环境的情况:
减少内存占用:如果嵌入式系统资源有限,需要占用较小的内存,可以考虑使用裸机环境,因为 std 会显著增加最终二进制文件的大小和编译时间。
实现直接硬件控制:如果需要在嵌入式系统中实现直接硬件控制,例如实现底层设备驱动程序或访问特定硬件功能,可以考虑使用裸机环境,因为 std 的抽象层会提高直接与硬件进行交互的难度。
涉及实时约束或对时间敏感的应用程序:如果嵌入式系统要求实时性能或低延迟响应时间,可以考虑使用裸机环境,因为 std 可能导致意外延迟和开销。
自定义需求:裸机环境支持更多自定义配置,同时也能实现对应用程序行为的精细控制,非常适用于特定或非标准环境。