Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

esp-generate 简介

既然我们已经了解了如何生成一个 no_std 项目,让我们看看生成的项目里有哪些东西, 尝试理解它的各个部分,并运行它。

检查生成的项目

使用 esp-generate 创建项目时,如果不指定额外选项:

esp-generate --chip esp32c3 your-project

应该会生成类似这样的文件结构:

├── build.rs
├── .cargo
│   └── config.toml
├── Cargo.toml
├── .gitignore
├── rust-toolchain.toml
├── src
│   ├── bin
│   │   └── main.rs
│   └── lib.rs
└── .vscode
    └── settings.json

在进一步讨论之前,让我们看看这些文件的用途。

  • build.rs
    • 根据模板选项设置链接脚本参数
  • .cargo/config.toml
    • Cargo 的配置
    • 定义了一些用于正确构建项目的选项
    • 包含 espflashprobe-rs 的自定义 runner 命令。例如,runner = "espflash flash --monitor" - 这意味着你可以直接使用 cargo run 来烧写和监控你的代码
  • Cargo.toml
    • Cargo 清单(manifest),通常声明了一些元数据和项目的依赖项
  • .gitignore
    • 指示 git 要忽略哪些目录和文件
  • rust-toolchain.toml
    • 定义要使用的 Rust 工具链的种类
      • 根据目标设备,工具链可以是 nightlyesp
  • src/bin/main.rs
    • 项目的主要源文件
    • 关于它的详细信息,请参阅下面的 main.rs 简介一节
  • src/lib.rs
    • 用于告知 Rust 编译器这段代码不使用 libstd
  • .vscode/settings.json
    • 为 Visual Studio Code 定义一系列设置,使 Rust Analyzer 能够正常工作。

main.rs 简介

 1 #![no_std]
 2 #![no_main]
  • #![no_std]
    • 用于告知 Rust 编译器这段代码不使用 libstd
  • #![no_main]
    • no_main 属性表示该程序不使用标准的 main 接口,这通常用在有完整的操作系统的情况下。我们将使用 esp-riscv-rt crate 中的入口(entry)属性来创建一个自定义入口点(entry point),而不是使用标准的 main。在此程序中,我们将入口点命名为 main,但也可以使用任何其他名称。入口点函数必须是发散函数,即具有签名 fn foo() -> !,这种类型表明该函数永远不会返回——这意味着程序永远不会终止。
4 use esp_backtrace as _;
5 use esp_hal::delay::Delay;
6 use esp_hal::prelude::*;
7 use log::info;
  • use esp_backtrace as _;
    • 由于我们处于裸机环境中,因此需要一个 panic 处理程序,该处理程序在代码发生 panic 时运行
    • 有多种不同的 crate 可选(例如 panic-halt),但是 esp-backtrace 提供了一个打印回溯地址的实现——与 espflash 配合,这些地址可以被解析为源代码中的位置
  • use esp_hal::delay::Delay;
    • 提供 Delay 驱动实现。
  • use esp_hal::prelude::*;
 8 #[entry]
 9 fn main() -> ! {
10    esp_println::logger::init_logger_from_env();
11
12    let delay = Delay::new();
13    loop {
14      info!("Hello world!");
15      delay.delay(500.millis());
16    }
17 }

main 函数中包含:

  • esp_println::logger::init_logger_from_env();
    • 初始化日志记录器,如果定义了 ESP_LOG 环境变量,将使用该日志级别。
  • let delay = Delay::new();
    • 创建一个延迟实例。
  • loop {}
    • 由于我们的函数应该永远不会返回,所以我们使用循环
  • info!("Hello world!");
    • 创建一个 info 级别的日志消息,打印 "Hello world!"。
  • delay.delay(500.millis());
    • 等待 500 毫秒。

运行代码

构建和运行这段代码只需:

cargo run --release

这会根据配置构建代码,并执行 espflash 将其烧写到板子上。

由于 runner 配置还会将 --monitor 参数传递给 espflash,屏幕上将显示打印的内容。

确保已经安装了 espflash,否则此步骤会失败。执行此命令以安装 espflashcargo install espflash

屏幕上应该会显示类似这样的内容:

...
[2024-11-14T09:29:32Z INFO ] Serial port: '/dev/ttyUSB0'
[2024-11-14T09:29:32Z INFO ] Connecting...
[2024-11-14T09:29:32Z INFO ] Using flash stub
[2024-11-14T09:29:33Z WARN ] Setting baud rate higher than 115,200 can cause issues
Chip type:         esp32c3 (revision v0.3)
Crystal frequency: 40 MHz
Flash size:        4MB
Features:          WiFi, BLE
MAC address:       a0:76:4e:5a:d2:c8
App/part. size:    76,064/4,128,768 bytes, 1.84%
[00:00:00] [========================================]      13/13      0x0
[00:00:00] [========================================]       1/1       0x8000
[00:00:00] [========================================]      11/11      0x10000
[2024-11-14T09:29:35Z INFO ] Flashing has completed!
Commands:
    CTRL+R    Reset chip
    CTRL+C    Exit
...
INFO - Hello world!

这些是第一和第二阶段 bootloader 产生的信息,然后是我们的 “Hello world” 信息!

这就是这段代码做的事情。

可以按 CTRL+R 重启,或按 CTRL+C 退出。

如果在构建项目时遇到了什么问题,请查看 Troubleshooting 章节。