ROWLETBOT · FRAMEWORK

环境配置
从零到能烧录。

RowletBot 电控框架的 Windows 开发环境配置教程:装工具、拿代码、编译、烧录、Ozone / VS Code 调试,以及一份能按报错查的故障字典。所有命令均在真机逐条校验。

8 章 · 33 条故障字典 · 3 个附录

图例:■ 注意■ 提示■ 要点■ 目标■ 通过

给谁看:会一点 C,没用过 CMake / 交叉编译 / 嵌入式工具链的同学。 前提:Windows 10/11(最好有管理员权限)+ 一块主控板 + 一个调试器。 要多久:走通第 1~4 章(配置 → 编译 → 烧录)约 2~3 小时(下载占大半)。 把第 5、6 章(Ozone / VS Code 调试)也做完,一共约 4~5 小时。

怎么读:第 0 → 1 → 2 → 3 → 4 章,按顺序,别跳。 任何一步报错都不要跳过,去 第 7 章 按报错现象查表。

一个约定:命令里的路径分两种 —— 仓库根目录(能看到 project.py 的那一层,你自己解压出来的位置) 和 <你的工具目录>(工具的安装位置,第 1 章装完就在那儿;本文示例写成 C:\Tools\)。 ⚠️ 只有 Ninja 必须放在 C:\Tools\ninja\(见 §0.3)—— 其余工具换到别的盘、别的目录都行, 但换了目录之后,命令里的路径要跟着换成你自己的实际路径,也别改成相对路径。 本文用 RowletBot 当示例目录名,换成你自己的。


目录

章 内容 大概多久
第 0 章 这套环境到底是什么、十个工具各干什么、目录布局、两条铁律 15 分钟(读)
第 1 章 装 7-Zip / VS Code / Python / Git / CMake / Ninja / LLVM / ARM 工具链 / OpenOCD(9 件) 1.5~3 小时
第 2 章 解包压缩包、子模块真相、什么时候才需要 Git 20 分钟
第 3 章 编出第一个固件(build_script.bat)、产物在哪、怎么改一行看变化 30 分钟
第 4 章 接线、确认调试器、烧录、烧录成功的样子 20 分钟
第 5 章 装 Ozone + J-Link、替换 JLinkARM.dll(必装包取件页) 20 分钟
第 6 章 插件、跳转、调试、快捷键 20 分钟
第 7 章 故障字典:33 条常见故障,按现象查表 按需查(不必顺序读)
附录 A–C 目录结构 / 版本参照 / 术语表 按需查

第 0 章 开始之前

📖 本章导读

  • 做什么:搞清楚这套环境是什么、要装哪十件工具、装完长什么样
  • 需要:15 分钟,不用动手,读完就行
  • 读完的标志:能说出「clang 编译、gcc 链接」,并知道自己该把仓库放在哪

0.1 一句话说清:这套环境是什么

你写的代码在你的电脑上被翻译成 ARM 机器码,打包成一个 .bin 文件,通过调试器烧进单片机,然后板子跑起来。

   ┌──────────────────────────┐   ①编译             ┌─────────────┐
   │ VS Code 写代码            │  ──────────────►   │  ┌─────────────┐  │
   │ clang 翻译成 ARM 码       │   生成 xrobot.bin   │  │ 只能跑 ARM   │  │
   └──────────────────────────┘                     │  │ 机器码       │  │
              ▲                    ②烧录             │  └─────────────┘  │
              │                ──────────────►      │         ▲         │
              │                通过调试器            └─────────┼─────────┘
              └─────────────────────── ③看现象(轮子转 / 灯闪)┘

三个新词:

词 一句话解释
单片机 / MCU 那块"小电脑"。常用的板子上是 STM32H723VG(mc02 板)或 STM32F407IG(rm-c 板)
固件 / firmware 烧进单片机里、长期住在里面的那个程序。相当于电脑上的 .exe
工具链 / toolchain 「编译器 + 链接器 + 打包工具」这一整套的统称。缺任何一件,编译都跑不起来

0.2 十个工具,每个是干什么的

工具 干什么(大白话) 不装会怎样
7-Zip 解压工具:.zip / .7z / .rar / .tar.gz 都能开,右键一键解压 第 2 章那个 .tar.gz 代码包必须靠它 —— 别的工具解不开
VS Code 写代码的编辑器,能高亮、能跳转、能一键编译 只能用记事本写代码
Git(可选) 管理代码版本:看改动、提交、回滚 学习阶段不装也能用 —— 框架是压缩包下发的。想给自己的改动做"游戏存档"再装
Python 3.12 跑 project.py,整个工程的总指挥 python project.py build 直接报「不是内部或外部命令」
CMake 算出要编哪些文件、用什么参数,生成构建清单 编译根本起不来
Ninja 按 CMake 算好的清单一条条执行编译,比 make 快得多 编译根本起不来
ARM GNU Toolchain 把零散的 .o 链接成一个 .elf,并附带 objcopy/size 最后一步链接失败,.bin 永远出不来
LLVM / Clang 真正把 C/C++ 翻译成 ARM 机器码的那个人 编不出 .o 文件
OpenOCD 把固件写进单片机,也能在线调试(作 GDB server) 编译得再好也烧不进去
Ozone 图形化调试器:断点、单步、看变量、看外设寄存器(第 5 章单独装) 必装 —— 调试、断点、看变量、变量曲线都靠它

🔑 必须记住的反直觉点:clang 编译,gcc 链接

嵌入式教程通常说「就用 arm-none-eabi-gcc 编」,本框架不是这样:

  • clang / clang++ 负责编译(加 --target=arm-none-eabi 变成交叉编译器);
  • arm-none-eabi-gcc 只负责链接 —— 因为工程用了 nano + nosys specs, 而 LLVM 的 lld 不支持 GCC 的 specs 文件;
  • arm-none-eabi-size / objcopy / objdump / ar 负责后处理和归档。

结论:两套工具链都得装,缺一个都编不出来。

0.3 装完长什么样:目录布局(照抄即可)

⚠️ 只有 Ninja 必须放在 C:\Tools\ninja\(测试证明:它放别处会出问题); 其余工具全部可以换盘 / 换目录。

下面这棵树是教程用的示例布局(照抄最省事):

C:\Tools\
  ├─ ninja\                  ← Ninja ⚠️ 唯一"必须在这儿"的(ninja\ninja.exe)
  ├─ openocd\                ← OpenOCD(可以换盘,见 §1.9)
  └─ arm-gnu-toolchain\      ← ARM 工具链(可以换盘,见 §1.8)

用官方安装包安装的(下表是安装器的默认位置 —— 你可以改成别的盘/别的目录,改了记得自己记住):

工具 安装包 默认装到哪(可自选)
7-Zip 7z*-x64.exe <你的 7-Zip 安装目录>\(默认 C:\Program Files\7-Zip\)
Git(可选) Git-<版本>-64-bit.exe <你的 Git 安装目录>\cmd\git.exe(默认 C:\Program Files\Git\)
Python 3.12 python-3.12.x-amd64.exe <你的 Python 安装目录>\python.exe(默认 %LOCALAPPDATA%\Programs\Python\Python312\)
VS Code VSCodeUserSetup-x64-<版本>.exe <你的 VS Code 安装目录>\(默认 %LOCALAPPDATA%\Programs\Microsoft VS Code\)
CMake cmake-<版本>-windows-x86_64.msi <你的 CMake 安装目录>\bin\cmake.exe(默认 C:\Program Files\CMake\)
LLVM / Clang LLVM-18.1.8-win64.exe <你的 LLVM 安装目录>\bin\clang.exe(默认 C:\Program Files\LLVM\)
Ozone Ozone_Windows_V324_x86.exe <你的 SEGGER 安装目录>\(默认 C:\Program Files (x86)\SEGGER\,目录名带版本号如 Ozone V3.24;位置可自选)
ARM GNU Toolchain arm-gnu-toolchain-13.3.rel1-*.exe <你的 ARM 工具链目录>\bin\arm-none-eabi-gcc.exe(教程示例:C:\Tools\arm-gnu-toolchain\,为什么不用安装器默认路径见下)
本仓库 学长给的压缩包 例如 %USERPROFILE%\Desktop\RowletBot,⚠️ 不能有中文和空格

⚠️ 为什么 ARM 工具链建议别用安装器默认路径:ARM 安装器的默认路径是 C:\Program Files (x86)\Arm GNU Toolchain arm-none-eabi\13.3 rel1\ —— 里面有空格。 本工程的 toolchain.cmake 要把 sysroot 路径拼成编译参数传给 clang, 带空格的路径在这种场景下是经典的踩坑点;装到一个不含空格/括号的目录最省事 (教程示例:C:\Tools\arm-gnu-toolchain —— 换成 D:\Tools\arm-gnu-toolchain 一样可以)。

💾 装到哪个盘都行 —— C:\Tools\ 只是约定,不是硬要求

💾 装到哪个盘都行 —— C:\Tools\ 只是约定,不是硬要求

C 盘小的同学可以整套搬到 D 盘。全部工具装到 D:\ (D:\Tools\、D:\ProgramFiles\、D:\RowletBot)后编译完全正常 (build all all → 11 个目标成功,单目标 25.2 秒)。

因为工程里没有任何写死的盘符:

依赖 实际怎么找到的
ARM 工具链 toolchain.cmake 用 execute_process(COMMAND where arm-none-eabi-gcc) 查 PATH,再取 <bin>/.. 推 sysroot → 装哪都行,只要 PATH 对
OpenOCD cfg 里是 source [find interface/…] 相对查找,靠自身 scripts 目录或 OPENOCD_SCRIPTS,与盘符无关
构建系统 全部相对路径(BSP_DIR=${CMAKE_CURRENT_SOURCE_DIR}/hw/bsp)

构建链路里没有任何写死的盘符 —— 在 CMakeLists.txt、hw\bsp\*\toolchain.cmake、*.cfg 里 grep C:\Tools / C:\Program → 0 命中。 仓库里另有几处带 C:\Tools 的文件,但都不是构建输入:

  • tools\ozone\ 下两个 .bat 和 README.md —— 那是另一条 Ozone 调试路线 (Ozone ≥3.40 + OpenOCD GDB server,和本文第 5 章的 Ozone 3.24 直连不是一套), 脚本里写死了作者机器的路径,照抄会报 ERROR: Ozone not found at C:\Tools\Ozone\Ozone.exe;
  • doc\ 下的历史报告 / 指南 —— 纯文档,不参与编译。

唯一要守的还是「路径不能有中文和空格」(§0.4 铁律 1)。 换 D 盘时别用 D:\Program Files\ —— 那个空格会在脚本传参时出事(见坑 33), 用 D:\ProgramFiles\ 更稳。

判断 openocd 布局对不对:<你的 OpenOCD 目录>\bin\openocd.exe 和 <你的 OpenOCD 目录>\share\openocd\scripts\interface\cmsis-dap.cfg 两个文件都要存在(教程示例目录:C:\Tools\openocd\)。

0.4 两条铁律(违反任何一条都会浪费你一整天)

# 规矩 违反了会怎样
1 所有路径里不能有中文、空格、特殊符号 utils\python\tool.py 会直接打印「工程路径请不要带有空格 / 中文」然后退出;CMake / Ninja 也会报各种看不懂的错
2 命令一律在仓库根目录敲 openocd -f hw/bsp/mc02/debug/openocd_dap.cfg、build/xrobot.bin 全是相对路径,在别的目录敲会「找不到文件」

0.5 开工前的准备清单

硬件

# 东西 说明 没有会怎样
1 主控板(mc02 / rm-c / …) 带 STM32 芯片的机器人主控板 只能编译,不能烧录验证
2 调试器 DAP-Link / J-Link / ATK 无线调试器,任选一种 同上
3 烧录线 4 根 接 3V3 / GND / SWDIO / SWCLK 同上
4 给板子供电的电源 电池或 USB 供电都行 板子不跑
5 USB 线(能传数据的) ⚠️ 有些线只能充电不能传数据 烧录 / 调试连不上

软件 / 账号

# 东西 说明
1 至少 10 GB 空闲磁盘 工具链约 1.5 GB,仓库 + 构建产物约 5 GB
2 稳定的网络 首次下载约 1.5 GB
3 管理员权限(装 Python / VS Code 系统版时需要) 装 C:\Tools 下的绿色包不需要管理员
4 学长给你的框架压缩包 ✅ 学习阶段就靠这个 —— 不需要 GitHub 账号,也不需要 git clone,见第 2 章

💡 学习阶段不需要 Git,也不需要 GitHub 权限 —— 框架用压缩包下发(见 §2.1)。 什么时候才需要 Git,见 §2.4。


第 1 章 装工具(逐步详细)

📖 本章导读

  • 做什么:把九件工具装上(Ozone 在第 5 章单独装),并让 PATH 生效(本章最长,占了全程一多半时间)
  • 需要:管理员权限、约 1.5 GB 下载量、2~3 小时(下载占大半)
  • 做完的标志:新开一个终端,§1.11 那 7 条版本命令全都有输出

⚠️ 本章最容易崩心态的地方是"装完了但敲不出来" —— 那 99% 是 PATH 没生效, 不是你没装好。别急着重装,先看 §1.10 和坑 2。

1.0 装之前先读这 5 条

装之前花 2 分钟扫一遍,能省下几个小时。

# 规矩 一句话原因
1 路径不要有中文和空格 工程脚本会直接拒绝含中文/空格的路径(§0.4 铁律 1)
2 不要装"最新版" 有四个工具有版本红线,见下表
3 PATH 加完必须重开终端 终端只在启动那一瞬间读一次 PATH
4 把 C:\Tools 和仓库目录加进杀毒白名单 不加编译 5 分钟级 → 加了 20 秒级
5 想装到别的盘要改 6 个地方 本文默认 C:\Tools\;换盘不是改一个路径就完事,见下面第 5 条

第 1 条 · 什么算好路径

✅ C:\Tools\...                      ✅ %USERPROFILE%\Desktop\RowletBot
❌ C:\工具\...                       ❌ D:\我的 文件\...

第 2 条 · 四个不能装最新的工具(本教程最重要的版本约束)

工具 必须装 装错的后果
OpenOCD sysprogs 0.11.0 xPack 0.12.0 烧不进去 —— 探测正常、写入失步,报错极具迷惑性 → §1.9
Ozone 3.24(32 位)+ J-Link 7.22b 新版连不上 DAP-Link,曲线功能也用不了 → 第 5 章
ARM GNU Toolchain 13.3.rel1 太新会换掉 newlib 头文件布局,CMake 找不到工具链 → §1.8
LLVM / Clang 18.1.x 19 之后对编译参数检查更严,可能编不过 → §1.7

第 3 条 · 为什么"重开终端"这么重要

终端只在启动的那一刻读一次 PATH,加完 PATH 不重开等于没加。 VS Code 的终端是 VS Code 的子进程 —— 所以VS Code 要整个关掉重开(见坑 2)。

🖥 "终端"是什么、在哪儿打开?(零基础看这里 —— 全教程只讲这一遍)

终端 = 敲命令的那个黑窗口(本文里 cmd 和 PowerShell 都算终端)。打开方法:

  1. 同时按住键盘左下角的 Windows 键和 R 键(即 Win + R), 屏幕左下角会弹出一个小窗口,标题是「运行」;
  2. 在里面的输入框键入 cmd(三个字母),按回车;
  3. 弹出的黑底白字窗口就是本文说的"终端"。窗口里会显示一行以 C:\Users\你的用户名> 开头的提示符,后面闪烁的方块就是光标 —— 命令就敲在这里。

以后每次改完 PATH,都要先把旧窗口关掉、再按上面三步重新开一个新的 —— 在旧窗口里敲什么都没用(原因就是上面那句话)。

💡 习惯 PowerShell 的话:第 2 步输入 powershell 再回车,效果一样。 ⚠️ 但本文标着 bat 的命令请用 cmd 跑 —— 有两条 cmd 写法在 PowerShell 里不成立: where 要写成 where.exe(PowerShell 里 where 是 Where-Object 的别名,敲 where git 什么都不显示)、 A & B 要拆成一行一条(& 在 PowerShell 里不是命令分隔符)。 标着 powershell 的代码块,当然要用 PowerShell 跑。

第 4 条 · 杀毒白名单怎么加

你的系统 入口路径
Windows 11 设置 → 隐私和安全性 → Windows 安全中心 → 病毒和威胁防护
Windows 10 设置 → 更新和安全 → Windows 安全中心 → 病毒和威胁防护

🔍 两条都找不到?用搜索:打开「设置」,在窗口顶部的搜索框里输入 病毒和威胁防护(或 Windows 安全中心),点搜出来的第一条,一样能进去。

进去之后:「病毒和威胁防护」设置里点 「管理设置」 → 往下滚,找到「排除项」(不在最底部 —— 它下面还有「通知」等几段)→ 「添加或删除排除项」 → 「添加排除项」→「文件夹」,把下面两个加进去:

⚠️ 点「添加或删除排除项」时会弹一个 UAC 管理员确认框,点「是」; 如果你的账号不是管理员,跳过这一条就行(只是编译慢,不影响正确性)。

要加的文件夹 为什么
C:\Tools(或你放工具的目录) 免得编译器 / openocd 被反复扫描
你的仓库文件夹(如 %USERPROFILE%\Desktop\RowletBot) 免得编译产生的 .o 被逐个扫描

⚠️ 注意:这两个文件夹现在都还不存在 —— 这一条要分两次做,别在这里卡住。

文件夹 现在怎么办
C:\Tools 现在就手工建一个空的:打开「此电脑」→ 进 C:\ → 在空白处右键 → 新建 → 文件夹 → 命名为 Tools(不能有空格),建完回到上面把它加进白名单。§1.6 装 Ninja 时就是往这个空文件夹里放东西,不影响。
你的仓库文件夹 先不加,等第 2 章解压完再回来补 —— 它要到 §2.2 解压压缩包时才出现。拿到 RowletBot 文件夹后,照上面同样的步骤再「添加排除项 → 文件夹」一次即可。

💡 不想现在建 C:\Tools 也行:整条先跳过,等 §1.6 建好 C:\Tools、第 2 章解压出仓库之后,再回来一次性加这两个文件夹。 但别拖到编译突然变慢才想起来 —— 那时你会以为是环境装坏了。

(C:\Tools 要你自己建(就是上面表里那次),教程不会替你建;仓库目录要到 第 2 章 才有。)

不加排除项编译要 5 分钟级,加了之后 20 秒级。 偶尔还会文件被锁住 → ninja: error: ... Permission denied。

第 5 条 · 想把工具装到别的盘(比如 C 盘小、只有 D/E 盘)

完全可以 —— 把十件工具全部装到 E 盘(E:\Tools\、E:\RowletBot), 编译正常通过(mc02 上的目标 29.45 秒,与默认盘符无差别)。 只要满足"路径无中文无空格"(第 1 条)就行。

⚠️ 除了 Ninja,其余工具都可以换盘 —— Ninja 必须留在 C:\Tools\ninja\(测试证明它只有放这儿才稳)。

换盘后要一起改下面这几处,漏一处就会报「找不到命令」或「找不到工具链」:

# 在哪一节 要改什么
1 §1.3~§1.7 五个官方安装包 装的时候如果改了默认位置,后面核对/where 里的路径也要跟着改(本文都写成 <你的 X 安装目录>)
2 §1.8 ARM 工具链 安装路径(示例 C:\Tools\arm-gnu-toolchain → 你的盘)
3 §1.9 OpenOCD 解压目标(示例 C:\Tools\openocd\ → 你的盘)
4 第 5 章 Ozone / J-Link 安装目录(位置可自选;目录名带版本号,别写死)
5 §1.10 PATH ⚠️ 手动加的 OpenOCD 那一条要换成你的实际路径(Ninja 那条不要动),还有 OPENOCD_SCRIPTS 那一行
6 §1.11 自检 里面的绝对路径核对命令

💡 最省事的办法:换盘之后不用自己找,直接 双击 5-check.bat —— 它会告诉你每个工具实际在哪(位置: 那一行)、 环境变量可不可用(只有 3 件还额外核对版本,见 §1.11)。 位置: 那行有你的实际路径、判定是 [OK],就说明你换对了。

📌 另外:仓库本身也可以放别的盘(放到 E:\RowletBot 完全正常)—— 工程里没有任何写死的盘符,见 §0.3。


1.1 第 1 步:7-Zip(解压工具)

下载:https://www.7-zip.org/ → 下 64-bit Windows x64 的 .exe 安装包 (文件名形如 7z*-x64.exe)。

安装:双击 → 确认 Destination folder 是 C:\Program Files\7-Zip\ → 点 Install → 装完点 Close。 (7-Zip 24 之后是单页安装器,没有 Next / Finish,这是正常的。)

为什么用它:

  • ✅ 格式全:.zip / .7z / .rar / .tar.gz / .tar.xz / .iso 都能开;
  • ✅ 快(多线程),解大包比别的工具快得多;
  • ✅ 「解压到当前位置」直接铺在当前文件夹,不多套一层同名目录;
  • ✅ 免费、开源、无广告、无捆绑。

1.2 第 2 步:VS Code

下载:https://code.visualstudio.com/download

下哪个 需要管理员 装到哪 适合
① User Installer(用户安装版,推荐) ❌ 不需要 C:\Users\<你>\AppData\Local\Programs\Microsoft VS Code\ 绝大多数人
② System Installer(系统安装版) ✅ 需要 C:\Program Files\Microsoft VS Code\ 多人共用一台机器

版本不用挑 —— 官网默认给的就是最新稳定版,装最新即可。

安装:

  1. 双击 → 接受许可协议 → 一路 Next;

    图 1-1 13_vsc_license.png
    图 1-1 许可协议页:选「我同意此协议」→ 点「下一步」

    ⚠️ 如果你当前是管理员账户,用户版安装器会弹一个提示:

    This User Installer is not meant to be run as an Administrator.
    If you would like to install VS Code for all users in this system,
    download the System Installer instead.
    

    点「确定」继续就行 —— 不影响安装,也不影响 PATH 注册。 不用跑去下系统版重装(本文推荐用户版,见下面那个说明框)。

    中间还有「选择目标位置」和「选择开始菜单文件夹」两页 —— 都保持默认,直接 Next:

    图 1-2 14_vsc_location.png
    图 1-2 选择目标位置:默认用户目录,不用改
    图 1-3 15_vsc_startmenu.png
    图 1-3 选择开始菜单文件夹:默认文件夹名,不用改
  2. ⚠️ 关键一步:务必勾上「添加到 PATH」(Add to PATH,默认就是勾上的,别取消) —— 它和第 3 步那几项都在同一页「选择附加任务」里。

  3. 把「其他」里的项全部勾上(一个都别漏);最上面的 「创建桌面快捷方式」勾不勾都行(它只是往桌面放一个图标)—— 英文界面这一页从上到下依次是:

    • 「附加快捷方式」:Create a desktop icon(创建桌面快捷方式)—— 可勾可不勾
    • 「其他」(这一组全部勾上):
      • Add "Open with Code" action to Windows Explorer file context menu(文件右键菜单)
      • Add "Open with Code" action to Windows Explorer directory context menu(目录右键菜单 —— 和上一条是两个独立的勾)
      • Register Code as an editor for supported file types(关联文件类型)
      • Add to PATH ← 这个本来就必须勾着,别取消(见第 2 步)

    ⚠️ 别去死记"勾前三项" —— 不同小版本这一页的项数和顺序会略有差别。 判断标准只有一条:添加到 PATH 必须勾着、「其他」里的项全部勾上 (只有「创建桌面快捷方式」可勾可不勾)。

    图 1-4 17_vsc_tasks_after.png
    图 1-4 「选择附加任务」页:「其他」里的项全部勾上(最上面的「创建桌面快捷方式」可勾可不勾
  4. 点「安装」后先是安装进度:

    图 1-5 18_vsc_installing.png
    图 1-5 安装进度

    最后是完成页 —— 点「完成(F)」:

    图 1-6 19_vsc_done.png
    图 1-6 完成页:点「完成(F)」—— 勾不勾「运行 Visual Studio Code」都行」

装插件(6 个):

  1. 打开 VS Code,按 Ctrl + Shift + X —— 左侧会弹出「扩展」面板(图标是四个方块);

  2. 在左侧扩展面板的搜索框里逐个搜下面的名字,找到后点结果行右边的「安装」:

    图 1-7 16_vsc_ext_panel.png
    图 1-7 搜索框在左侧扩展面板里(按 Ctrl+Shift+X 打开,不是窗口顶部的全局搜索栏)—— 搜到后点结果行右边的「安装」
# 在搜索框里粘这个 作用
1 ms-vscode.cpptools C/C++ 支持
2 ms-vscode.cmake-tools CMake 支持(含语法高亮,不用再单独装高亮插件)
3 marus25.cortex-debug 在线调试(第 6 章用)
4 dan-c-underwood.arm ARM 汇编高亮
5 llvm-vs-code-extensions.vscode-clangd 代码跳转 F12
6 ms-ceintl.vscode-language-pack-zh-hans 中文界面
  1. 装完关掉 VS Code 再打开 —— 重新打开看到的就是欢迎页:

    图 1-8 20_vsc_welcome.png
    图 1-8 重新打开 VS Code 的欢迎页(Get Started / Walkthrough)

怎么确认装齐了:扩展面板左侧有个 「已安装 / INSTALLED」 分组。

⚠️ 点开你会看到 11 个,不是 6 个 —— 这是正常的,别以为多出来的是垃圾:

来源 个数
上面让你装的 6 个
cortex-debug 自动带上的 mcu-debug.* 依赖 +4 个
cpptools 自动带上的 ms-vscode.cpp-devtools +1 个
合计 11 个

对照检查:只要上面表里那 6 个都在,就装齐了。少哪个再搜一遍装哪个。

备选:命令行版 —— 终端里一次性装完
code --install-extension ms-vscode.cpptools
code --install-extension ms-vscode.cmake-tools
code --install-extension marus25.cortex-debug
code --install-extension dan-c-underwood.arm
code --install-extension llvm-vs-code-extensions.vscode-clangd
code --install-extension ms-ceintl.vscode-language-pack-zh-hans

检查:code --list-extensions —— 应列出上面 6 个 ID(实际会多几条自动依赖,见上面的表)。

💡 如果 VS Code 卡在自动更新中间状态,code --list-extensions 会报 Error: Cannot find module ...cli.js。在 %APPDATA%\Code\User\argv.json 里加一行 "update.mode": "none" 关掉自动更新即可。


1.3 第 3 步:Python 3.12

下载:https://www.python.org/downloads/windows/ → 找 Python 3.12.x 那一栏, 下 Windows installer (64-bit)(文件名形如 python-3.12.x-amd64.exe)。 补丁号不用挑 —— 3.12 里最新的那个就行(本文只约束到 3.12 这个主次版本)。

⚠️ 不要装 3.13+:个别第三方库还没跟上。 ⚠️ 也别下错包:要 Windows installer (64-bit) —— 不要 embeddable package(缺 pip / tkinter), 也不要 ARM64 版(除非你确定是 ARM 电脑)。

安装:

  1. 双击安装包 —— 会先出现一个首屏,先别急着点 Install Now;

  2. 第一个界面底部,务必勾上 Add python.exe to PATH ← 不勾后面全是坑:

    图 1-9 09_py_addpath_after.png
    图 1-9 首屏:勾上 Add python.exe to PATH 再点 Install Now

    ⚠️ 首屏底部有两个复选框,另一个是 Use admin privileges when installing py.exe —— 不用勾:它决定安装器要不要用管理员权限把 py.exe(Python 启动器)装给所有用户 ("Customize installation" 页里这一项的原话就是 for all users (requires admin privileges))。 本文全程只用 python 命令、用不到 py;不勾,整个安装过程连管理员权限都不需要。

  3. 点 Install Now(默认装到 %LOCALAPPDATA%\Programs\Python\Python312\;想装到别处就点下面的 Customize installation,装完记住路径), 接下来是几分钟的安装进度:

    图 1-10 10_py_installing.png
    图 1-10 安装中:Setup Progress(进度条 + 当前在装的组件)
  4. 装完点 Disable path length limit(如果有这个按钮,点它):

    图 1-11 11_py_done.png
    图 1-11 完成页(改前):Setup was successful,下方还有 Disable path length limit
    图 1-12 12_py_pathlimit_after.png
    图 1-12 点过之后(改后):整项消失 = 已生效

验证(先重开终端 —— 刚勾的 Add python.exe to PATH 只对新开的终端生效):

python --version

期望:Python 3.12.x(补丁号不用对 —— 3.12 里哪个补丁都行)

python -c "import tkinter; print(tkinter.TkVersion)"

期望:8.6 ← 这是图形配置界面能不能开的关键。报 ModuleNotFoundError 说明装的时候没勾 tcl/tk and IDLE,重装一次。

where python

期望:第一行是你装的那个 python.exe(默认 %LOCALAPPDATA%\Programs\Python\Python312\python.exe;不能是 …\WindowsApps\…)


🔧 补充:Python 实际装在哪?

点「Install Now」时,Python 默认是仅当前用户安装,落在:

C:\Users\<你的用户名>\AppData\Local\Programs\Python\Python312\

不是 C:\Program Files\Python312(那需要管理员 + 选「Install for all users」)。

后面 §1.10 配 PATH、§1.11 自检都按 %LOCALAPPDATA%\Programs\Python\Python312 写(你要是换了安装位置,把它们换成你自己的), where python 能查到就说明对了。


1.4 第 4 步:Git(学习阶段可选)

💡 学习阶段用压缩包下发框架,所以不装 Git 也能一路走完(编译、烧录、调试全都行)。 着急开工的话,这一步可以直接跳到 §1.5。

什么时候才真正需要 Git,见 §2.4。这里给出安装方法,想装就照做。

下载:https://git-scm.com/download/win → 选 「64-bit Git for Windows Setup」 (认这个名字就行 —— 版本号不用挑,页面给的就是最新稳定版)

安装:一路 Next,但有 3 个地方要改。

第 1 页 · GPL 许可协议 —— 看完直接点「Next」,这页不用改:

图 1-13 01_git_welcome.png
图 1-13 第 1 页:GPL 许可协议,看完直接点「Next」

⚠️ 安装向导一共 16 页,要改的那 3 处分别在 第 5、6、7 页。改完这 3 处还没结束 —— 后面还有约 8 页(SSH 可执行文件、HTTPS 后端、换行符、终端模拟器、 git pull 行为、凭据助手、额外选项、实验特性)。

那 8 页全部保持默认,一路 Next 到 Install 就行。 别以为"改完 3 处就可以关窗口了"——那时候还没点 Install。

安装步骤 选什么 为什么
Choosing the default editor Use Visual Studio Code as Git's default editor 第 2 步已经装好 VS Code,选它以后 git commit 直接用 VS Code 编辑提交信息
Adjusting the name of the initial branch 点 Override(下方方框会自动出现 main,不用手输) 跟 GitHub 保持一致
Adjusting your PATH environment Git from the command line and also from 3rd-party software(默认) 这样才能在 VS Code 终端里敲 git

第 5 页 · 选择默认编辑器 —— 展开下拉框,选 Use Visual Studio Code as Git's default editor:

图 1-14 05_git_editor_fixed.png
图 1-14 第 5 页:展开下拉框,选 Use Visual Studio Code as Git's default editor

第 6 页 · 初始分支名 —— 点 Override(下方方框会自动出现 main,不用手输):

图 1-15 04_git_branch_after.png
图 1-15 第 6 页:点 Override,方框里会自动出现 main

第 7 页 · PATH 环境 —— 保持默认的推荐项就行:

图 1-16 05_git_path.png
图 1-16 第 7 页:保持默认 Git from the command line and also from 3rd-party software

安装中 —— 后面约 8 页全部保持默认,一路 Next 到 Install:

图 1-17 06_git_installing.png
图 1-17 点 Install 之后:Extracting files... + 进度条

完成页 —— 看到这个就点 Finish:

图 1-18 07_git_done.png
图 1-18 完成页:Completing the Git Setup Wizard → 点 Finish

验证(先重开终端 —— 装 Git 之前就开着的终端不认识 git):

git --version

期望:git version 2.x(补丁号不用对 —— 装了 2.48、2.50 都是对的)

where git

期望:打印出你装的那个 …\Git\cmd\git.exe(默认 C:\Program Files\Git\cmd\git.exe)—— ⚠️ where 只列路径,不打印版本号。


1.5 第 5 步:CMake

下载:https://cmake.org/download/ → 在 Windows 那一栏找 Windows x64 Installer(.msi,安装版)—— 认这个类型,不用记版本号。 (嫌官网慢也可以走 GitHub Releases,内容一样:https://github.com/Kitware/CMake/releases —— 认文件名以 -windows-x86_64.msi 结尾,别下 .zip 绿色包,也别下 i386 / arm64。)

安装:

  1. 双击 .msi → 欢迎页点 Next:

    图 1-19 21_cmake_welcome.png
    图 1-19 欢迎页 → Next
  2. 接受许可协议 → Next:

    图 1-20 22_cmake_license.png
    图 1-20 许可页:选 I accept the terms → Next
  3. ⚠️ 确认「Add CMake to the PATH environment variable」是勾着的 —— 它默认就是勾上的,不用改;Add CMake shortcut to the Desktop 默认未勾,要不要都行:

    图 1-21 23_cmake_options_before.png
    图 1-21 Install Options 默认状态:Add CMake to the PATH environment variable 默认就是勾上的
    图 1-22 24_cmake_options_after.png
    图 1-22 ① Add CMake to the PATH environment variable 保持勾选;② 桌面快捷方式本例已勾上(可勾可不勾)
  4. 安装路径:默认 C:\Program Files\CMake\,也可以装到别处(记住路径)→ Next → 出现 Ready to install CMake 页再点一次 Install:

    图 1-23 25_cmake_location.png
    图 1-23 目标文件夹:默认 C:\Program Files\CMake,改不改都行 —— 但要记住你选的路径

    安装中:

    图 1-24 26_cmake_installing.png
    图 1-24 安装中:Please wait while the Setup Wizard installs CMake.(下面 Status 进度条从空到满)

    完成页:

    图 1-25 27_cmake_done.png
    图 1-25 完成页:Completed the CMake Setup Wizard → Finish

装完应该是:

<你的 CMake 安装目录>\bin\cmake.exe        ← 必须有这个
<你的 CMake 安装目录>\share\...

验证(先重开终端):

cmake --version

期望:cmake version 3.x(认大版本就行)

📌 本文实测的是 CMake 3.31.x;如果官网给的是 4.x,也可以用 —— §1.11 的自检不核对 cmake 版本(只验"环境变量可用"),所以不会再报 [~]。 万一 cmake 配置这一步真的报错,就换回 3.31.x 重装。

where cmake

期望:第一行是你装的那个 …\CMake\bin\cmake.exe(默认 C:\Program Files\CMake\bin\cmake.exe)

⚠️ 如果 where cmake 没输出,说明装的时候没勾「Add CMake to the system PATH」。 跑一遍 §1.10 的脚本就能补上(那段脚本里带了这一条作为兜底)。


1.6 第 6 步:Ninja

下载:https://github.com/ninja-build/ninja/releases → ninja-win.zip

不要下 ninja-win-arm64.zip,除非你是 ARM 电脑。

⚠️ sysprogs 0.11.0 的 cmsis-dap 只有两个子命令

🛠 装完这一步,把 Ninja 加进 PATH

要加的路径:

C:\Tools\ninja

⚠️ 全教程要你手动加 PATH 的只有 2 个:Ninja 和 §1.9 的 OpenOCD —— Ninja 是绿色包,没有安装程序,PATH 只能自己加。

怎么加 —— 做法全教程只讲一遍,见 §1.10。 一句话版:Win+R → sysdm.cpl → 高级 → 环境变量 → 选中用户变量 Path → 编辑 → 新建 → 粘贴。

⚠️ sysprogs 0.11.0 的 cmsis-dap 只有两个子命令

网上有些教程会让你用 VID/PID 锁定探针:

openocd -f interface/cmsis-dap.cfg -c "cmsis-dap vid_pid 0x04d8 0x00df" -c "init; shutdown"

在本文要求的 sysprogs 0.11.0 上,这条跑不通 —— 它的 cmsis-dap 只有 cmd 和 info 两个子命令(vid_pid 是别的构建才有的)。

它不会报"未知命令",而是打印一段用法后静默退出 —— 又是个"看着像成功、其实没干活"的坑。

不需要它:hw\bsp\<板>\debug\openocd_dap.cfg 已经指定好了接口, 本文的 4 个工具也是这么用的。

安装(解压式):解压得到单独一个 ninja.exe,建目录 C:\Tools\ninja\ 放进去。

第 1 步 · 新建目标目录 —— 在 C:\Tools\ 下新建文件夹 ninja(还没有 C:\Tools\ 就先建它)。

第 2 步 · 用 7-Zip 解压 —— 在下载目录里右键 ninja-win.zip → 7-Zip →「解压到 "ninja-win"」, 再把解出来的 ninja.exe 放进 C:\Tools\ninja\。

💡 想一步到位:右键 → 7-Zip →「解压文件...」,在弹出的对话框里把目标填成 C:\Tools\ninja, 解压和落位一次完成。(认准对话框里的目标路径填对就行。)

⚠️ 7-Zip 那三个菜单项别点错(26.03 中文界面里的实际名字): 要指定目标目录 → 点「解压文件...」(会弹出一个带目标框的对话框); 「解压到当前位置」是直接解到当前文件夹(不问你); 「解压到 "xxx\"」是解到它自己建的同名文件夹。 名字很像 —— 认准带省略号的「解压文件...」。

⚠️ 对话框里如果有一个「解压到 "xxx"」的子文件夹勾(默认是勾着的),把它取消掉 —— 否则会多套一层目录。 拿不准就看解压结果:project.py(或 ninja.exe)直接躺在目标文件夹第一层就对了。

⚠️ 解压首选 7-Zip:右键 ninja-win.zip →「7-Zip」→「解压文件...」, 目标填 C:\Tools\ninja,一步到位(走法和 §2.2 解包代码包一致)。 万一右键没有「7-Zip」子菜单 —— 那是装完还没生效,注销重登一次再看。

第 3 步 · 目标路径 —— 在 7-Zip「解压文件...」对话框的目标框里填 C:\Tools\ninja。

第 4 步 · 确认结果 —— 目录里就一个 ninja.exe,没有多余层级:

图 1-26 31_ninja_result.png
图 1-26 结果:C:\Tools\ninja 里只有一个 ninja.exe(557 KB)
C:\Tools\ninja\ninja.exe            ← 必须有这个

验证(先重开终端):

"C:\Tools\ninja\ninja.exe" --version

期望:能打印出版本号(形如 1.12.1,小版本不用对)

💡 这里为什么用全路径:Ninja 是绿色包,PATH 要到 §1.10 才加 —— 现在还没有。 §1.10 配完 PATH 之后,直接敲 ninja --version 就行(那条同时也是 PATH 检查)。


1.7 第 7 步:LLVM / Clang

下载:https://github.com/llvm/llvm-project/releases 找 LLVM-18.1.8-win64.exe(安装版) 大小:374,335,885 字节(约 357 MB)

安装:

  1. 双击 → 欢迎页点 Next(中文向导):

    图 1-27 32_llvm_welcome.png
    图 1-27 中文向导欢迎页 → Next
  2. 许可页选「我接受(I)」→ Next:

    图 1-28 33_llvm_license.png
    图 1-28 许可页:选「我接受(I)」→ Next
  3. ⚠️ 改选「Add LLVM to the system PATH for all users」 —— 默认是 Do not add LLVM to the system PATH,不勾后面敲 clang 没反应:

    图 1-29 35_llvm_options_after.png
    图 1-29 Install Options:选 Add LLVM to the system PATH for all users
  4. 安装路径:默认是 C:\Program Files\LLVM\,你也可以装到别的盘(比如 D:\Tools\LLVM\)。 ⚠️ 不管装哪儿,把路径记下来 —— 虽然第 3 步勾了「Add LLVM to the system PATH for all users」, 但万一以后 PATH 里找不到 clang,你得能想起来它装在哪(手动补 PATH 时就要填这个路径)。 路径不能有中文和空格(§1.0 第 1 条)。→ Next:

    图 1-30 36_llvm_location.png
    图 1-30 选择安装位置:默认 C:\Program Files\LLVM,改不改都行 —— 但要记住你选的那个路径
  5. 这一页点右下角的「安装(I)」—— 点完才开始真正解压:

    图 1-31 W2_llvm_install_running.png
    图 1-31 「选择开始菜单文件夹」页:点右下角的「安装(I)」
  6. 然后就是漫长的解压(安装包约 2.6 GB,要等几分钟):

    图 1-32 37_llvm_installing.png
    图 1-32 安装中:解压 clang*.exe + 进度条(约 2.6 GB,要等)
  7. 看到完成页就点「完成(F)」:

    图 1-33 38_llvm_done.png
    图 1-33 完成页:LLVM 安装程序结束

装完应该是(<你的 LLVM 安装目录> = 你第 4 步选的那个;默认 C:\Program Files\LLVM\):

<你的 LLVM 安装目录>\bin\clang.exe        ← 必须有
<你的 LLVM 安装目录>\bin\clang++.exe      ← 必须有
<你的 LLVM 安装目录>\bin\clangd.exe       ← VS Code 跳转要用
<你的 LLVM 安装目录>\lib\clang\18\include\...   ← C++ 标准头文件

验证(先重开终端):

clang --version

期望(第一行):clang version 18.1.x —— 红线是 18.1.x(别装 19+),补丁号不用对

where clang

期望:第一行指向你装的那个 …\LLVM\bin\clang.exe(没改路径的话就是 C:\Program Files\LLVM\bin\clang.exe)

✅ 关键验证:clang 要能当 ARM 交叉编译器用

clang --target=arm-none-eabi -c -x c nul -o nul.o
  • 没有输出(静默成功)= ✅ 能用;
  • 报 error: unknown target triple 'arm-none-eabi' = ❌ 下错包了,重下。

⚠️ 别用 clang++ --target=arm-none-eabi 单独编 C++ 来验证环境 —— 那会报 fatal error: 'cstddef' file not found,是正常的:clang 不知道 ARM 的 libstdc++ 头文件在哪。工程 toolchain.cmake 会用显式 -isystem 喂给它。

真正算数的验证是 §3.4 的工程编译。


1.8 第 8 步:ARM GNU Toolchain

下载:https://developer.arm.com/downloads/-/arm-gnu-toolchain-downloads 在 "Windows (x86_64) hosted" 那一栏找:

arm-gnu-toolchain-13.3.rel1-mingw-w64-i686-arm-none-eabi.exe

大小:207,426,408 字节(约 198 MB)

⚠️ 别下错:

  • ...-x86_64-arm-none-eabi.tar.xz 是 Linux 版;
  • ...-darwin-... 是 macOS 版;
  • 带 -aarch64 的是给 ARM 电脑的 Windows。

(另有同版本 .zip 包,297,871,203 字节,解压式,适合脚本化;两者内容一致。)

安装:

  1. 双击 .exe —— 先在语言下拉框里选 中文(简体),点「确定」:

    图 1-34 39_arm_lang.png
    图 1-34 语言选择:下拉框选 中文(简体)

    然后是欢迎页:

    图 1-35 40_arm_welcome.png
    图 1-35 欢迎页 → Next
  2. 许可页选「我接受(I)」→ Next:

    图 1-36 41_arm_license.png
    图 1-36 许可页:选「我接受(I)」→ Next
  3. 安装路径:点一下文本框 → Ctrl+A 全选 → 键入你的安装目录。 默认那串带空格和括号,建议换个干净的(教程示例:C:\Tools\arm-gnu-toolchain)。→ Next:

    图 1-37 42_arm_location_before.png
    图 1-37 安装位置:默认路径带空格和括号,建议改成不含空格/括号的干净路径
  4. 点「安装(I)」:

    图 1-38 44_arm_installing.png
    图 1-38 安装进度
  5. 完成页 —— 点「完成(F)」之前,把 Add path to environment variable 勾上(它默认没勾):

    图 1-39 45_arm_done.png
    图 1-39 完成页:勾上 Add path to environment variable,再点「完成(F)」

    勾了 PATH 就自动配好你这个安装目录下的 bin,§1.10 不用再加这一条。

装完应该是(<你的 ARM 工具链目录> = 你第 3 步键入的那个路径,教程示例是 C:\Tools\arm-gnu-toolchain):

<你的 ARM 工具链目录>\bin\arm-none-eabi-gcc.exe    ← 必须有
<你的 ARM 工具链目录>\bin\arm-none-eabi-g++.exe
<你的 ARM 工具链目录>\bin\arm-none-eabi-objcopy.exe
<你的 ARM 工具链目录>\arm-none-eabi\include\...              ← newlib 头文件
<你的 ARM 工具链目录>\arm-none-eabi\include\c++\13.3.1\...   ← libstdc++ 头文件

实际落点长这样 —— bin / include / lib / share 和 arm-none-eabi 直接同级:

图 1-40 46_arm_result_folder.png
图 1-40 <你的 ARM 工具链目录>\ 的实际内容:各目录直接同级

📌 目录里多一层(如 <你的目录>\arm-gnu-toolchain-13.3.rel1\bin\)也不影响使用 —— 只要 bin 在 PATH 里就行。底下那两条验证命令跑通,就说明装对了。

验证(先重开终端):

arm-none-eabi-gcc --version

期望(第一行):

arm-none-eabi-gcc (Arm GNU Toolchain 13.3.Rel1 (Build arm-13.24)) 13.3.1 20240614

💡 这条命令其实一次验证两件事:① 工具链装好了;② 完成页那个 PATH 勾生效了。 报「不是内部或外部命令」= PATH 没配上(先 where arm-none-eabi-gcc 看有没有输出, 没有就回第 5 步确认那个勾)。 📌 不需要写全路径 —— 勾了 Add path to environment variable 之后 PATH 里就有它了; 写全路径反而绕过了 PATH 检查(就算 PATH 没配好也"跑得通")。

再验证 C++ 标准头文件在不在(这一步很多人会漏):

Get-ChildItem '<你的 ARM 工具链目录>' -Recurse -Filter cstddef |
  Select-Object -ExpandProperty FullName

期望:打印出 ...\arm-none-eabi\include\c++\13.3.1\cstddef(6,656 字节)。 (<你的 ARM 工具链目录> 就是你第 3 步键入的那个;忘了的话 where arm-none-eabi-gcc 会告诉你它在哪 —— 去掉末尾的 \bin\arm-none-eabi-gcc.exe 就是安装目录。)

⚠️ 注意路径:网上很多教程让你 dir ...\arm-none-eabi\include\cstddef, 但 13.3.rel1 里没有这个路径 —— 它把 C++ 头文件放在 include\c++\<版本>\ 下面。 上面这条 Get-ChildItem -Recurse 才是对的;照抄错的路径会让你误以为装坏了。


1.9 第 9 步:OpenOCD ⚠️ 版本选错会烧不进去

🔴 不要用 xPack 0.12.0

🛠 装完这一步,把 OpenOCD 加进 PATH

要加的路径(<你的 OpenOCD 目录>\bin;教程示例 C:\Tools\openocd\bin):

<你的 OpenOCD 目录>\bin

⚠️ 全教程要你手动加 PATH 的只有 2 个:OpenOCD 和 §1.6 的 Ninja —— OpenOCD 是绿色包,没有安装程序,PATH 只能自己加。

怎么加 —— 做法全教程只讲一遍,见 §1.10。 一句话版:Win+R → sysdm.cpl → 高级 → 环境变量 → 选中用户变量 Path → 编辑 → 新建 → 粘贴。

🔴 不要用 xPack 0.12.0

它在本战队的 DAP-Link 类调试器(含 ATK 无线调试器)上烧不进去。 现象很有迷惑性 —— openocd --version 正常,探测也完全正常(能看到 CMSIS-DAP、 Cortex-M7、flash 尺寸),但批量读内存必失步,dump_image 每次在 8–16 KB 处断:

Error: CMSIS-DAP command mismatch. Expected 0x6 received 0x5
Error: Failed to read memory at 0x080024e8

已排除:降速(1800/1000/500/250/100 kHz 全试过)、复位 USB、关掉占用进程 —— 都无效。 换成 0.11.0 后立刻恢复正常。

下载 OpenOCD.zip(sysprogs 构建的 0.11.0,22,315,834 字节)—— 快递柜取件页:

  1. 打开 http://139.196.220.183:8080/#/?code=YG347
  2. 页面上确认取件码是 YG347(链接里已经带上了,一般不用手输)
  3. 点页面上的 「下载」 按钮

⏳ 取件页是长期有效的;万一打不开或提示鉴权失败, 重新打开取件页、重新输一次取件码再点下载即可。

拿到包后核对这两条

项 值
bin\openocd.exe 4,245,518 字节
版本自证 openocd --version 第一行必须含 sysprogs/openocd

⚠️ 不要用压缩包大小判断 —— 换个打包方式(多套一层目录、压缩级别不同) 大小就差几百 KB。

安装(解压式):

  1. 新建目录 —— 教程示例 C:\Tools\openocd\,你可以换到别的盘/目录;

  2. 用 7-Zip 解压 OpenOCD.zip —— 右键 OpenOCD.zip → 7-Zip →「解压文件...」, 目标直接填你新建的那个目录(下文中统一写成 <你的 OpenOCD 目录>,教程示例 C:\Tools\openocd\。 这个包的顶层就是 bin\ / share\ / drivers\,解出来正好对上):

    ⚠️ 对话框里如果有一个「解压到 "xxx"」的子文件夹勾(默认是勾着的),把它取消掉 —— 否则会多套一层目录。

拿不准就看解压结果:project.py(或 ninja.exe)直接躺在目标文件夹第一层就对了。

  1. 装完应该是(<你的 OpenOCD 目录> = 你新建的那个;注意 bin 和 share 是同级的):

    图 1-41 49_openocd_structure.png
    图 1-41 <你的 OpenOCD 目录>\:bin 和 share 同级(drivers 可有可无)
    图 1-42 50_openocd_bin.png
    图 1-42 bin 里的 openocd.exe
<你的 OpenOCD 目录>\bin\openocd.exe                                    ← 必须有
<你的 OpenOCD 目录>\share\openocd\scripts\interface\cmsis-dap.cfg      ← 必须有
<你的 OpenOCD 目录>\share\openocd\scripts\target\stm32h7x.cfg          ← 必须有(mc02)
<你的 OpenOCD 目录>\share\openocd\scripts\target\stm32f4x.cfg          ← 必须有(rm-c)
share\openocd\scripts\ 和 bin\ 必须在同一个父目录下

share\openocd\scripts\ 和 bin\ 必须在同一个父目录下

OpenOCD 靠这些脚本认识各种调试器和芯片。如果布局错了,它报的错非常有误导性:

Can't find interface/cmsis-dap.cfg

—— 这不是配置写错了,是安装布局错了。

判断布局对不对(不用连板子):

openocd -c "echo FOUND=[find interface/cmsis-dap.cfg]" -c shutdown
  • 打印出 FOUND=.../share/openocd/scripts/interface/cmsis-dap.cfg = ✅ 布局对;
  • 报 Can't find = ❌ 布局错,把 scripts 挪到 share\openocd\ 下面。

兜底方案(布局一时改不动时):设一个环境变量显式告诉它脚本在哪 —— 把 OPENOCD_SCRIPTS 设为 <你的 OpenOCD 目录>\share\openocd\scripts(教程示例 C:\Tools\openocd\share\openocd\scripts) (用户变量和系统变量都设一份,见 §1.10 的脚本)。

验证(先重开终端):

"<你的 OpenOCD 目录>\bin\openocd.exe" --version

💡 这里为什么用全路径:OpenOCD 是绿色包,PATH 要到 §1.10 才加 —— 现在还没有,所以必须写全路径。 §1.10 配完 PATH 之后,直接敲 openocd --version 就行(那条同时也是 PATH 检查)。 期望:

Open On-Chip Debugger 0.11.0 (2021-11-18) [https://github.com/sysprogs/openocd]
Licensed under GNU GPL v2
libusb1 09e75e98b4d9ea7909e8837b7a3f00dda4589dc3
For bug reports, read
	http://openocd.org/doc/doxygen/bugs.html

1.10 把所有目录加进 PATH

PATH 是什么:Windows 的「去哪儿找程序」清单。 不把工具目录加进去,你敲 ninja 它会说 「不是内部或外部命令」 —— 这是新生最常撞的一堵墙(原因和解法见 坑 2)。

VS Code 不用手动加 —— 安装版会自动把自己的 bin 写进 PATH(见 §1.2)。

入口有两个,走哪个都行 —— 除了下面第 1 步的 sysdm.cpl, 也可以从「设置 → 系统 → 关于 → 高级系统设置」进:

图 1-43 57_path_settings.png
图 1-43 另一个入口:设置 → 系统 → 关于

操作步骤:

  1. 按 Win + R,输入 sysdm.cpl,回车 —— 打开「系统属性」;

  2. 切到 「高级」 选项卡 → 点右下角 「环境变量(N)…」:

    图 1-44 58_path_sysprop.png
    图 1-44 系统属性 →「高级」→ 点「环境变量(N)...」
  3. 在上半部分(写着「<你的用户名> 的用户变量」)里, 单击选中 Path → 点 「编辑(E)…」:

    图 1-45 59_path_envwin.png
    图 1-45 ① 在「用户变量」里选中 Path;② 点「编辑(E)...」
    图 1-46 60_path_row_selected.png
    图 1-46 Path 这一行选中后,「编辑」按钮才变亮
  4. 先看列表里有没有;缺了才点「新建(N)」补上 —— 本文要你手动加的只有两条: Ninja:C:\Tools\ninja、OpenOCD:<你的 OpenOCD 目录>\bin(教程示例 C:\Tools\openocd\bin), 输完回车确认;两条都加完就够了。 ⚠️ 列表里已经有同名/同目录的那条,就别再加(重复条目只会让后面排查更乱); 其余 7 个工具不用你加(安装器 / 安装时勾的选项已经加好了,见下面的表)。

    ① 先看当前列表(安装器已经自动加了几条;要加的那条不在里面,才点「新建(N)」):

    图 1-47 61_path_edit_rows.png
    图 1-47 「编辑环境变量」窗口(改前):点「新建(N)」加一条(列表里就是当前 Path 的每一条)

    ② 出现一条空白行,光标在里面:

    图 1-48 62_path_new_empty.png
    图 1-48 点完「新建」:出现一条空白行、光标在里面(输入前)

    ③ 把路径输进去(例:C:\Tools\ninja),回车确认:

    图 1-49 63_path_new_typed.png
    图 1-49 把路径输进去,例如 C:\Tools\ninja(输入后)

💡 9 个工具的 PATH:先查有没有,缺了才补

⚠️ 大部分安装器会自动加好,你不用管。真正要你手动加的只有 2 个: Ninja(§1.6)+ OpenOCD(§1.9) —— 都是绿色包,没有安装程序。 其余 7 个:先看环境变量 Path 列表里有没有对应目录 —— 有就别动,也别重复加。

工具 对应目录(先查有没有) 需要手动加吗
7-Zip (不需要) ❌ 靠右键菜单集成,不依赖 PATH
VS Code (自动) ❌ 安装器自动加
Python <你的 Python 安装目录> 和 …\Scripts(默认 %LOCALAPPDATA%\Programs\Python\Python312) ❌ 安装时勾了「Add python.exe to PATH」就自动加(§1.3 第 2 步)
Git <你的 Git 安装目录>\cmd(默认 C:\Program Files\Git\cmd) ❌ 安装器自动加
CMake <你的 CMake 安装目录>\bin(默认 C:\Program Files\CMake\bin) ❌ 安装时勾了「Add CMake to the PATH」就自动加(§1.5)
Ninja C:\Tools\ninja ✅ 必须手动加 —— 绿色包,没有安装程序
LLVM <你的 LLVM 安装目录>\bin(默认 C:\Program Files\LLVM\bin) ❌ 选了 for all users 就自动进系统 PATH —— 用户 Path 列表里没有它是正常的
ARM 工具链 <你的 ARM 工具链目录>\bin(教程示例 C:\Tools\arm-gnu-toolchain\bin) ❌ 完成页勾了「Add path to environment variable」就自动进用户 Path(§1.8)
OpenOCD <你的 OpenOCD 目录>\bin(教程示例 C:\Tools\openocd\bin) ✅ 必须手动加 —— 绿色包,没有安装程序

真正要你动手的只有 2 条:Ninja(§1.6)+ OpenOCD(§1.9) —— 都是绿色包,没有安装程序, PATH 只能自己加(加法见上面第 4 步)。其余 7 个都自动加好了(Python / CMake / VS Code 看安装时的勾选, Git 安装器自动加,LLVM 写进系统 PATH、ARM 写进用户 Path)。

「扫一眼有没有」具体怎么看 —— 在环境变量窗口里对着列表看有没有上面那一列的目录; 或者在终端里直接问:

where.exe git & where.exe cmake & where.exe clang & where.exe python & where.exe arm-none-eabi-gcc & where.exe openocd

有输出的就是已经在 PATH 里了 —— 不用管;哪一条报「找不到文件」就补哪一条。 ⚠️ 这一行是 cmd 的写法:PowerShell 里 where 是 Where-Object 的别名(敲了什么都不显示), 要用 where.exe(上面就是),或者把 & 拆成一行一条。

⚠️ 补的时候只加缺的那条,别照抄一堆 —— 加重复条目会让 Path 里出现两条一模一样的 ARM 条目,后面排查时很难看出哪条是哪来的。

📌 这张表就是 §0.2 说的那 10 件工具(Git 在里面;7-Zip 也在,只是它不靠 PATH)。 Ozone / J-Link 不在表里 —— 它是图形界面工具, 安装器自己搞定调用方式,不需要加 PATH(见第 5 章)。

  1. 一路点 「确定」 关掉所有窗口 —— 三层都要点(编辑框 → 环境变量 → 系统属性), 少点一层就不保存。加完之后列表里能看到新加的路径:

    图 1-50 64_path_all_entries.png
    图 1-50 新加的路径都在列表里了,接着一路点「确定」
  2. 把已经打开的终端和 VS Code 全部关掉重开 —— 这一步不能省,PATH 只在程序启动那一刻读一次(见坑 2)。

怎么确认加对了:重新打开一个终端,敲:

ninja --version

有版本号输出就对了。 还是「不是内部或外部命令」→ 回第 6 步, 确认 VS Code 已经从任务管理器里彻底退出了。

备选:命令行版 —— 一次加完,适合批量 / 远程部署

打开 PowerShell,整段粘贴回车(幂等,重复跑不会重复添加):

这段脚本会自己找每个工具装在哪(先 where,再去常见位置找可执行文件), 把「实际存在」的目录加进 PATH;找不到的会明确报出来,让你手动确认。 手动装的同学其实只加 Ninja / OpenOCD 就够了 —— 脚本是给批量 / 远程部署用的。

# 先探测每个工具装在哪,再把"实际存在"的目录加进 PATH(只写用户变量,不需要管理员)
$ErrorActionPreference = 'SilentlyContinue'

# 显示名 / 命令名 / 可执行文件名 / 候选目录(按顺序找)
$tools = @(
  @{ N='Git';     C='git';               E='git.exe';               D=@("$env:ProgramFiles\Git\cmd", "${env:ProgramFiles(x86)}\Git\cmd") },
  @{ N='CMake';   C='cmake';             E='cmake.exe';             D=@("$env:ProgramFiles\CMake\bin") },
  @{ N='LLVM';    C='clang';             E='clang.exe';             D=@("$env:ProgramFiles\LLVM\bin") },
  @{ N='Python';  C='python';            E='python.exe';            D=@("$env:LOCALAPPDATA\Programs\Python\Python312") },
  @{ N='VS Code'; C='code';              E='code.cmd';              D=@("$env:LOCALAPPDATA\Programs\Microsoft VS Code\bin") },
  @{ N='Ninja';   C='ninja';             E='ninja.exe';             D=@('C:\Tools\ninja') },
  @{ N='OpenOCD'; C='openocd';           E='openocd.exe';           D=@('C:\Tools\openocd\bin') },
  @{ N='ARM';     C='arm-none-eabi-gcc'; E='arm-none-eabi-gcc.exe'; D=@('C:\Tools\arm-gnu-toolchain\bin') }
)

# 读注册表里的现有 PATH(用户 + 系统)—— 即使当前终端是旧的,也能正确判断"有没有"
function Get-PathList($scope) {
  if ($scope -eq 'User') { $v = (Get-ItemProperty 'HKCU:\Environment' -Name Path).Path }
  else { $v = (Get-ItemProperty 'HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager\Environment' -Name Path).Path }
  if (-not $v) { return @() }
  return @($v -split ';' | Where-Object { $_.Trim() -ne '' } | ForEach-Object { $_.Trim().TrimEnd('\') })
}
$userList = Get-PathList 'User'
$all = $userList + (Get-PathList 'Machine')
$add = New-Object System.Collections.ArrayList

foreach ($t in $tools) {
  $found = $null
  foreach ($d in $t.D) { if (Test-Path (Join-Path $d $t.E)) { $found = $d.TrimEnd('\'); break } }
  if (-not $found) {
    if (Get-Command $t.C -ErrorAction SilentlyContinue) { "[{0,-7}] 已在 PATH(装在别处),无需处理" -f $t.N }
    else { "[{0,-7}] 没找到,请手动确认装在哪" -f $t.N }
    continue
  }
  if ($all -contains $found) { "[{0,-7}] 已在 PATH:{1}" -f $t.N, $found; continue }
  [void]$add.Add($found)
  "[{0,-7}] 已添加:{1}" -f $t.N, $found
  if ($t.N -eq 'Python') {                                  # Python 还要 Scripts
    $sc = Join-Path $found 'Scripts'
    if ((Test-Path $sc) -and ($all -notcontains $sc)) { [void]$add.Add($sc); "[Python ] 已添加:$sc" }
  }
}

if ($add.Count -eq 0) { "PATH 无需改动(探测到的目录都已经在 PATH 里)。" }
else {
  $merged = @($userList)
  foreach ($d in $add) { if ($merged -notcontains $d) { $merged += $d } }
  [Environment]::SetEnvironmentVariable('Path', ($merged -join ';'), 'User')
  "已写入用户变量 Path:新增 $($add.Count) 条。"
}

# 顺手把 OpenOCD 的脚本目录显式告诉它(§1.9 提过的兜底)
$ocd = @($add) + @($userList) | Where-Object { $_ -like '*openocd*' } | Select-Object -First 1
if ($ocd) {
  $root = if ($ocd -like '*\bin') { Split-Path $ocd -Parent } else { $ocd }
  [Environment]::SetEnvironmentVariable('OPENOCD_SCRIPTS', (Join-Path $root 'share\openocd\scripts'), 'User')
}

"请【完全关闭】终端 / VS Code 再重新打开,PATH 才会生效。"

✅ 这段脚本是幂等的:重复跑不会重复添加,也不会删掉已有的条目。 ✅ 找不到就不加:候选目录都 Test-Path 过 —— 不存在的位置绝不会被写进 PATH。 ✅ 只写用户变量(不需要管理员),也不用管装到哪个盘 —— 探测到哪儿就加哪儿。

💡 Python 如果装在别处(比如自己改过路径):不用手改脚本 —— 它的候选目录里已经带了 %LOCALAPPDATA%\Programs\Python\Python312;实在探测不到会明确报「没找到,请手动确认装在哪」。

1.11 全环境自检(装完必做)

🖱 最省事的做法:双击一个脚本,它替你全查完

下载 RowletBot-环境验证.zip(1,939 字节)—— 快递柜取件页:

  1. 打开 http://139.196.220.183:8080/#/?code=9LESD
  2. 页面上确认取件码是 9LESD(链接里已经带上了,一般不用手输)
  3. 点页面上的 「下载」 按钮

⏳ 取件页是长期有效的;万一打不开或提示鉴权失败, 重新打开取件页、重新输一次取件码再点下载即可。 (拿到 zip 后用 7-Zip 解压,得到 1 个 .bat。)

双击 5-check.bat(放哪都行,它不依赖仓库)。 约 20 秒后你会看到逐项判定 —— 10 件工具里,自检脚本只查 8 件 (不含 7-Zip 和 Ozone:一个只管解压、一个是调试工具,都不影响编译和烧录)。 这 8 件里只有 3 件有硬版本要求(openocd / arm-none-eabi-gcc / clang)—— 脚本对它们核对版本;其余 5 件只验"命令能不能跑、环境变量可不可用",不看版本:

  git                [OK] 环境变量可用
  python             [?] 取不到版本          ← 指向了微软商店的占位程序(见坑 3)
  ninja              [OK] 环境变量可用  [已确认在 PATH]
  openocd            [~] 版本不对,期望含 0.11.0  [已确认在 PATH]
  ...
  [有 3 项没通过] 往上翻看是哪几个…

判定符号:[OK] 通过 · [~] 版本不对 · [?] 取不到版本 · [X] 没装或不在 PATH。

📌 ninja / openocd 行尾多的 [已确认在 PATH]:脚本对这两件额外验了一步 —— 拿 where 找到的绝对路径再跑一次 --version,跑得通才算 PATH 真的可用 (上面 位置: 那行打印的就是它实际用的那个文件)。

📌 出现 [?] 时别急着重装:先用下面第 1/2 组的命令手工复核一遍 —— 手工能出结果,就说明环境没问题,是脚本没抓到(例如 OpenOCD 把版本打到 stderr,不是没装); 手工也出不来,才回对应小节重装或修 PATH。

📌 [~] 版本不对 怎么读:现在只有那 3 件(openocd / arm-none-eabi-gcc / clang)可能报它 —— 它们正是 §1.0 第 2 条里既靠 PATH、又有硬版本红线的那三个。 看到 [~] = 真装错版本了,按 §1.0 第 2 条回对应小节换版本 (脚本提示的「版本红线见教程 1.0 第 2 条」说的就是这件事)。 其余工具(git / python / cmake / ninja / code)根本不会再报 [~] —— 它们只报 [OK] 环境变量可用 / [?] / [X],所以不用再纠结"我装的版本是不是和教程写的不一样"。

📌 Ozone 的版本为什么不在这儿查:它不靠 PATH(本来就不在这 8 件里),脚本抓不到它 —— Ozone 3.24(32 位)+ J-Link 7.22b 这条红线只能手动核对,见 §5.1。

📌 [X] 没装 / 不在 PATH 里的 git 也可以忽略: Git 是可选件(§1.4 / §2.4 —— 压缩包路线不需要它),没装时就是这一项报 [X], 最后那句「[有 N 项没通过]」里把 git 减掉再看。

它还会把结果写成 env-check-report.txt —— 在群里问问题时把这个文件的内容贴上去,别人一眼就能看出你哪儿不对, 不用来回问三遍。

全部通过的输出长这样 —— 10 件工具里它只查 8 件(不含 7-Zip 和 Ozone), 这 8 件逐项 [OK]:openocd / arm-none-eabi-gcc / clang 这三件是 [OK] 版本正确, 其余 5 件是 [OK] 环境变量可用,后面各自跟一行 位置:(ninja / openocd 还多一个 [已确认在 PATH]):

图 1-51 65_check_all_ok.png
图 1-51 全部通过:自检的 8 件工具逐项 [OK](3 件 [OK] 版本正确 + 5 件 [OK] 环境变量可用)+ 各自的 位置: 路径,最后还有 tkinter [OK] 版本 8.6 和 [全部通过]

下面是它查的内容 —— 想手动核对时展开:

展开看:四组手动自检命令(版本 / where / 特殊检查 / 记结果)

新开一个终端(建议直接用 cmd;PowerShell 里要把下面的 where 写成 where.exe,见 §1.0 第 3 条),一条条敲:

第 1 组:版本命令

git --version
python --version
cmake --version
ninja --version
clang --version
arm-none-eabi-gcc --version
openocd --version
命令 期望输出的第一行 没输出说明
git --version git version 2.x Git 没装 / 没进 PATH
(Git 是可选件,没装就跳过这条)
python --version Python 3.12.x 见坑 3(商店占位程序)
cmake --version cmake version 3.x(官网已出 4.x —— 有版本号就算对) CMake 没装 / 路径多套了一层
ninja --version 有版本号输出(形如 1.12.1) Ninja 没装 / 没进 PATH
clang --version clang version 18.1.x(红线) LLVM 没装 / 没进 PATH
arm-none-eabi-gcc --version arm-none-eabi-gcc (Arm GNU Toolchain 13.3.Rel1 ...) 13.3.1 ... ARM 工具链没装
openocd --version Open On-Chip Debugger 0.11.0 ... sysprogs/openocd 装错版本了,见 §1.9

第 2 组:where 命令(更硬的证据)

where git
where python
where cmake
where ninja
where clang
where clangd
where arm-none-eabi-gcc
where openocd
where code

每一条的判据只有两个(路径长什么样不重要):

# 判据
① 有输出 有输出 = 这个工具在 PATH 里;报 INFO: Could not find files = 没进 PATH
② 指向真实安装目录 第一行不能是 ...\WindowsApps\...(那是微软商店的占位程序,见坑 3);where python 第二行是 WindowsApps 属于正常,不用管

示例(你的路径很可能和这里不一样,那是正常的):

C:\Program Files\Git\cmd\git.exe
%LOCALAPPDATA%\Programs\Python\Python312\python.exe       ← 不能是 ...\WindowsApps\python.exe
C:\Program Files\CMake\bin\cmake.exe
C:\Tools\ninja\ninja.exe
C:\Program Files\LLVM\bin\clang.exe
C:\Program Files\LLVM\bin\clangd.exe
C:\Tools\arm-gnu-toolchain\bin\arm-none-eabi-gcc.exe
C:\Tools\openocd\bin\openocd.exe
...\Microsoft VS Code\bin\code.cmd

💡 关于 where code 的一行小字:它的输出可能有不止一行,而且第一行常常是 没有扩展名的 code(...\Microsoft VS Code\bin\code),第二行才是 code.cmd —— 这是正常的,不算装坏。判据还是上面那两条:有输出、不是 ...\WindowsApps\...; 另外不应该出现 Code.exe(出现就说明 PATH 指到了 GUI 版,见坑 7)。

📌 装在哪都行 —— 关键只有一个:它在 PATH 里

📌 装在哪都行 —— 关键只有一个:它在 PATH 里

上面那串路径是本文示例机器的,不是标准答案。把十件工具 全部装到 D 盘(D:\Tools\、D:\ProgramFiles\、D:\RowletBot) 一样能编译通过(build all all 11 个目标成功)。

所以别人给的路径不用照抄,你只要确认:

  • 你自己的安装目录在 PATH 里(where 有输出);
  • 版本对(第 1 组那张表)。

换句话说:where 输出的路径和本文不一样 → 完全正常,不用重装。 只有「没输出」或「指向 WindowsApps」才是问题。

第 3 组:三个特殊检查

python -c "import tkinter; print(tkinter.TkVersion)"

→ 8.6

clang --target=arm-none-eabi -c -x c nul -o nul.o

→ 没有 unknown target triple 就对了

openocd -c "echo OK=[find target/stm32h7x.cfg]" -c shutdown

→ 能打印出完整路径(验证 §1.9 的布局)

第 4 组:把结果记下来

把上面 7 条版本号抄在纸上或存个文本 —— 以后在群里问问题,第一句就贴这个, 别人一眼就能看出你环境对不对。


第 2 章 拿代码(学习阶段用压缩包)

📖 本章导读

  • 做什么:把学长给的压缩包解开,放到一个不会出问题的路径
  • 需要:框架压缩包、约 5 GB 空闲磁盘
  • 做完的标志:解压出来的 project.py / src\ / hw\ / build_script.bat 都在(§2.5)

💡 学习阶段不用 GitHub、不用 git clone —— 压缩包解压就能用,子模块已经打包在内。

2.1 学习阶段的框架来源:压缩包

战队对学习阶段的新生不下发 git 权限,统一用压缩包发放框架。

也就是说:你不需要 GitHub 账号,也不需要 git clone。 学长会给你一个打包好的压缩包,解压就能编译。

这样做有几个好处:

好处 说明
不用等权限 私有仓库要先把你加进组织才能 clone,压缩包直接给
不会误操作 新生不会一不小心 push 坏分支、或者把仓库搞乱
拿到就是完整的 压缩包里已经包含了那 5 个 vendored 子模块(见 §2.3),不用再拉
离线可用 拷 U 盘就能传,不依赖 GitHub 网络

常见的包名(具体以学长给你的为准):

RowletBot-<日期>.tar.gz
RowletBot-<日期>.zip

📌 什么时候才需要 Git? 见 §2.4 —— 学习阶段不用, 等你要参与开发、提交代码的时候再配。


2.2 解包(照做)

第一步:先决定放哪

  • ✅ 好:%USERPROFILE%\Desktop\RowletBot、D:\RowletBot
  • ❌ 坏:C:\Users\张三\桌面\我的代码\RowletBot(中文)、 C:\Program Files\RowletBot(空格 + 权限问题)

⚠️ 铁律 1:路径里不能有中文和空格,否则后面 CMake / Ninja 会报一堆看不懂的错。

第二步:用 7-Zip 解包

先新建一个文件夹放代码 —— 在桌面空白处 右键 → 新建 → 文件夹, 名字改成 RowletBot。

然后解压(全部走 7-Zip,右键就行):

你的压缩包是 用 7-Zip 怎么做
.zip 右键 → 7-Zip →「解压到当前位置」,解出来的东西就铺在当前文件夹
.tar.gz 解两次:先「解压到当前位置」得到一个 .tar → 再对着这个 .tar 右键 → 7-Zip →「解压到当前位置」,才看到代码目录
想指定解到哪 右键 → 7-Zip →「解压文件...」,目标填你刚新建的 RowletBot 文件夹

⚠️ 对话框里如果有一个「解压到 "xxx"」的子文件夹勾(默认是勾着的),把它取消掉 —— 否则会多套一层目录。 拿不准就看解压结果:project.py(或 ninja.exe)直接躺在目标文件夹第一层就对了。

⚠️ 解压完一定要看一眼文件夹里面。 有些包解开后会多套一层同名目录,变成 RowletBot\RowletBot\project.py。 判断标准:project.py 必须直接躺在 RowletBot 文件夹的第一层。 如果多了一层,进去把里层的东西全选剪切,粘贴到外层。

备选:命令行版
cd /d "%USERPROFILE%\Desktop"
mkdir RowletBot
tar -xzf .\RowletBot-<日期>.tar.gz -C .\RowletBot

.zip 用 Expand-Archive -Path .\RowletBot-<日期>.zip -DestinationPath .\RowletBot。

第三步:确认解压对了(在资源管理器里看)

打开 RowletBot 文件夹,应该直接看到:

应该看到 是什么
project.py 整个工程的入口 —— 它在第一层就对了
src 源代码(robot / module / component / device / system)
hw 板级支持包(hw\bsp\mc02、hw\bsp\rm-c …)
lib 第三方库
utils 构建辅助脚本
user 留给你自己写代码的地方

💡 看不到 .vscode 文件夹? 那是正常的 —— 以 . 开头的文件夹默认隐藏。 在资源管理器里点 「查看」→ 勾上「隐藏的项目」 就能看到。

备选:命令行版
dir project.py
dir src\robot
dir hw\bsp
dir lib
dir utils

src\robot 里是一堆 robot 目录,hw\bsp 里是板子目录 (mc02、rm-c、f334_supercap、f042_can、Webots)。


2.3 压缩包里已经包含子模块,不用跑 git submodule

lib\ 和 hw\mcu\st\ 下面有些目录不属于本仓库,而是从别的 GitHub 仓库「挂」进来的, 这种机制叫 git submodule(子模块)。用 git clone 拉的话它们是空的,必须再跑一次 git submodule update --init。

✅ 但你用的是压缩包 —— 打包的时候已经把这 5 个目录的真实文件都放进去了, 所以这一步完全不用做。


2.4 关于 Git(学习阶段用不到,但不是没用)

学习阶段你完全可以不装 Git —— 压缩包解压就能编译、能烧录、能改代码。

那什么时候需要它?

场景 需不需要 Git
跟着教程编译 / 烧录 / 改着玩 ❌ 不需要
自己改代码想能回退("昨天还能跑") ✅ 建议装,git init 一下就有一个本地仓库
要参与开发、提交代码、拉最新分支 ✅ 需要,而且要 GitHub 权限
展开看:Git 的三种用法(装它 / 本地存档 / 接 GitHub)

想装 Git 的话

安装步骤见 §1.4(下载地址、安装时要注意的 3 个选项、静默安装参数、验证命令都在那里)。

装完回来跑一次验证:

git --version
where git

期望:git version 2.x / 你装的那个 …\Git\cmd\git.exe(默认 C:\Program Files\Git\cmd\git.exe)

只想给自己的改动做版本管理(不需要 GitHub)

在仓库根目录跑:

git init
git config --global user.name "你的名字"
git config --global user.email "你的邮箱@example.com"
git config --global core.autocrlf false
git add -A
git commit -m "导入框架压缩包"

之后改完代码 git diff 看改了什么,git checkout -- <文件> 撤销。 这就是"游戏存档"的用法,完全在本地,不碰服务器。

⚠️ core.autocrlf false 一定要设:本仓库的 .config 文件如果是 CRLF, 旧版 project.py 会直接 IndexError 崩溃。

以后要参与开发:需要 GitHub 权限

本仓库是私有的。没有权限时 git clone 会有两种表现:

表现 意思
remote: Repository not found. 没权限(GitHub 对私有仓库统一回这个)
浏览器打开是 404 同上

做法:把 GitHub 用户名发给学长/队长,让他把你加进组织并给仓库权限。

登录方式二选一:

方式 优点 缺点
SSH key(推荐) 配一次,之后永远不用输密码 要生成密钥、往 GitHub 粘贴一次
Personal Access Token (PAT) 不用生成密钥 有有效期,过期要重配

方式 A:SSH key

ssh-keygen -t ed25519 -C "你的邮箱@example.com"
  • Enter file in which to save the key → 直接回车(默认路径)
  • Enter passphrase → 直接回车两次(不设密码)
type %USERPROFILE%\.ssh\id_ed25519.pub

整行复制打印出来的文本(以 ssh-ed25519 开头)。

浏览器打开 https://github.com/settings/keys → New SSH key → Title 填 我的 Windows 开发机 → Key type 选 Authentication Key → 粘贴 → Add SSH key。

验证:

ssh -T [email protected]

期望(第一次会问 Are you sure you want to continue connecting? → 输 yes):

Hi <你的用户名>! You've successfully authenticated, but GitHub does not provide shell access.

⚠️ 如果回 Permission denied (publickey). —— 这句话的意思是 「这把钥匙 GitHub 不认」,不是网络问题,也不是 Git 装坏了。 检查公钥有没有真的加到你自己的 GitHub 账号上。 📌 如果你选的是方式 B(PAT),看到这条说明 clone 时用的是 SSH 地址([email protected]:)—— 换成本节下面方式 B 那条 HTTPS 地址即可。

方式 B:Personal Access Token

https://github.com/settings/tokens → Generate new token (classic) → 勾 repo 整个大项 → 设置有效期 → 生成 → 立刻复制那串 token(页面关掉就再也看不到了)。

clone 时弹用户名密码:用户名填 GitHub 用户名,密码栏粘贴 token(不是账号密码!)。

clone 命令(地址跟着你选的登录方式走,两条不要混):

cd /d "%USERPROFILE%\Desktop"

REM 方式 A(SSH key)—— 地址以 [email protected]: 开头
git clone -b dev [email protected]:Birdiebot2025/RowletBot.git RowletBot

REM 方式 B(PAT)—— 地址是 https:// ,会弹凭据窗口
git clone -b dev https://github.com/Birdiebot2025/RowletBot.git RowletBot

⚠️ 选方式 B 却敲了 [email protected]: 那条,不会弹用户名密码,而是直接 Permission denied (publickey).(等于被引去修你已经绕开的 SSH key)。 方式 B 就用上面第二条 HTTPS 地址:用户名填 GitHub 用户名,密码栏粘 token。 🅳 分支差异:-b dev 换成 -b 26Sort 就是新赛季分支。

cd RowletBot
git submodule update --init      REM ⚠️ 走 git 路线才需要这一步

第 3 章 编第一个固件:改一行 → 看变化

📖 本章导读

  • 做什么:编出第一个固件,看到 [N/N] + 内存占用表、没有红色 failed:(§3.4)
  • 需要:第 1、2 章都走完了
  • 做完的标志:dir build\xrobot.bin 有文件

📌 本章只要三步:§3.2 用 python ./project.py config 选目标 → §3.4 在 VS Code 里跑 build 任务 → §3.5 看产物。

🎯 这一章的目标

让板子上的 LED 闪起来,然后改一个数字让它闪得不一样, 重新烧进去,亲眼看到它变了。

本文用的目标:rm-c + ex1_led(§3.2 里选它)—— 只闪灯、不驱动任何电机,所以直接烧就行,不用架车、也不用拔电机线。 (只有换成会驱动电机的目标,比如 26-Omni_Infantry,才需要先把车架起来。)

3.1 先认识一个词:目标(target)

一个目标 = 一块板子 + 一个 robot 程序。

  • rm-c 是板子;ex1_led 是跑在它上面的 robot 程序(本文全程用它当例子)。
  • 同一个 robot 名字在不同板子上可能是两份不同的配置。
  • 所以编译前必须先确定「这块板子 + 这个 robot」 —— 在 §3.2 的配置窗口里选一次(Save),之后的重编就按这个组合走(换目标 = 回配置窗口改 + Save,见 §3.4)。

3.2 打开配置窗口,选板子和 robot

图 3-1 13_cfg_board.png
图 3-1 配置窗口:上面「开发板」里选中 board-rm-c,下面「机器人」里选中 robot-ex1_led(两个菜单各选一个;再往下的「系统 / 组件 / 设备 / 模块」本文不动)

这是全程唯一的"配置"动作 —— 选完之后,编译和烧录都跟着这个选择走。

  1. 在 VS Code 集成终端里跑(确认目录是仓库根,提示符末尾是 \RowletBot>):

    python ./project.py config
    

    → 弹出 Main menu 配置窗口。

  2. 展开「开发板 (board-…)」 → 点 board-rm-c 那行最左边的小圆圈(见图 3-1)。

  3. 展开「机器人 (robot-…)」 → 点 robot-ex1_led 那行最左边的小圆圈(见图 3-1)

    ⚠️ 点名字只会把那一行变蓝(高亮),不算选中 —— 必须点最左边那个小圆圈。 不确定有没有点上:看窗口底部的 Choice symbols: 几行,带 (selected) 的才生效。

  4. 点 Save → 关掉窗口(本工具没有 Exit 按钮,点右上角 X 或 Alt + F4)。 config_cmake() 要等窗口关掉之后才跑,build\build.ninja 这时才生成 —— 黑窗口刷完出现 Build files have been written to 就说明配置好了。

📌 树上只有「开发板」和「机器人」必须各选一个(决定编"哪块板子的哪个 robot"); 系统 / 组件 / 设备 / 模块 是更细的开关,目标配置里已经配好了,本文流程不用动。

⚠️ 第一次必须走这一步:它顺带把 CMake 配置好,跳过它直接编译会报 ninja: error: loading 'build.ninja'(见坑 20)。

💡 本文全程用 rm-c + ex1_led —— ex1_led 只闪灯、不驱动电机,直接烧就行、 不用架车也不用拔电机线;换成会驱动电机的目标(如 26-Omni_Infantry)才要架车或拔电机线再烧。 ⚠️ 但窗口里有什么才是准的(见坑 21)—— 别背本文的例子。

3.3 打开文件、找到要改的那一行

用 VS Code 打开整个仓库文件夹(File → Open Folder,不是打开单个文件), 然后打开 src\robot\ex1_led\robot.cpp —— 这是这个 robot 的主程序。

要找的是「改一个数字就能看出差别」的地方,最常见的是这两类:

  • 延时:形如 System::Delay(500)、Thread::Sleep(1000) 里的毫秒数;
  • 速度 / 系数:形如 SetSpeed(...)、* 0.5、PID 的那一组参数。

用 Ctrl + F 搜 Delay 或 Speed,挑一处改一个数字(比如把 500 改成 1000), 按 Ctrl + S 保存。

💡 改完看不出差别? 换一处再试 —— 不同目标里「看得出差别」的参数不一样。 只要能编过、能烧进去,这一章的目的(走通流程)就已经达到了。

3.4 编译(第一次)

编译 = 先在 §3.2 的配置窗口里定好目标,再跑 VS Code 的 build 任务 —— 在 VS Code 里打开仓库,跑任务 build(定义在 .vscode\tasks.json):

  • Ctrl + Shift + P → 输入 Run Task → 选 build ← 最稳,一定可用;
  • 菜单 终端 → 运行任务… → 选 build(图 3-2、图 3-3);
  • Ctrl + Shift + B —— ⚠️ 本仓库没设成"默认生成任务",按下去可能先弹任务列表,选 build 即可。
图 3-2 17_ch3_run_task_menu.png
图 3-2 菜单入口:终端 → 运行任务…(图中 ① 就是它)
图 3-3 18_ch3_task_list.png
图 3-3 在列表里选 build(①)—— 「运行任务…」和 Ctrl+Shift+B 都会落到这一步
图 3-4 19_ch3_build_done.png
图 3-4 编译成功的输出(rm-c + ex1_led):收尾的 [279/279](objcopy 那一步)+ 内存占用表。数字随 robot / 板子变 —— 能看到这张表就说明编好了

成功的样子:最后一行是 [N/N](objcopy 那两步:xrobot.bin / .hex),紧跟着一张内存占用表 (Memory region / Used Size / Region Size / %age Used —— 图 3-4),全程没有红色的 failed:。

📌 数字对不上是正常的 —— 只有两件事要记住

① Region Size 是这块板的上限(来自链接脚本):rm-c(本文用它)→ 768 KB、mc02 → 1024 KB。 ② 要盯的是 FLASH 那一行的百分比 —— 以后固件装不下时它就是线索;Used Size 只是示例,你的数字一定不一样。 💡 rm-c 会多出一行 CCMRAM(STM32F4 特有,显示 100% 是固定输出,不用管);mc02 没有这一行。

失败:结尾是红色的 failed: ninja exited with 1. → 别慌,去第 7 章按报错关键字查。

⚠️ 顺序:先 §3.2 配置窗口,再跑 build。反过来会报 ninja: error: loading 'build.ninja': The system cannot find the file specified.(见坑 20)。

💡 换板子 / 换 robot:回 §3.2 改一次 + Save,再跑 build —— 编出来的就是新目标。 只想重编一次(改完代码):双击 build_script.bat —— 快、沿用上次目标,但只 ninja、不配置也不归档。 ⚠️ 别用 build_script.bat <板> <目标> 这种写法:本文这版脚本忽略参数(坑 20)。

📌 想编 Release 版(一般用不到,上板一律用默认 Debug):python project.py build-release rm-c ex1_led。

3.5 产物在哪:build\ 里的那五个文件

图 3-5 26_firmware_dir.png
图 3-5 build\ 目录:产物就是那五个文件(xrobot.bin / .elf / .hex / .map + compile_commands.json)。其余是 CMake / Ninja 的中间文件,不用管

编译成功后,产物都在 build\ 里(正常流程):

文件 是什么 用在哪
build\xrobot.elf 带调试信息的可执行文件 VS Code / Ozone 在线调试
build\xrobot.hex Intel HEX 文本格式 J-Link / JFlash 烧录、发给别人
build\xrobot.bin 纯二进制镜像 ✅ OpenOCD 烧录用这个
build\xrobot.map 内存映射表 Flash 装不下时查是谁占的
build\compile_commands.json 每条编译命令 clangd 跳转、CodeChecker

第 4 章 烧录

📖 本章导读

  • 做什么:把固件烧进板子,并确认它真的在跑
  • 需要:调试器 + 4 根烧录线 + 给板子供电
  • 做完的标志:看到 wrote N bytes ... + shutdown command invoked(§4.5)

⚠️ 本章有一条"能救你的车"的规矩:烧错目标不会报错,只会安静地烧进去。 所以顺序是 接线 → 确认调试器 → 烧录 → 看现象,一步都别省。

📌 本文只保留 §1.11 的环境自检脚本(5-check.bat),不再附带探测 / 备份的助手脚本 —— 需要探测芯片或备份板子里的固件时用命令行,两条命令都在第 7 章: 探测见坑 23,备份 / 还原见坑 26。

⚠️ 烧错目标不会报错

build\xrobot.bin 是共享路径、0x08000000 对所有 STM32 都成立 —— 所以烧错目标只会安静地写进一份错误的固件。 把驱动电机的固件烧到真车上可能直接飞车,所以下面几步一步都别省。

4.1 你手上可能是哪一种下载器

类型 特征 本文适用
DAP-Link / CMSIS-DAP(含 ATK 无线调试器) USB 插上出现 HID 设备 + 一个串口 ✅ 本文用的就是 ATK CMSIS-DAP
J-Link 出现 JLink 设备 命令里的 -f 换成 jlink 的 cfg
ST-Link 出现 STLink 设备 用 st-link 的 cfg

4.2 接线(4 根线,一根都不能错)

线 必须接吗 说明
GND ✅ 必接 共地
SWDIO ✅ 必接 数据
SWCLK ✅ 必接 时钟
3V3 ⚠️ 只在板子自己没供电时接 板子和调试器都供电时不要接,会打架

接反/接错通常表现为「设备管理器里能看到调试器,但 openocd 探测不到芯片」。

⚠️ 烧录之前:先让轮子悬空

本文用的 ex1_led 只闪灯(不驱动电机)—— 不会动。换成会驱动电机的目标时,烧进去之后程序一跑,轮子就可能转。 第一次烧录前做一件事(二选一):

  • 把车架起来,让四个轮子离地空转;
  • 或者拔掉电机线(只烧程序、不接电机)。

这样即使程序写错、上电就全速转,车也不会冲出去撞坏东西。

4.3 确认电脑认出了调试器

把调试器插进 USB 口,等 2~3 秒。

设备管理器里看:应该出现 3 个相关设备,分在 3 个节点下 —— 所以这三个节点都要展开:「端口 (COM 和 LPT)」、「通用串行总线控制器」、「人机接口设备」 (有的系统把最后一个显示成「人体学输入设备」,是同一个节点)。

设备名 在哪个节点下 表示什么
USB Composite Device 通用串行总线控制器 调试器整体
USB 串行设备 (COMx) 端口 (COM 和 LPT) 调试器自带的串口通道(COM 号不一定是几)
HID-compliant vendor-defined device 人机接口设备 ✅ CMSIS-DAP 调试通道 —— openocd 用的就是它

🔎 第三个(「人机接口设备」里的那个)是关键 —— 少了它,openocd 必然连不上。 有黄色感叹号:右键 → 卸载设备 → 拔插一次,让 Windows 重装驱动。 认不出是哪个设备时,点开设备 →「详细信息」→「硬件 ID」,看有没有 VID_04D8&PID_00DF。

烧录前必须关掉所有可能占用调试器的程序:VS Code 的调试会话、其它 openocd 窗口、Keil / IAR。


4.4 烧录(VS Code 运行任务 download_dap)

这是唯一会写板子的一步。

在 VS Code 里运行任务 download_dap(入口和 §3.4 跑 build 任务完全一样):

  • 菜单 终端 → 运行任务… → 选 download_dap。

它干的事就一行 —— 先编译,再用 openocd 烧:

build_script.bat && openocd -f toolchain/openocd_dap.cfg -c init -c halt -c "reset halt; wait_halt;flash write_image erase build/xrobot.bin 0x08000000" -c reset -c shutdown

拆开看:

这一段 做什么
build_script.bat 先重编(= 只跑一遍 ninja,§3.4)
openocd -f toolchain/openocd_dap.cfg 用 toolchain\ 那份共享配置连调试器
flash write_image erase build/xrobot.bin 0x08000000 把固件写到 Flash 起始地址
-c reset 烧完自动复位,板子立刻开始跑新固件
图 4-1 28_flash_task_done.png
图 4-1 任务跑完:wrote 340096 bytes … + shutdown command invoked —— 烧进去了,板子已自动复位

⚠️ 它没有确认环节 —— 任务一跑就开始烧,不会问你 y。 所以烧之前先探一下板子:按坑 23 那条命令确认探到的芯片(Device: 那行)就是你手上这块板。

📌 toolchain\openocd_dap.cfg 是"最后一次配置的那块板"的共享副本(§3.2 配置时拷过来的)—— 单块板子开发时它就是对的(你刚在 §3.2 配过);换过板子、又不确定它指向哪颗芯片时, 先 type toolchain\openocd_dap.cfg 看最后一行 target,或按坑 23 先探一次。

⚠️ 唯一要留意的:build_script.bat 那一步失败时脚本不一定停(老版返回码恒 0,见坑 20) —— 编译输出里有红色 failed: 就别往下烧。

烧录成功的输出(openocd 写完 + 脚本结尾):

wrote 338016 bytes from file build/xrobot.bin in 7.540754s (43.775 KiB/s)
shutdown command invoked

  烧录完成,板子已复位。

4.5 烧录成功的样子 & 板子上的现象

成功输出(关键几行):

wrote 338016 bytes from file build/xrobot.bin in 7.540754s (43.775 KiB/s)
shutdown command invoked

退出码 0。

板子上的现象:

现象 说明
板上的 LED 开始闪(约 0.5 秒一次) 本文用的 ex1_led 就是闪灯目标 ✅ 不驱动电机,直接烧就行
板载 LED 闪烁 / 蜂鸣器响 你选的是灯 / 响类目标(§3.2 里的"可选替换")✅
板子毫无反应 见坑 23
电机狂转、不受控 ⚠️ 立刻断电,回 §3.2 重新选目标 / 检查代码

⚠️ 会驱动发射机构、拨弹轮的 robot(名字带 Hero / Infantry / shoot 的), 测试前务必确认机构周围无人、无弹。

最后一步,也是最重要的一步:

改一行代码 → build_script.bat → 重新烧录 → 现象变了 🎉


做完第 1~4 章再回来装这一章 —— 调试、断点、看变量、变量曲线都靠它。 (基础编译 / 烧录环境不依赖它,所以它排在第 4 章「烧录」之后。)

软件 版本 为什么是它
Ozone 3.24 · 32 位 只有 32 位的 Ozone 3.24 支持 DAP-Link(含正点原子 ATK 无线调试器)
J-Link 工具箱 7.22b 提供 Ozone 需要的驱动、GDB 等调试工具;和 Ozone 3.24 是配套的一对

🚫 不要装最新版 Ozone。 新版 Ozone(V3.40 以后)走的是「OpenOCD GDB server 中转」的路子, 和这里「Ozone 直连探针」完全不是一种用法:配置界面、连接方式、能用的功能都不一样, 换成新版反而更麻烦(新版走 GDB server 中转,曲线功能也用不了)。

装 3.24 32 位就对了。

下载 RowletBot-Ozone+JLink-必装包.zip —— 87,190,628 字节(83.2 MB) —— 快递柜取件页:

  1. 打开 http://139.196.220.183:8080/#/?code=0MAW5
  2. 页面上确认取件码是 0MAW5(链接里已经带上了,一般不用手输)
  3. 点页面上的 「下载」 按钮

⏳ 取件页是长期有效的;万一打不开或提示鉴权失败, 重新打开取件页、重新输一次取件码再点下载即可。 这一步要用的东西全在这一个包里。

包里 4 个文件(字节数可用来核对下载是否完整):

文件 字节数 用途
Ozone_Windows_V324_x86.exe 19,325,384 Ozone 3.24(32 位)安装包
JLink_Windows_V722b.exe 53,935,680 J-Link 7.22b 安装包
JLinkARM.dll 18,103,072 必做:装完上面两个之后覆盖进去(见下面第 ③ 步)
Ozone_doc.pdf 3,924,927 Ozone 官方手册,需要时自己翻

💡 这一步只用这一个包就够了 —— 包里那份 JLinkARM.dll 是改过的,官网下不到。

① 安装 Ozone

  1. 双击 Ozone_Windows_V324_x86.exe —— 欢迎页点 Next:

    图 5-1 51_ozone_welcome.png
    图 5-1 欢迎页 → Next
  2. 许可页点 I Agree:

    图 5-2 52_ozone_license.png
    图 5-2 许可页:点 I Agree
  3. ⚠️ 这一步注意选择 install a new instance(安装一个新的实例); 组件 / 目标目录 / 用户范围都保持默认即可:

  4. 后续一路确认,看到完成页就结束:

    图 5-3 54_ozone_done.png
    图 5-3 完成页:Completing Ozone V3.24 Setup

② 安装 J-Link

  1. 双击 JLink_Windows_V722b.exe;
  2. ⚠️ Update DLL in other applications 默认是勾着的,要手动取消勾选 —— 否则 J-Link 会把 Ozone 里那套老的驱动和启动项替换掉;
  3. choose destination 和 Ozone 一样,选 install a new instance;
  4. 如果已经装过相同版本的 J-Link,先卸载;版本相同不用管,直接新装一个。

默认安装位置(32 位程序,在 Program Files (x86) 下):

C:\Program Files (x86)\SEGGER\Ozone V3.24\Ozone.exe
C:\Program Files (x86)\SEGGER\JLink_V722b\

⚠️ 目录名里带版本号(因为上面选的是 install a new instance)—— 以你机器上实际的名字为准。

③ 必做:替换 JLinkARM.dll

✅ 把包里的 JLinkARM.dll 覆盖到两个安装目录

包里那份是改过的,用来绕过 SEGGER 对克隆调试器的检测 —— 不覆盖的话,J-Link OB / 克隆版 J-Link / 部分 DAP-Link 会反复弹 clone version 之类的提示,甚至连不上。

怎么找这两个目录:打开 C:\Program Files (x86)\SEGGER\ —— 里面就是两个文件夹, 一个是 J-Link、一个是 Ozone。⚠️ 目录名带版本号(因为选的是 install a new instance):

C:\Program Files (x86)\SEGGER\JLink_V722b\      ← J-Link 安装目录
C:\Program Files (x86)\SEGGER\Ozone V3.24\      ← Ozone 安装目录

以你机器上实际的名字为准(版本号不同,名字就不同)。 每个文件夹里都有一个 JLinkARM.dll(约 18 MB)—— 两个都要覆盖。

怎么做:把包里那个 JLinkARM.dll 复制一份 → 分别进上面两个目录 → 粘贴 → 提示「替换目标中的文件?」时,点 「替换目标中的文件」。 ⚠️ 往 C:\Program Files 下复制会弹权限提示(「你需要提供管理员权限才能复制到此文件夹」)—— 点 「继续」 即可。 (想稳妥点:覆盖前把原文件改名成 JLinkARM.dll.bak 备份,要还原时改回来。)

⚠️ 以后如果又装了别的版本的 J-Link,千万不要勾 Update DLL in other applications —— 那会把这份 DLL 覆盖回去,等于白替换(要重新覆盖一次)。

验证:双击 Ozone 图标,能看到 SEGGER 的启动界面(New Project Wizard)就对了。

第一次启动会先弹一个 J-Link 使用条款,点 Accept 才能进去:

图 5-4 55_ozone_jlink_terms.png
图 5-4 首次启动先弹 J-Link 使用条款:点 Accept

进去之后就是 Ozone 主界面(New Project 向导):

图 5-5 56_ozone_main.png
图 5-5 Ozone 主界面:New Project 向导

也可以看一眼版本号(应该显示 3.24 / FileVersion 3.2.4.0):

(Get-Item 'C:\Program Files (x86)\SEGGER\Ozone V3.24\Ozone.exe').VersionInfo.FileVersion

5.4 ⚠️ 两个已知的启动失败

现象 原因 处理
双击立刻退出,错误码 0xC0000135 STATUS_DLL_NOT_FOUND,缺 VC++ 运行库 装 vc_redist.x86.exe。Ozone 3.24 是 32 位程序,装 x86 包
第一次启动弹许可确认框 SEGGER 非商业用途的官方确认框,不是缺授权 人在自己电脑前点一次"接受",该选择会持久化

📌 注意位数:如果你装的是新版 64 位 Ozone,缺运行库时要装的是 vc_redist.x64.exe。3.24 是 32 位,装 x86 那个。


第 6 章 VS Code 配置

📖 本章导读

  • 做什么:让 VS Code 能跳转定义、能在线调试
  • 需要:§1.2 已装好 VS Code 和那 6 个插件;已成功编译过一次
  • 做完的标志:在 .cpp 里按 F12 能跳到定义

💡 clangd 和 cpptools 会抢跳转 —— 本章 §6.1 说了怎么二选一。

6.1 插件

§1.2 已经装过。检查:

code --list-extensions

应该包含:ms-vscode.cpptools、ms-vscode.cmake-tools、 marus25.cortex-debug、dan-c-underwood.arm、 llvm-vs-code-extensions.vscode-clangd、ms-ceintl.vscode-language-pack-zh-hans。

💡 clangd 和 cpptools 会打架:两个都想做代码跳转。 建议只留一个:要么禁用 ms-vscode.cpptools 的 IntelliSense,要么禁用 clangd。 本框架工程自带 .clangd 配置,推荐用 clangd。

6.2 用 File → Open Folder 打开仓库

不是打开单个文件 —— 否则 .clangd、.vscode 里的配置都不生效,跳转全废。

6.3 代码跳转(F12)

前提:build\compile_commands.json 存在(第一次完整编译之后就有了)。

dir build\compile_commands.json
where clangd

两个都有输出,然后在 .cpp 里按 F12 应该能跳到定义。 如果不跳:Ctrl+Shift+P → clangd: Restart language server。

6.4 在线调试(cortex-debug)

.vscode\launch.json 是完整编译时从 hw\bsp\<板>\debug\launch.json 拷过来的(每次编译都会刷新,所以不要直接改 build\ 或 .vscode\ 里的那份, 要改就改 hw\bsp\<板>\debug\launch.json)。

⚠️ 先改 .vscode\settings.json 里的三条路径

为什么:仓库模板里这三条指向的是队友电脑上的目录(D:\softwarerm\...)—— 你机器上根本没有这个目录,一按 F5 就报「找不到 openocd / gdb」。

改哪儿:用 VS Code 打开仓库根目录下的 .vscode\settings.json,找到这三行(原文就是这样):

    "cortex-debug.openocdPath": "D:\\softwarerm\\OpenOCD\\bin\\openocd.exe",
    "cortex-debug.armToolchainPath": "D:\\softwarerm\\gcc-arm-none-eabi-10.3-2021.10-win32\\Arm-GNU-Toolchian\\bin",
    "cortex-debug.JLinkGDBServerPath": "D:\\softwarerm\\SEGGER\\JLinkGDBServerCL.exe",

改成什么(用你自己机器上的真实路径):

这一条 改成 怎么找
cortex-debug.openocdPath 你的 openocd.exe 完整路径 §1.9 你装的 OpenOCD:<你的 OpenOCD 目录>\bin\openocd.exe(教程示例 C:\Tools\openocd\bin\openocd.exe)
cortex-debug.armToolchainPath 你的 ARM 工具链 bin 目录 ⚠️ 这条要的是目录,不是某个 .exe §1.8:<你的 ARM 工具链目录>\bin(教程示例 C:\Tools\arm-gnu-toolchain\bin)
cortex-debug.JLinkGDBServerPath JLinkGDBServerCL.exe 的完整路径 §5.3 你装 J-Link 的目录下(用 CMSIS-DAP 的话这条用不上,但别删、写对就行)

⚠️ JSON 里反斜杠要写两个:C:\Tools\openocd\bin\openocd.exe 在 json 里必须写成 "C:\\Tools\\openocd\\bin\\openocd.exe"。

💡 文件上面还有一组被 /* */ 注释掉的(用的是 C:\Program Files\...)—— 那是队友的参考示例, 别删;你可以照它的格式改下面那三行。 📌 那组注释里的 Arm-GNU-Toolchian 是原文的拼写(少了个 i)—— 照抄时别被它带偏:路径要以你自己机器上实际的目录名为准。

📌 改完按 Ctrl + S 存盘即可,不用重开 VS Code。

⚠️ servertype 要和你的调试器对上:模板里可能写的是 "servertype": "jlink"。

你的调试器 servertype configFiles
J-Link jlink 留空即可
DAP-Link / ATK 无线调试器 openocd hw\bsp\<板>\debug\openocd_dap.cfg

对不上的表现:按 F5 后一直连不上,或者 GDB server 根本起不来。

⚠️ 调试器同一时刻只能被一个程序占用。 用 Ozone 调试时,先关掉 VS Code 的调试会话;反过来也一样。

调试流程:

  1. 先确认没有别的程序占用调试器(关掉其它 openocd / 上位机);
  2. VS Code 里按 F5;
  3. cortex-debug 会自己起 openocd、烧录、停在 main。

6.5 看外设寄存器(SVD)

hw\bsp\<板>\debug\launch.json 里的 svdFile 指向 lib\cmsis_svd\data\STMicro\...。 这个目录编译时零引用,但别删 —— 看外设寄存器就靠它,删了调试时就没有寄存器视图。

6.6 VS Code 常用快捷键

功能 快捷键
跳转到定义 Ctrl + 点击 / F12
选中当前行 Ctrl+L
删除当前行 Ctrl+Shift+K
重命名变量 F2
当前文件查找 Ctrl+F
整个项目查找 Ctrl+Shift+F
查找所有引用 Alt+Shift+F12
返回上一动作 Alt+←
切换打开的文件 Ctrl+Tab
编译(本工程) 跑任务 build:Ctrl+Shift+P → Run Task → build(Ctrl+Shift+B 可能要先从列表里选一个)
调试 F5

更多快捷键按 Ctrl+K 再按 Ctrl+S 查看,并且可以改成你最习惯的方式。 补全和 snippet 都用 Tab 接受提议,↑/↓ 切换。


第 7 章 故障字典

📖 本章导读

  • 做什么:查错。这章不是用来顺序读的
  • 需要:一条具体的报错信息(越完整越好)
  • 用法:按报错现象在本章搜关键字。

💡 查错三步:① 看清报错最后 20 行 → ② 在本章搜关键字 → ③ 还是不行就贴出来问, 附上 §1.11 的版本号。

用法:出问题先来这里按现象查。

🔑 先做一次分类:是环境问题,还是代码问题?

这一步能帮你跳过 80% 的无用重装。 对不上号再往下按现象查。

你看到的现象 判断 去哪儿
有的目标编得过、有的编不过 ✅ 代码问题 工具链是好的 → 那是下发包自身的代码缺陷,别动环境
所有目标都卡在同一个工具上(都找不到 clang / ninja…) 🔴 环境问题 §1.11 自检 → PATH → 盘符
报 cstddef 找不到 🔴 环境问题 where arm-none-eabi-gcc 空不空 → §1.7
openocd --version 正常、探测也正常,但读内存失步 🔴 版本问题 用了 xPack 0.12.0 → 回 §1.9
打完 banner 无限静默卡住 🔴 硬件问题 探针好的,芯片没响应 → 查接线/供电/有没有接板子(坑 23)
命令打印一段用法后静默退出 🔴 参数/版本问题 见 §1.9 末尾
报 ERROR:No target select. ⚠️ 名字写错了 大小写不对 → §3.2

💡 一句话记住:「有的过有的不过 → 工具链是好的」。

7.1 环境类

🔴 坑 1:路径含中文 / 空格 → CMake / Ninja 各种奇怪报错

展开看:现象 · 原因 · 解决

utils\python\tool.py 会直接打印「工程路径请不要带有空格 / 中文」然后退出。 解决:把仓库挪到 %USERPROFILE%\Desktop\RowletBot 这种纯英文无空格路径。


🔴 坑 2:ninja / cmake / clang 报 「不是内部或外部命令」 → PATH 没生效

展开看:现象 · 原因 · 解决

现象(新生最常撞的一个):

'ninja' 不是内部或外部命令,也不是可运行的程序或批处理文件。

明明按文档配好了 PATH,在自己的 cmd 窗口里敲 ninja --version 也正常, 一进 VS Code 的终端就不认了。

原因:PATH 只在进程启动的那一刻读一次。

  • VS Code 的集成终端是 VS Code 进程的子进程,继承的是 VS Code 启动时的环境;
  • 你后来加的 PATH,已经开着的 VS Code 完全看不到 —— 在里面新开多少个终端标签都没用。

解决(必须整个重开):

  1. 完全退出 VS Code:File → Exit,然后去任务管理器确认没有残留的 Code.exe (VS Code 经常关了窗口但进程还驻留着);
  2. 重新打开 VS Code;
  3. 新开一个终端,敲 where ninja —— 有输出就对了。

⚠️ 只关掉终端标签、或者执行 Developer: Reload Window,都不保证生效。 别赌,整个退出。

如果重开 VS Code 还是不行:说明它的父进程(桌面 explorer.exe)也拿着旧环境。 最快的办法是注销一次再登录(或者重启)。

自检三条(分清到底卡在哪一层):

# 在哪敲 where ninja 结果 → 结论
1 VS Code 的终端里 没有输出 → 就是本坑
2 桌面上按 Win+R → cmd → 回车,再敲 有输出 → PATH 是对的,只是那个 VS Code 实例旧了,重开 VS Code 即可
3 同上,桌面的 cmd 里也没有 PATH 真的没配上 → 回去跑 §1.10 的脚本,然后注销/重启

💡 为什么"我的 cmd 里是好的、VS Code 里不行":cmd 是后开的,读到了新 PATH; VS Code 是先开的,读的是旧 PATH。同一时刻,不同进程可以有完全不同的 PATH。

⚠️ 补一条:"新开的终端"也可能是旧的

常见情况:改完 PATH 后明明新开了一个 cmd,敲 git --version 还是 "不是内部或外部命令"。

原因:那个 cmd 是从"改 PATH 之前就已经在运行的进程"派生出来的。 Windows 子进程继承的是父进程启动那一刻的环境块 —— 注册表改了,已经在跑的父进程不会自动刷新,它的子进程自然也拿不到。

终端从哪儿开出来的 结果
从一个改 PATH 之前就存在的进程派生(IDE、脚本宿主、远程会话…) ❌ 还是找不到命令
那个父进程重启之后再派生 ✅ 正常

所以:如果新终端里仍然找不到命令,把它的"父进程"也一起重启。 典型场景:从 IDE / 脚本 / SSH 远程会话里拉起来的终端 —— 只关终端本身不够,要重启那个宿主进程(或者干脆注销一次)。


🔴 坑 3:python 命令不存在 / 敲 python 弹出微软商店

展开看:现象 · 原因 · 解决

原因:Windows 的「应用执行别名」占位程序(WindowsApps\python.exe,0 字节重解析点) 排在真实 Python 前面。 解决:删掉那两个别名(等价于「设置 → 应用 → 高级应用设置 → 应用执行别名 → 关掉 python.exe / python3.exe」), 再把真实 Python 提到用户 PATH 最前:

Remove-Item "$env:LOCALAPPDATA\Microsoft\WindowsApps\python.exe"  -Force
Remove-Item "$env:LOCALAPPDATA\Microsoft\WindowsApps\python3.exe" -Force

验证:where python 第一行要指向真实的 Python 安装目录, 不能是 ...\WindowsApps\python.exe(你的路径可能不同,见 §1.11)。


🔴 坑 4:杀毒软件拦截 → 编译变慢 / 文件被锁

展开看:现象 · 原因 · 解决

把 C:\Tools 和仓库目录加进排除项(见 §1.0 ④)。 顺带:这也能显著加快编译(从 5 分钟级降到 20 秒级)。


🔴 坑 5:core.autocrlf 导致 CRLF → 旧版 project.py 会 IndexError 崩溃

展开看:现象 · 原因 · 解决

解决:git config --global core.autocrlf false。 (仓库有 .gitattributes 时可以不设;没有就设上。)


🔴 坑 6:Windows 更新中途重启 → 编译到一半断电

展开看:现象 · 原因 · 解决

编译到一半被打断,build\ 里会残留半成品,下次编译报莫名其妙的错 —— 删掉整个 build\ 目录重新编译即可。


🔴 坑 7:code --version 不打印版本、反而弹出一个 VS Code 窗口然后卡住

展开看:现象 · 原因 · 解决

原因:PATH 里加的是解压出来的便携版根目录(如 C:\Tools\VSCode), 于是 code 解析到 GUI 版 Code.exe。

解决:

  • 用安装版(本文 §1.2 的做法),PATH 里只会有 bin 目录,天然没这个问题;
  • 如果已经在用便携版,把 PATH 里的 C:\Tools\VSCode 换成 C:\Tools\VSCode\bin, 并且排在 C:\Tools\VSCode 前面。

验证:where code 输出里要有 ...\bin\code.cmd(不一定在第一行 —— 同目录下还有个无扩展名的 code,where 常把它排前面,正常);不能出现 Code.exe。


🔴 坑 8:dir ...\arm-none-eabi\include\cstddef 报「找不到文件」

展开看:现象 · 原因 · 解决

原因:这个路径在 ARM 13.3.rel1 里本来就不存在,不是装坏了。 真实位置:...\arm-none-eabi\include\c++\13.3.1\cstddef。

正确的检查:

Get-ChildItem '<你的 ARM 工具链目录>' -Recurse -Filter cstddef |
  Select-Object -ExpandProperty FullName

更硬的判据是能编译(见 §3.4)。


🔴 坑 9:单独敲 clang++ --target=arm-none-eabi 编 C++ 报 'cstddef' file not found

展开看:现象 · 原因 · 解决

原因:这样调用时 clang 不知道 ARM 的 libstdc++ 头文件在哪 (--gcc-toolchain 在 clang 18 被判为 unused)。

这不是环境坏了 —— 工程 toolchain.cmake 会用显式 -isystem 喂给 clang。 要验证工具链,请编译一个真实目标:python project.py build rm-c ex1_ledm_Hero`。


7.2 构建类

🔴 坑 10:project.py config 保存后报 cstddef 找不到 → 其实是坑 2 的变体

展开看:现象 · 原因 · 解决

现象(用 python project.py config 勾选、Save 退出后立刻编译):

CMake Error at hw/bsp/mc02/toolchain.cmake:128 (message):
  Could not find the arm-none-eabi toolchain C++ headers (cstddef).

    arm-none-eabi-gcc :
    sysroot           :
    searched          : <sysroot>/include/c++/*/cstddef and /usr/include/newlib/c++/*/cstddef
...
CMake Error: CMake was unable to find a build program corresponding to "Ninja".
  CMAKE_MAKE_PROGRAM is not set.
-- Configuring incomplete, errors occurred!

这是最容易被误判的一个报错:字面看像"ARM 工具链没装 / 装坏了", 于是很多人去重装工具链、改 toolchain.cmake、翻 cstddef 路径 —— 全部白费。

真相:又是坑 2(PATH 没生效),只不过换了个面孔。

hw/bsp/mc02/toolchain.cmake 在 Windows 下是这样定位工具链的:

if(WIN32)
  execute_process(
    COMMAND where arm-none-eabi-gcc      # ← 完全依赖 PATH
    OUTPUT_VARIABLE GCC_ARM_NONE_EABI_GCC
    ...)
  ...
  get_filename_component(GCC_ARM_NONE_EABI_BIN "${GCC_ARM_NONE_EABI_GCC}" DIRECTORY)
  get_filename_component(GCC_ARM_NONE_EABI_PREFIX "${GCC_ARM_NONE_EABI_BIN}" DIRECTORY)
  if(EXISTS "${GCC_ARM_NONE_EABI_PREFIX}/${CLANG_TARGET}")
    set(GCC_ARM_NONE_EABI_ROOT "${GCC_ARM_NONE_EABI_PREFIX}/${CLANG_TARGET}")
  endif()
endif()

也就是说:where arm-none-eabi-gcc 找不到 → GCC_ARM_NONE_EABI_ROOT 为空 → 拼不出 sysroot → 报 cstddef 找不到。 而 C:\Tools\ninja 不在 PATH 里,就同时报出下面那条 Ninja 错误。

一眼判定(记住这个特征):

报错里这两行长什么样 结论
arm-none-eabi-gcc : 空的、sysroot : 空的 PATH 问题(= 本坑)→ 不要重装工具链
两行都打印出了真实路径,仍然报 cstddef 才是布局问题(比如多套了一层目录,见 §1.8)

对照实验(证明就是这个原因,不是猜的):

实验 做法 结果
A 全新会话(PATH 已生效)跑 where arm-none-eabi-gcc / ninja 2/2 都解析出正确路径 ✅
B 全新会话 + 干净 build\ 跑 python project.py build mc02 Mecanum_Hero exit 0,24 秒,无任何 cstddef / Ninja 报错 ✅
C 人为构造陈旧 PATH(保留 CMake,但去掉两个 C:\Tools\* 条目)跑同一条命令 逐字复现出上面全部报错(含 sysroot : 空行)✅

A 证明环境是好的,C 证明陈旧 PATH 必然产生这个报错,B 证明修复方式有效 —— 三者闭环。

验证方法(不用猜,直接问 where):

where.exe arm-none-eabi-gcc
where.exe ninja
  • 两条都有输出 → 环境是好的,问题在当前这个终端进程;
  • 某条没有输出 → 你的 PATH 里缺这一条,回去跑 §1.10 的脚本,然后完全重开 VS Code。

解决:完全按 坑 2 的步骤做 —— 彻底退出 VS Code(任务管理器确认无 Code.exe 残留)→ 重开 → 新终端里 where ninja 有输出 → 再编译。

💡 判定性问题:如果 project.py config 的图形界面能正常打开、能勾选、能保存, 那 Python 和 tkinter 都是好的,一定不是"环境没装", 而是"某个进程没看到 PATH"。别重装,去查进程环境。

⚠️ 如果 build\ 已经被这次失败污染

失败的那次会在 build\CMakeCache.txt 里留下空的工具链缓存, 即使 PATH 修好了也可能继续报同样的错。直接删掉重来:

Remove-Item .\build -Recurse -Force
python project.py build mc02 Mecanum_Hero

🔴 坑 11:Configuration file not found / ERROR:No target select.

展开看:现象 · 原因 · 解决

板子名或 robot 名和 §3.2 配置窗口里显示的不一致(大小写敏感;名字里有空格要加引号)。 先把 §3.2 配置窗口里「机器人」菜单看到的名字贴出来对照。


🔴 坑 12:Cannot find source file: .../system_stm32h7xx.c → 没跑子模块初始化

展开看:现象 · 原因 · 解决
git submodule update --init

如果你拿到的是打包好的压缩包,这 5 个目录里应该已经是真实文件,不用跑(见 §2.3)。


🔴 坑 13:'robot.hpp' file not found → 配置指向的 robot 不存在

展开看:现象 · 原因 · 解决

.config 里选的 robot 名字,在 src/robot/ 下没有对应目录。换一个存在的目标。


🔴 坑 14:'dev_cap.hpp' file not found → 某些分支没有 src/device/cap/

展开看:现象 · 原因 · 解决

换目标,或把该设备从配置里去掉。


🔴 坑 15:HAL_IWDG_DeInit 未定义 → STM32 的 IWDG HAL 根本没有这个函数

展开看:现象 · 原因 · 解决

看门狗一旦启动就不能"反初始化"。改代码逻辑(用 BSP_WDG_ENABLE 之类的开关),别去调它。


🔴 坑 16:module.hpp: No such file or directory → 同名头 / 选错模块

展开看:现象 · 原因 · 解决

检查相应目录下是否存在同名头文件冲突,以及 .config 里选的模块是否真的存在。


🔴 坑 17:编译"到一半失败"但没提示 → 一定要看汇总

展开看:现象 · 原因 · 解决

ninja 的失败信息可能被大段编译输出冲掉。直接看整个命令的最后 20 行, 或者用 python ./project.py build all all(正常开发用不到,只是它能一次性汇总失败清单):

1 target(s) failed to build:
  - .../hw/bsp/XXX [yyy] (cmake configure failed)

🔴 坑 18:build all all 报 Webots 的 cmake configure failed

展开看:现象 · 原因 · 解决

这是正常的,忽略即可(原因就在下面)。 (不同包里失败的那个 robot 名不一样,看到 Webots 字样就点这里。)

报错会长这样:

lld-link: error: could not open 'kernel32.lib': no such file or directory

Webots 是 PC 仿真器 BSP,需要 MSVC / Windows SDK,本教程的十件工具里没有。 Webots 之外的失败,几乎都是下发包自身的代码缺陷,不是你的环境坏了。

具体有几个成功、几个失败,随压缩包版本变 —— 别拿"17 个"这个数字当验收标准(见坑 21 和附录 B)。


🔴 坑 19:编完 A 目标,再编 B 目标,firmware\ 里 A 不见了

展开看:现象 · 原因 · 解决

原因:完整编译(python project.py build <板> <目标>)每次开始都会清空 firmware\ 并重新生成(build\ 不会被删,但里面的产物会被这次编译覆盖)。

  • build all all → firmware\ 里有全部目标;
  • 单次 build <板> <robot> → 只剩这一个。

解决:要留档就编译完立刻把 firmware\<板>\<robot>\ 复制出去。


🔴 坑 20:没配置过就编译 —— 两种报错,都不是环境坏了

展开看:现象 · 原因 · 解决

这是新生最常撞的一个错,而且极具误导性 —— 它看起来像「环境没配好」, 其实只是顺序错了:还没配置过就按了编译。

它有两种表现形式,都要认得:

你怎么编的 报错 说明
VS Code 跑 build 任务 / 双击 build_script.bat,但 build\ 里还没有 build.ninja ninja: error: loading 'build.ninja': The system cannot find the file specified. 脚本只编译、不配置
跑 python project.py build 没带板子和 robot 参数错误 不是 ninja 报错,就光秃秃三个字

⚠️ 看到「参数错误」别慌 —— 它只是说「你没告诉我编哪个目标」。 回 §3.2 配好目标(配置窗口里选板子 + robot → Save)就好。

原因:build_script.bat(以及 VS Code 里那个叫 build 的运行任务 —— 它跑的就是这个脚本) 只编译、不配置,内容就这么几行:

@echo off
if not exist build mkdir build
cd build
ninja -j%NUMBER_OF_PROCESSORS%
cd ..

(有的分支包里这个脚本还带 BOARD ROBOT 之类的分支;你手上这份通常只有上面这几行 —— type build_script.bat 看一眼就知道。)

build\ 里还没有 build.ninja 时,ninja 自然找不到文件。

更容易误判的地方:if not exist build mkdir build 会建一个空的 build\ 目录, 于是你去看的时候 build\ 是存在但空的 —— 很容易以为「编译坏在半路」或者「环境配错了」。

解决:先回 §3.2 跑一次配置窗口(黑窗口刷完 Build files have been written to 就有了 build.ninja),之后改代码才跑 build 任务 / 双击 build_script.bat。 换目标也是同一步:回 §3.2 配置窗口改一次 + Save。

验证:

dir build\build.ninja       REM 有输出就说明配置过了
ninja -C build               REM 应该能正常跑

排查三步(确认到底是不是这个问题):

检查 命令 说明
1 dir build\build.ninja 没有 → 就是本坑
2 type build_script.bat 里面只有 ninja 一行 = 只编译版,必须先跑一次 §3.2 的配置
3 跑 build 任务能不能编出固件(§3.4) 能编出来 → 环境本身没问题,别去重装工具链

💡 想编指定目标:在 §3.2 的配置窗口里选它 → Save,再跑 build 任务(§3.4)。 ⚠️ 不要指望 build_script.bat <板> <目标> 能换目标 —— 本文这版脚本会忽略参数,只跑 ninja。


🔴 坑 21:目标名(robot / module)随分支和压缩包变化,不能背文档

展开看:现象 · 原因 · 解决

现象:照抄文档里的示例命令会报错,而报错看起来像环境问题:

Configuration file not found
ERROR:No target select.
fatal error: 'dev_blink_led.hpp' file not found

原因(很简单,但最容易误判):

不同分支 / 不同压缩包里,robot 和 module 的集合是不一样的。 本文档的示例(Mecanum_Hero、25-omni、shoot_hero…)只是参考名, 不是"标准答案"。战队每次下发或更新分支,目录都可能增减改名。

做法:以 §3.2 配置窗口里显示的名字为准,别背文档里的目标名。

对照一下(在 RowletBot-26Sort-ShootHero-slim-* 这一个包上 Test-Path 验证, 仅用于说明差异有多大,不要当成其他分支的结论):

教程示例里的名字 在这个包里 备注
blink ❌ 该包没有 本文档已改用 rm-c + ex1_led(§3.2),不再用 blink
25-omni ❌ 该包没有 该包叫 Omni_Infantry / 26-Omni_Infantry
close_hero / dev_arm / delta_custom_ctrl ❌ 该包没有 —
motor_test / wheelleg_gimble ❌ 该包没有 —
shoot_hero ✅ 有 目录名 Shoot_Hero,配置名 shoot_hero;本文不用它当例子
src\robot\blink\robot.cpp ❌ 该包没有 本文档已改用 src\robot\ex1_led\robot.cpp(§3.3)

该包里真实存在的 15 个 robot 目录(同样只对这个包成立):

26-Omni_Infantry   demo_serial_leg_chassis   Drone      gather_table
Mecanum_Hero       Mecanum_Infantry          Meca_TrackHero
Music              New_26_Hero               Omni_Infantry   Radar
rudder_chassis     rudder_gimbal             Shoot_Hero      WLT_TestChassis

✅ 唯一正确的做法:永远先问机器,别背文档

在 §3.2 的配置窗口里展开「开发板」和「机器人」两个菜单 —— 那就是你这个包里真实存在的 板子与 robot(配置窗口读的是 src\robot\,永远可用)。从里面挑一个 → Save → 跑 build 任务。

💡 两句话记住这一坑:

  1. 文档教的是"怎么做","有哪些目标"看 §3.2 配置窗口里的菜单。
  2. 目标名区分大小写,含空格的要加引号(如 "new rudder gimbal")。

📌 换了分支/换了压缩包之后,第一件事就是回 §3.2 的配置窗口看一遍菜单, 别拿上一份的 robot 名硬套。


7.3 烧录类

🔴 坑 22:Error: couldn't open analysis\before-flash.bin → 反斜杠被 Tcl 吃掉

展开看:现象 · 原因 · 解决

-c "..." 里的路径一律用 / —— 反斜杠会被 Tcl 当成转义符吃掉: analysis\before-flash.bin 里的 \b 是退格符,于是变成 analysisefore-flash.bin。 特征:报错里的文件名少字母 / 多个怪空格。


🔴 坑 23:烧完没反应 → 先确认烧的是哪个固件,再确认板子型号

展开看:现象 · 原因 · 解决
# 可能原因 怎么查
1 烧的不是你以为的那个固件(build\ 里是别的板/robot 的产物) dir build\xrobot.bin 看修改时间是不是刚才 —— 时间对就说明是刚编的;或干脆重跑一次 build 任务再烧(§4.4)
2 板子型号对不上(用 F4 的 cfg 烧 H7) type hw\bsp\<板>\debug\openocd_dap.cfg 看最后一行 target;或看探测输出的 Device: 行
3 改了代码但没保存就编译了 看 VS Code 标签页的小圆点;git diff
4 编译其实失败了,烧的是上一次的旧 bin 看编译输出有没有红色的 failed:;别只看脚本有没有跑完(§4.4 讲过:老脚本失败也可能返回 0)
5 板子需要重新上电 / 按复位 断电重上电
6 固件本身有问题(卡在初始化 / 反复重启) 用调试器打断点看卡在哪(坑 27 / 28)

想更早发现?烧之前先探一下板子(只读,不改任何东西 —— 命令行):

openocd -f hw/bsp/rm-c/debug/openocd_dap.cfg -c init -c halt -c "flash probe 0" -c "flash banks" -c shutdown
你看到的 含义
Device: STM32F4xx + 768 KB Flash(rm-c)/Device: STM32H72x/73x + 1024 KB(mc02) ✅ 探针和接线都正常,可以往下烧
报 unable to find CMSIS-DAP device(或类似找不到设备) 探针压根没被认出来 → 设备管理器(§4.3)、换 USB 口、驱动
打完版本 banner 后无限静默卡住(能挂 2 分钟以上) 🔴 探针是好的,芯片那头没回应 → 查 4 根接线(§4.2)、板子是否上电、是否根本没接板子;别因为这个去重装 OpenOCD

📌 为什么用 hw\bsp\<板>\debug\openocd_dap.cfg 而不是 toolchain\openocd_dap.cfg: 后者是构建产物(cmake 配置时拷过来的共享副本),内容会随最后一次编译的板子变 —— 编完 rm-c 再拿它去烧 H7 板,会报 Cannot identify target as a STM32 family, 报错指向硬件,实际是构建顺序问题。 另外:-c "..." 里的路径必须用正斜杠 /(见坑 22)。


🔴 坑 24:Error: CMSIS-DAP command mismatch. Expected 0x6 received 0x5

展开看:现象 · 原因 · 解决

完整现象(这个坑极具迷惑性):

  • openocd --version、探测、芯片识别、flash 尺寸读取全部正常;
  • 但 dump_image 每次读到 8–16 KB 就断,报上面这行 + Error: Failed to read memory at 0x...。

原因:xPack OpenOCD 0.12.0 的 CMSIS-DAP 驱动与调试器固件不兼容。

已排除:降速(1800/1000/500/250/100 kHz 全试过)、软件复位 USB 设备、 关闭占用进程 —— 都无效。

解决:换成 sysprogs 构建的 OpenOCD 0.11.0(见 §1.9)。

验证:openocd --version 第一行应该是 Open On-Chip Debugger 0.11.0 (2021-11-18) [https://github.com/sysprogs/openocd]。


🔴 坑 25:Can't find interface/cmsis-dap.cfg

展开看:现象 · 原因 · 解决

原因:安装布局错了,不是配置错 —— share\openocd\scripts\ 必须和 bin\ 在同一个父目录下。

判断:

openocd -c "echo [find interface/cmsis-dap.cfg]" -c shutdown

解决:把 scripts 挪到 share\openocd\ 下;或设环境变量 OPENOCD_SCRIPTS (见 §1.9 / §1.10)。


🔴 坑 26:没备份就烧了

展开看:现象 · 原因 · 解决

拿到的 mc02 板上真的躺着别人的固件(78.46% 非零、向量表有效)。 不备份就烧,等于把队友的固件永久抹掉。

规矩:动任何一块不是自己的板子之前,先备份(只读,命令行):

openocd -f hw/bsp/rm-c/debug/openocd_dap.cfg -c init -c halt -c "dump_image analysis/rm-c-backup.bin 0x08000000 0x100000" -c shutdown
  • dump_image <输出文件> <起始地址> <长度>:把 Flash 读出来存成文件(只读);
  • 长度用探测出的真实容量:mc02 → 0x100000(1024 k),rm-c → 0xC0000(768 k)(怎么探见坑 23);
  • -c "..." 里的路径要用正斜杠 /(见坑 22);备份落在 analysis\,别用 git 提交它;
  • 备份大小对一下:本文的 rm-c → 786,432 字节;mc02 → 1,048,576 字节。 对不上说明读取中途断了(多半是 OpenOCD 版本问题,见 §1.9)。

以后要还原 —— 把备份文件直接写回板子(不经过 ninja,不会被重编覆盖):

openocd -f hw/bsp/mc02/debug/openocd_dap.cfg -c init -c halt -c "flash write_image erase analysis/mc02-backup-20261002-024759.bin 0x08000000" -c reset -c shutdown

(文件名换成你 analysis\ 里那一个;-c "..." 里的路径必须用正斜杠 /,原因见坑 22。 还原前先比对它的时间戳和 md5,确认这真的是你要还原的那一份 —— 还原之后 build\xrobot.bin 不再是你当前工程编出来的那一份,别拿它当身份凭据。)

如果已经烧了没备份 —— 只能找回原作者重编一份,没有别的办法。


🔴 坑 27:蜂鸣器响完就不叫了 / 车控不了 → Error_Handler 的报警

展开看:现象 · 原因 · 解决

某代 Error_Handler 会用蜂鸣器/闪灯报出是哪个外设初始化失败。 看门狗由 hw/bsp/*/drivers/bsp_wdg.c 统一管理(超时 2.0 s、默认不启动)。


🔴 坑 28:板子反复重启 → 看门狗复位 或 Error_Handler 循环

展开看:现象 · 原因 · 解决

用调试器打断点看卡在哪(报警现象见坑 27)。 Release 固件不会因为看门狗不停重启(那条旧说法已作废),但排查还是用 Debug 方便。


7.4 调试类

🔴 坑 29:p g_assert_file / p g_err_file / p g_overflow_task_name

展开看:现象 · 原因 · 解决

这些 RAM 全局是断言 / 故障现场,调试器里直接读就知道哪一行出错。


🔴 坑 30:System::AssertInfo() —— 没调试器时在还能跑的线程里打印

展开看:现象 · 原因 · 解决

连不上调试器时用它把故障信息打到串口。


7.5 报错怎么读(零基础版)

  1. 先看最后 20 行 —— 真正的错误几乎总在最后;
  2. 找 error: / Error: 关键字,忽略 warning;
  3. 看第一个错,后面的经常是它的连锁反应;
  4. 把报错原文整段贴出来问,别只说"编译不过";
  5. 对照坑 22 的特征:路径里出现少字母或多出怪空格(如 analysisefore-flash.bin) = -c "..." 里用了反斜杠。

7.6 脚本 / 自动化类

这一节是给「用脚本或远程方式配环境」的人看的。手动双击安装的同学可以跳过。

🔴 坑 31:PowerShell 脚本里的中文变成乱码

展开看:现象 · 原因 · 解决

原因:PowerShell 5.1 读取没有 BOM 的 .ps1 时,按系统 ANSI 代码页 (中文系统是 GBK)解析,于是脚本里的中文字面量在解析阶段就已经坏了, 还没执行就已经是乱码。

现象:python -c "print('中文测试')" 报 UnicodeEncodeError: 'gbk' codec can't encode character '\ue15f' —— 不是 Python 的问题。

解决(三选一):

  1. 把脚本存成带 BOM 的 UTF-8;
  2. 脚本里不写中文,用码点拼:[string]([char]0x4e2d + [char]0x6587);
  3. 需要验证中文输出时,写一个真正的 .py 文件再跑(绕开 shell 引号):
    [IO.File]::WriteAllText("$pwd\t.py", "print('中文')", (New-Object Text.UTF8Encoding($false)))
    $env:PYTHONIOENCODING='utf-8';  chcp 65001 > $null;  python .\t.py
    
    注意:控制台显示出来可能仍是乱码(那是终端代码页的事), 要看码点才算数 —— 让脚本打印 [hex(ord(c)) for c in s] 来断言。

🔴 坑 32:脚本装 ARM 工具链时永久卡住

展开看:现象 · 原因 · 解决

原因:安装器结尾的 gccvar.bat 会开一个永不退出的 cmd /K 窗口, 把 Start-Process -Wait 之类的"等待结束"逻辑卡死。

判断:去 <你的 ARM 工具链目录>\bin\ 看 arm-none-eabi-gcc.exe 在不在(教程示例 C:\Tools\arm-gnu-toolchain\bin\) —— 在就说明装好了。

解决:在任务管理器里结束那个 cmd.exe 进程即可 —— 工具链其实早装好了,别以为装失败。


🔴 坑 33:脚本里装软件静默装错目录(参数被空格拆断 / 用错参数名)

展开看:现象 · 原因 · 解决

现象:安装器看似跑完了,但目标目录没生成,或者装到了别的地方。 典型翻车:想装到 D:\Program Files\Git,实际装进了 D:\Program, 全程没有任何报错。

两个互相独立的原因:

① Start-Process 会把字符串参数按空格拆开

# ❌ 错:'/DIR=D:\Program Files\Git' 被拆成 '/DIR=D:\Program' + 'Files\Git'
Start-Process $exe -ArgumentList '/DIR=D:\Program Files\Git' -Wait

# ✅ 对:用数组,一个参数一个元素;加 -NoNewWindow 让退出码能正常回传
Start-Process $exe -ArgumentList @('/DIR=D:\Program Files\Git') -Wait -NoNewWindow -PassThru

⚠️ 装完一定要去目标目录看一眼,不要相信退出码 —— 这类错误退出码可能是 0 或空。

② NSIS 安装器只认 /D=,不认 /DIR=

打包方式 改安装路径的参数 本教程里哪些是它
Inno Setup /DIR="..." Git、Python
NSIS /D=... LLVM、ARM 工具链
MSI TARGETDIR=... / 专有属性 CMake(ADD_CMAKE_TO_PATH)

用错参数名不会报错,会被静默忽略 → 装回编译期写死的默认目录(C 盘)。 把 /DIR= 用在 LLVM 和 ARM 上,结果两个都装回了 C:\Program Files。

⚠️ NSIS 的 /D= 有两条硬规矩: 必须是最后一个参数,且 路径不能加引号。

# ✅ NSIS 正确写法
Start-Process $exe -ArgumentList '/S /D=D:\ProgramFiles\LLVM' -Wait -NoNewWindow -PassThru

③ 最好的规避办法:改用不带空格的路径

把 D:\Program Files\... 换成 D:\ProgramFiles\..., 从根上消除空格被拆断的可能(也正好符合 §0.4 铁律 1)。

④ 顺带:-Wait 会被 ARM 安装器留下的窗口永久挂住

ARM 安装器结尾会 start 一个永不退出的 cmd /K(见 §1.8)。装完顺手清掉:

Get-CimInstance Win32_Process -Filter "Name='cmd.exe'" |
  Where-Object { $_.CommandLine -like '*gccvar*' } |
  ForEach-Object { Stop-Process -Id $_.ProcessId -Force }

附录 A 目录结构

RowletBot\
  project.py                 ← 总指挥(日常只用 config / clean,见 §3.2)
  build_script.bat           ← 快速重编
  download_dap.bat           ← 仓库自带的一键烧录(⚠️ 分支差异大,别直接双击,见 §4.4)
  config\                    ← .config / config.cmake(构建时生成)
  build\                     ← 编译产物(xrobot.bin/elf/hex/map、compile_commands.json)
  firmware\                  ← 归档产物(⚠️ 正常流程不产生)
  analysis\                  ← 固件备份放这里(别提交 git)
  src\                       ← robot / module / component / device / system
  hw\bsp\<板子>\             ← config\ / debug\(openocd_dap.cfg, launch.json) / drivers\ / ld\
  lib\                       ← 第三方库(含 5 个 vendored 子模块)
  user\                      ← 你自己的代码
  toolchain\                 ← 构建产物缓存(openocd_dap.cfg 的拷贝在这里,⚠️ 别用它烧录)
  tools\ozone\               ← Ozone 调试脚本与工程(⚠️ 脚本里写死了作者机器的路径,是另一条 Ozone ≥3.40 路线,见 §0.3)

附录 B 本文实测环境(版本参照)

📌 本文主用例已改为 rm-c + ex1_led(§3.2)。

这份下发包里几个关键文件的实测大小(无 md5/包体字节数 —— 未测,不列):

文件 实测大小
build_script.bat 133 字节
download_dap.bat 174 字节
.vscode\settings.json 4,205 字节
ninja.exe 569,856 字节
openocd.exe 4,245,518 字节

📌 本表是"我们测过哪一版"的存档,不是让你照着下这个版本 —— 补丁号更新很正常(如 Git 2.48、Python 3.12.9),大版本一致就行。 📌 唯一要留神的是 CMake:官网现在给的是 4.x,而本文只实测过 3.31.x —— §1.11 的自检不核对 cmake 版本(只验"环境变量可用"),装了 4.x 它照样显示 [OK] 环境变量可用;但万一 cmake 配置这一步报错,就换回 3.31.x(见 §1.5)。 安装位置按 §0.3 的约定:CMake / LLVM / Ozone 用官方安装包的默认位置,Ninja / OpenOCD / ARM 工具链在 C:\Tools\。

项目 值
系统 Windows 10 专业工作站版 10.0.19045 · AMD64
Git 2.47.1.windows.1
Python 3.12.8(tkinter 8.6)
VS Code 1.96.2(安装版 + 6 个插件,加上自动依赖共 11 个)
CMake / Ninja 3.31.4 / 1.12.1
LLVM / Clang 18.1.8
ARM GNU Toolchain 13.3.Rel1 (13.3.1 20240614)
OpenOCD 0.11.0 (2021-11-18) [sysprogs]
Ozone 3.24(32 位)+ J-Link 7.22b(见第 5 章);必装,调试和变量曲线要用
调试器 ATK CMSIS-DAP(VID_04D8&PID_00DF,FW Version 2.0.0)
板子 mc02(Device: STM32H72x/73x,Cortex-M7 r1p2,1024 KB Flash)
编译验证 build all all → 17/18 成功(Webots 需 MSVC,属正常)
烧录验证 mc02 shoot_hero 338,012 B,读回 md5 7063482f27e06f4d7bce4ea126c75b63 一致
换盘验证 另一台机器把全部工具装到 D 盘(D:\Tools\、D:\ProgramFiles\、D:\RowletBot)→ build all all 11 个目标成功、单目标 25.20 秒,build\CMakeCache.txt 里无任何 C: 路径 ✅

卡住的时候,先把自己的 --version 输出和这张表对一遍 —— 十有八九能直接看出是哪个工具不对。 只有 §1.0 第 2 条那 4 个红线工具(OpenOCD / Ozone / ARM / LLVM)必须严格对上,其余差个补丁号无所谓。

⚠️ 固件体积和 md5 会随压缩包版本变,别拿它当验收标准

⚠️ 固件体积和 md5 会随压缩包版本变,别拿它当验收标准

上表的 mc02 shoot_hero = 338,012 B(shoot_hero 是记录当时那份包里的目标名 —— 目标名随包变,见坑 21)。另一台机器用另一份压缩包 (RowletBot-26Sort-ShootHero-slim-20261001-1345.tar.gz)编同一个目标得到 338,096 B, 差 84 字节 —— 这是包版本差异,不是环境问题。 (build all all 的成功/失败目标数量也会随包变:本文一次是 17/18, 那份包上是 11 成功 / 5 失败 —— 失败的那几个都是下发包自身的代码问题,不是环境坏了。)

正确的验收标准是「能编出固件」(§3.4 的三条判据), 而不是「体积等于某个数字」。


附录 C 术语表(零基础速查)

读文档时遇到不认识的词,来这里查。按"你在哪儿看到它"分组。 本文档里没解释、你又看不懂的词 → 直接在群里问,问的时候把看到它的那句话一起贴出来。

C.1 硬件与目标

词 一句话解释
MCU / 单片机 那块"小电脑"。本战队的板子上是 STM32H723VG(mc02)或 STM32F407IG(rm-c)
固件 / firmware 烧进单片机里、长期住在里面的那个程序。相当于电脑上的 .exe
BSP Board Support Package,板级支持包 —— "这块板子有哪些外设、引脚怎么接"
HAL Hardware Abstraction Layer,ST 官方的硬件抽象层代码,用来操作外设寄存器
CMSIS ARM 官方的 Cortex-M 软件接口标准,HAL 和 DSP 库都基于它
看门狗(WDG) 一个"到点没喂我就重启"的定时器。本工程超时 2.0 s、默认不启动
飞车 板子失控让电机乱转。本文用的 ex1_led 只闪灯、不会飞车;换成会驱动电机的目标时,烧录前把车架起来(轮子悬空)或拔掉电机线,就是为了防这个
断言 / assert 程序里"我认为这里一定成立"的检查,不成立就停下来报错

C.2 编译与工具链

词 一句话解释
工具链 / toolchain "编译器 + 链接器 + 打包工具"这一整套。缺任何一件都编不出固件
交叉编译 在 A 平台(你的 Windows)上生成 B 平台(ARM 单片机)能跑的代码
编译 vs 链接 编译 = 把 .c/.cpp 翻成机器码 .o;链接 = 把几百个 .o 拼成完整的 .elf
sysroot 交叉工具链的"根目录",里面有目标平台的头文件和库
newlib / libstdc++ ARM 上的 C 标准库 / C++ 标准库。头文件就在 sysroot 里
specs 给 GCC 的一组"附加规则"文件名。本工程用 nano.specs(精简库)+ nosys.specs(裸机系统调用)
.elf / .bin / .hex 三种固件格式。调试用 .elf,烧录用 .bin
objcopy 格式转换工具,把 .elf 转成 .bin / .hex
-Og / -O3 优化等级。-Og 是"为调试优化",-O3 是"为速度激进优化"
-Werror 把警告当错误。所以本工程一个警告都会让编译失败(这是故意的,不是 bug)

C.3 工程与代码

词 一句话解释
目标 / target 一块板子 + 一个 robot 程序的组合,例如 rm-c ex1_led
.config 描述"这个目标用哪些模块、哪个 robot"的配置文件
Kconfig 生成 .config 的选项定义文件。新增 device/module/robot 目录必须带它
robot / module / component / device / system 框架的分层:机器人 / 模块 / 组件 / 设备 / 系统。
依赖方向是单向的:robot → module → component → device → bsp
vendored "把第三方代码直接拷进仓库"(而不是用包管理器装)
子模块 / submodule git 的"从别的仓库挂一个目录进来"机制。压缩包里已经打包好,学习阶段不用管
compile_commands.json 记录每条编译命令的文件,clangd 靠它做代码跳转
BUILD_INFO.txt 记录「这份固件是哪块板、哪个 robot」的身份文件。有的包有、有的没有(§3.5)

C.4 调试与烧录

词 一句话解释
调试器 / 探针 电脑和单片机之间那块小盒子(DAP-Link / J-Link / ATK 无线调试器)
SWD / SWCLK / SWDIO 调试用的两线协议(时钟 + 数据)。加上 GND 就是那 4 根线
CMSIS-DAP 一类调试器遵循的标准。正点原子的 DAP-Link 属于这类,在 Ozone 里显示成 Unknown CMSIS-dap
人机接口设备 设备管理器里的一个节点(PowerShell 里看 Class 列是 HIDClass,有的系统显示成「人体学输入设备」)—— 键盘 / 鼠标和调试器的 HID 通道都在它下面,DAP 的 HID-compliant vendor-defined device 就在这里(§4.3)
OpenOCD 把固件写进单片机、并充当 GDB server 的程序
GDB server "翻译官":把 GDB 的调试指令翻译成调试器能懂的时序
Ozone SEGGER 出的图形化调试器。能实时看变量、画曲线
烧录 / 下载 把 .bin 写进单片机的 Flash
dump_image 从板子里读出来存成文件(只读,用来备份别人的固件)
verify_image 拿本地文件和板子里的内容比对
md5 文件指纹。两个文件 md5 一样 = 内容完全一样
HSS / BMA SEGGER 的高速采样 / 后台内存访问。是 J-Link 专有,所以第三方探针走 GDB server 时拉不了曲线

C.5 系统与操作

词 一句话解释
PATH / 环境变量 系统"去哪找程序"的目录清单。改完必须重开终端(§1.10)
终端 / cmd / PowerShell 敲命令的窗口(cmd 和 PowerShell 都算)。标着 bat 的命令请用 cmd 跑 —— PowerShell 里 where 要写成 where.exe、& 要拆成一行一条(§1.0 第 3 条)。怎么打开:Win + R → 输入 cmd → 回车
管理员权限 装 Git / Python / VS Code 系统版时需要;C:\Tools 下的绿色包不需要
长路径支持 Windows 默认限制路径 260 字符。本工程路径较深,要打开 LongPathsEnabled(§1.3)
%USERPROFILE% 环境变量,等于 C:\Users\<你的用户名>
%LOCALAPPDATA% 环境变量,等于 C:\Users\<你>\AppData\Local

教程看完,就去真机跑一遍。

遇到问题先查第 7 章故障字典;还搞不定,来实验室一起看。