Hello World

🦀 Rust + ESP32-S3 入门第一课:Hello World

作者 :CXi

硬件 :ESP32-S3R8N8 嘉立创开发板

语言 :Rust(esp-hal 硬件抽象层)

难度 :⭐ 入门级

适合人群:有 Rust 基础,想入门嵌入式开发的同学


📖 目录

  1. 项目简介
  2. 硬件介绍
  3. 开发环境搭建
  4. 项目结构
  5. 代码逐行详解
  6. 编译与烧录
  7. 常见问题
  8. 扩展练习

1. 项目简介

本教程将带你用 Rust 语言在 ESP32-S3 开发板上跑通第一个程序:

每隔 500ms,通过 RTT 调试输出打印一行计数

复制代码
你好,第 0 次
你好,第 1 次
你好,第 2 次
...

这个项目只有 38 行代码,但能帮你理解嵌入式 Rust 的核心概念:

知识点 你在代码中会看到
#![no_main] / #![no_std] 嵌入式程序的"标准开头"
esp_hal::init() 初始化芯片硬件
loop {} 嵌入式程序的无限主循环
rprintln!() 通过 RTT 输出调试日志
Instant::now() 时间测量与延时

2. 硬件介绍

2.1 ESP32-S3R8N8 嘉立创开发板

芯片参数:

参数
芯片 ESP32-S3
CPU Xtensa LX7 双核,240MHz
Flash 8MB(N8)
PSRAM 8MB(R8)
WiFi 802.11 b/g/n
蓝牙 BLE 5.0

2.2 你需要准备什么

  • ✅ ESP32-S3R8N8 嘉立创开发板 × 1
  • ✅ Type-C USB 数据线 × 1
  • ✅ 电脑(Windows / macOS / Linux)

💡 本教程不涉及任何外设接线,一根 USB 线就够了。


3. 开发环境搭建

3.1 安装 Rust

bash 复制代码
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

3.2 安装 ESP32 工具链

bash 复制代码
# espup:ESP32 Rust 工具链管理器
cargo install espup

# 安装 Xtensa 工具链(支持 ESP32-S3 的 Rust 编译器)
espup install

# 烧录工具
cargo install espflash --locked
cargo install probe-rs-tools --locked

3.3 配置环境变量

bash 复制代码
# Linux / macOS:每次打开终端都要执行
source $HOME/export-esp.sh

# Windows(PowerShell)
# espup install 完成后会提示环境变量路径,按提示操作即可

💡 嫌麻烦?把 source $HOME/export-esp.sh 加到 ~/.bashrc~/.zshrc 里,自动生效。

3.4 克隆项目

bash 复制代码
git clone https://github.com/cx693/Rust_ESP32_Dome.git
cd Rust_ESP32_Dome/examples/hello

4. 项目结构

复制代码
Rust_ESP32_Dome/
├── README.md                  ← 项目说明
├── examples/
│   ├── hello/                 ← ⭐ 本教程项目
│   │   ├── .cargo/
│   │   │   └── config.toml    ← 构建配置(目标芯片、烧录器)
│   │   ├── src/
│   │   │   ├── bin/
│   │   │   │   └── main.rs    ← ⭐ 主程序代码
│   │   │   └── lib.rs         ← 库入口(本项目未使用)
│   │   ├── build.rs           ← 构建脚本
│   │   ├── Cargo.toml         ← 依赖声明
│   │   └── rust-toolchain.toml ← 指定 esp 工具链
│   ├── LED/                   ← LED 闪烁
│   ├── 按键LED/               ← 按键控制 LED
│   └── ...                    ← 更多示例
└── dome/                      ← 进阶项目(SPI 显示屏等)

关键配置文件

.cargo/config.toml --- 告诉 Cargo 编译到哪个芯片:

toml 复制代码
[build]
target = "xtensa-esp32s3-none-elf"    # ESP32-S3 的编译目标

[target.xtensa-esp32s3-none-elf]
runner = "probe-rs run --chip=esp32s3" # cargo run 时自动用 probe-rs 烧录

rust-toolchain.toml --- 指定使用 esp 工具链:

toml 复制代码
[toolchain]
channel = "esp"   # espup 安装的专用工具链

Cargo.toml --- 依赖声明:

toml 复制代码
[dependencies]
esp-hal = { version = "~1.1.0", features = ["esp32s3"] }  # 硬件抽象层
esp-bootloader-esp-idf = "0.5.0"                          # IDF 引导加载程序
rtt-target = "0.6"                                        # RTT 日志输出
panic-rtt-target = "0.2"                                  # panic 时输出错误

5. 代码逐行详解

5.1 嵌入式必需声明

rust 复制代码
#![no_main]
#![no_std]
声明 作用 为什么需要
#![no_main] 禁用标准 main 入口 嵌入式没有操作系统,用 #[main] 宏替代
#![no_std] 禁用标准库 std std 依赖 OS(文件/网络/线程),嵌入式只能用 core

📌 每个嵌入式 Rust 程序都必须有这两行,直接背下来就行。

5.2 导入依赖

rust 复制代码
use esp_bootloader_esp_idf;
use esp_hal::{main, time::Instant};
use rtt_target::{rprintln, rtt_init_print};
use panic_rtt_target as _;
模块 用途
esp_bootloader_esp_idf ESP-IDF 引导加载程序(芯片启动用)
esp_hal::main 程序入口宏
esp_hal::time::Instant 时间测量工具(类似 std::time::Instant
rtt_target::rprintln RTT 打印宏(类似 println!
rtt_target::rtt_init_print 初始化 RTT 打印功能
panic_rtt_target panic 时通过 RTT 输出错误信息

📌 use panic_rtt_target as __ 表示"我不直接用这个模块的名字,但需要它生效"------这是 Rust 中引入"副作用模块"的惯用写法。

5.3 应用描述符

rust 复制代码
esp_bootloader_esp_idf::esp_app_desc!();

生成 ESP-IDF 引导加载程序需要的元数据(版本、大小等)。必须有,否则烧录会失败。

5.4 程序入口

rust 复制代码
#[main]
fn main() -> ! {
    rtt_init_print!();
语法 含义
#[main] esp-hal 的入口宏,替代标准 fn main()
-> ! "永不返回"类型 --- 嵌入式程序永远运行,不会退出
rtt_init_print!() 初始化 RTT,之后才能用 rprintln!

5.5 初始化硬件

rust 复制代码
    let _peripherals = esp_hal::init(esp_hal::Config::default());
复制代码
芯片上电
   │
   ▼
esp_hal::init()
   │
   ├── 配置时钟系统
   ├── 配置电源管理
   ├── 初始化 GPIO 控制器
   └── 返回 peripherals 对象(包含所有外设控制权)

_peripherals 的下划线前缀 _ 表示"暂时不用这个变量",但 init() 必须调用,否则硬件没初始化。

5.6 主循环

rust 复制代码
    let mut count: u32 = 0;

    loop {
        rprintln!("你好,第 {} 次", count);
        count += 1;

        // 忙等待延时 500ms
        let start = Instant::now();
        while start.elapsed().as_millis() < 500 {}
    }

逐行解析:

代码 作用
1 let mut count: u32 = 0 定义可变计数器
2 loop {} 无限循环,嵌入式程序必须有
3 rprintln!(...) 通过 RTT 输出文字到调试器
4 count += 1 计数器自增
5 Instant::now() 记录当前时间戳
6 while ... < 500 {} 忙等待 500 毫秒

延时原理图:

复制代码
时间轴 ─────────────────────────────────→

start = Instant::now()
  │
  ├── 0ms   start.elapsed() = 0ms   → 循环继续
  ├── 100ms start.elapsed() = 100ms → 循环继续
  ├── 200ms start.elapsed() = 200ms → 循环继续
  ├── ...
  └── 500ms start.elapsed() = 500ms → 条件不满足,跳出循环
                                        │
                                        ▼
                                    打印下一行文字

⚠️ 忙等待会一直占用 CPU,实际项目中推荐用定时器中断。但作为入门示例,它最容易理解。


6. 编译与烧录

6.1 编译

bash 复制代码
cd Rust_ESP32_Dome/examples/hello
cargo build --release

⚠️ 嵌入式项目建议用 --release,debug 模式的二进制可能太大。

6.2 烧录

bash 复制代码
cargo run --release

输出示例:

复制代码
   Compiling hello v0.1.0
    Finished `release` profile [optimized] target(s) in 5.23s
     Running `probe-rs run --chip=esp32s3 ...`
     Erasing ✔ 100% [####################]  12.00 KiB @  12.00 KiB/s
     Programming ✔ 100% [####################]  12.00 KiB @  12.00 KiB/s
INFO - ESP32-S3 启动成功!开始计数...
INFO - 你好,第 0 次
INFO - 你好,第 1 次
INFO - 你好,第 2 次

6.3 进入下载模式(如果烧录失败)

  1. 按住 BOOT 按键不放

  2. 按一下 RST 按键

  3. 松开 BOOT 按键

  4. 重新执行 cargo run --release

    复制代码
     ┌─────────────────────────────────────┐
     │       ESP32-S3 嘉立创开发板          │
     │                                     │
     │   [BOOT] 按键     [RST] 按键        │
     │    GPIO0            EN              │
     │                                     │
     │   按住 BOOT → 按 RST → 松 BOOT     │
     │   = 进入下载模式                     │
     └─────────────────────────────────────┘

7. 常见问题

Q1:编译报错 can't find crate for core

原因:没装 ESP32 工具链

bash 复制代码
espup install
source $HOME/export-esp.sh

Q2:烧录失败 Failed to connect

原因:开发板没进入下载模式

解决:按住 BOOT → 按一下 RST → 松开 BOOT → 重新烧录

Q3:看不到 RTT 日志

原因 :RTT 输出需要 probe-rs 支持,确认用的是 cargo run(不是 espflash

排查步骤

bash 复制代码
# 确认 probe-rs 已安装
probe-rs --version

# 确认开发板连接
probe-rs info --chip esp32s3

Q4:编译很慢

原因 :嵌入式项目需要从源码编译 core 库(build-std = ["alloc", "core"]),首次编译需要 2-5 分钟

解决:耐心等待,后续编译有缓存会快很多(增量编译通常 < 10 秒)

Q5:Windows 上找不到串口

解决:安装 CP2102 或 CH340 驱动(嘉立创开发板一般用 CH340)


8. 扩展练习

练习 说明 难度
修改延时 把 500ms 改成 100ms / 1000ms,观察输出频率变化
LED 闪烁 结合 GPIO48,每次打印时翻转 LED ⭐⭐
按键计数 按一下 BOOT 键,count 才 +1 ⭐⭐
温度打印 读取芯片内部温度传感器,打印温度值 ⭐⭐⭐
WiFi 联网 连接 WiFi,打印 IP 地址 ⭐⭐⭐

📝 完整源码

rust 复制代码
// ESP32-S3 Hello World ------ 每隔 500ms 打印一次计数

// 嵌入式程序没有操作系统,不用标准库和默认 main
#![no_main]
#![no_std]

use esp_bootloader_esp_idf;
use esp_hal::{main, time::Instant};
use rtt_target::{rprintln, rtt_init_print};
use panic_rtt_target as _;

// ESP-IDF 引导加载程序要求的应用描述,必须有
esp_bootloader_esp_idf::esp_app_desc!();

// #[main] 标记入口,`-> !` 表示永不返回(嵌入式程序永远在跑)
#[main]
fn main() -> ! {
    rtt_init_print!(); // 初始化 RTT,之后才能用 rprintln!

    // 初始化硬件,peripherals 包含所有外设控制权
    // 下划线前缀 _ 表示"暂时不用这个变量"
    let _peripherals = esp_hal::init(esp_hal::Config::default());

    let mut count: u32 = 0;

    // 嵌入式程序必须有无限循环
    loop {
        rprintln!("你好,第 {} 次", count);
        count += 1;

        // 忙等待延时 500ms(简单但占 CPU,实际项目建议用定时器)
        let start = Instant::now();
        while start.elapsed().as_millis() < 500 {}
    }
}

参考资料

资源 链接
本项目 GitHub https://github.com/cx693/Rust_ESP32_Dome
Rust on ESP 官方教程 https://esp-rs.github.io/book/
esp-hal 仓库 https://github.com/esp-rs/esp-hal
ESP32-S3 数据手册 https://www.espressif.com/sites/default/files/documentation/esp32-s3_datasheet_cn.pdf
esp-hal 官方示例 https://github.com/esp-rs/esp-hal/tree/main/examples
probe-rs 调试工具 https://probe.rs/

🎉 恭喜你跑通了第一个 Rust + ESP32 程序!

如果觉得有帮助,欢迎 👍 点赞 / ⭐ 收藏 / 💬 评论

相关推荐
ACP广源盛139246256732 小时前
GSV5600@ACP#多接口协议转换芯片,物理 AI 便携终端的互联核心
大数据·人工智能·分布式·嵌入式硬件·spark
望眼欲穿的程序猿2 小时前
ESP32-S3 定时器中断
单片机·嵌入式硬件
电气_空空2 小时前
基于 LabVIEW 的深海气密采水器测控系统
单片机·嵌入式硬件·毕业设计·labview
牛牛,牛3 小时前
榨干最后一微安:STM32 的低功耗设计与中断唤醒机制深度剖析
单片机·嵌入式硬件
星华云3 小时前
[STM32] SAR型ADC(逐次逼近型ADC)工作原理简介
stm32·单片机·嵌入式硬件
小娄~~4 小时前
时钟控制器原理
单片机·嵌入式硬件
望眼欲穿的程序猿4 小时前
按键控制 LED
嵌入式硬件·rust
天天爱吃肉82185 小时前
豆包 vs DeepSeek API 对比分析报告
android·java·大数据·开发语言·功能测试·嵌入式硬件·汽车
ai安歌5 小时前
鸿蒙PC:Linux 搭建 Rust 开发环境并实现计算器项目
linux·rust·harmonyos