P1 · ONE BOARD, ONE CONTRACT
先把基准板固定下来
全课程 MCU 主线固定为 NUCLEO-G071RB。这样引脚、启动文件、链接脚本、烧录器和观察方法都有唯一答案,初学者不必在第一天同时猜芯片和工具。
P1.1 为什么选择 NUCLEO-G071RB
板卡采用 STM32G071RBT6(Arm Cortex‑M0+,128 KiB Flash、36 KiB SRAM),板载 ST‑LINK 调试器、USB 供电和虚拟串口。课程固定使用绿色用户 LED LD4、蓝色用户按键 B1 和板载虚拟串口,不要求面包板与外接电源。
固定基准板不等于其他板不能学。它只是把第一次成功所需的变量减到最少;迁移时再替换芯片头文件、链接脚本、引脚和外设实例,并重新验证电气边界。
P1.2 三条硬件映射
| 对象 | 固定映射 | 验收 |
|---|---|---|
| LD4 用户 LED | PA5,高电平点亮 | 每 500 ms 翻转 |
| B1 用户按键 | PC13 | 第 4 章去抖输入 |
| ST‑LINK VCP | USART2:PA2/PA3 | 115200 8N1 输出 |
这些映射来自 ST 的 UM2324 板卡手册,而不是按 Nucleo 外观猜测。若丝印、产品标签或板卡手册不一致,应停止烧录并重新核对型号。
P1.3 第一天的安全边界
只用 ST‑LINK USB 接口供电;不接市电、裸锂电池、外接 5 V 和未知传感器;拔插跳线前先断开 USB。LED/UART 路径不需要改焊桥。若电脑反复枚举设备、板卡发热或供电指示异常,立即断开并保存现象,不以重复插拔代替诊断。
P1.4 读懂板卡文档的四层地图
面对一块陌生开发板,资料不要从搜索结果里随便挑一篇开始。先把信息按四层放回正确的位置:产品页回答“这是什么型号、面向谁”;用户手册回答“接口、跳线、LED、按钮和供电怎样安排”;原理图回答“丝印名称最终接到了哪个 MCU 引脚”;芯片数据手册回答“这个引脚和外设在电气上允许怎样配置”。四层资料互相补充,不能用一层的宣传语替代另一层的引脚或额定值。
在 NUCLEO-G071RB 上,产品页让我们确认板卡家族,UM2324 让我们确认 Nucleo-64 的连接器与板载 ST-LINK,板卡原理图让我们核对 LD4、B1 和 VCP 的走线,STM32G071RBT6 数据手册则用于核对 GPIO 复用、输入电平和复位后的状态。阅读顺序很重要:先确认对象,再抄写事实,最后才把事实转成代码常量。若四层资料之间出现名字不一致,优先暂停并记录差异,而不是凭经验选一个。
| 资料层 | 最适合回答 | 留下的证据 | 不能越界推出 |
|---|---|---|---|
| 产品页 | 型号、系列、工具入口 | 产品名称、修订日期、链接 | 某个 LED 一定接在哪个脚 |
| 用户手册 | 连接器、跳线、板载器件 | 章节、图号、页码 | 所有 GPIO 都能承受相同电流 |
| 原理图 | 网络名称和实际连线 | 网名、器件标号、页码 | 复位后软件已经初始化外设 |
| 芯片数据手册 | 电气、复用、限制 | 表号、条件、版本 | 板卡上的外部电阻和焊桥不存在 |
请为自己的板卡抄写型号、MCU、板卡修订、LED 网络名、按键网络名、VCP 引脚、唯一供电入口和三个来源链接。每个字段旁边写“产品页/用户手册/原理图/数据手册”中的一个来源;找不到来源的字段标为未知,不要用搜索摘要补齐。
P1.5 把引脚映射写成合同
引脚映射不是一张方便记忆的列表,而是固件与硬件之间的合同。合同至少包含端口、位号、有效电平、复位状态、输入输出方向、是否被其他板载器件共享,以及代码初始化完成的时刻。以 LD4 为例,“PA5 高电平点亮”只描述行为的一半;还要知道 PA5 在复位期间是否浮空、是否被调试器占用、驱动 LED 时是否需要串联电阻,以及低功耗时它会不会保持状态。
将映射集中在一个头文件或配置结构中,主循环只调用 led_write(true),不要让每个业务函数散落 GPIOA->BSRR 和神秘的 5。这样迁移到另一块板时可以替换合同并重新验证,而不是搜索全仓库猜哪些数字属于硬件。代码并没有替代手册:它只是把已经确认的事实写成可检查的接口。
C · BOARD CONTRACT#include <stdbool.h> typedef struct { const char *name; unsigned port; unsigned pin; bool active_high; } led_contract_t; static const led_contract_t user_led = { .name = "LD4", .port = 0u, /* GPIOA */ .pin = 5u, .active_high = true, }; bool led_level_for(bool on) { return user_led.active_high ? on : !on; }
只修改 active_high,不要改调用者和计时逻辑。先预测 led_level_for(true) 的结果,再在主机上编译小片段;如果结果和预测不同,检查布尔取反的位置。这个练习故意不要求上板,先证明合同和行为分离。
P1.6 板卡识别记录:从开箱到可复查
第一次插入板卡时,不要只拍一张“灯亮了”的照片。记录板卡正面和背面的型号标签、USB 插口旁的 ST-LINK 标识、供电指示、系统枚举出来的调试器名称和串口名称。照片解决“当时是哪块板”的问题,文本记录解决“当时使用了什么环境”的问题;两者一起才足以让另一个读者复查。
建议把识别过程写成四步:一是断开所有外接线,只保留数据线;二是连接后等待系统完成枚举,不在设备管理器或 lsusb 尚未稳定时开始烧录;三是抄写 ST-LINK 固件或序列号(若系统显示);四是保存一份对象卡。以后如果换了 USB 口、电脑或板卡修订,重新记录变化,不要覆盖旧记录。
任何一格缺失,都应把结论范围缩小到“尚未确认”。
把“这块板能跑程序”改写成带条件的句子,至少包含板卡型号、供电方式、工具或系统观察、时间窗口和仍未证明的事项。例如可以证明 ST-LINK 被枚举,不要因此宣称目标固件已经启动。
P2 · INSTALL AND PROVE
安装工具,但先验证工具自己
推荐图形路径使用 STM32CubeIDE;课程交付包的命令行路径使用 Arm GNU Toolchain、Python 和 STM32CubeProgrammer。两条路径产物相同,命令行路径更适合读者复现。
P2.1 安装清单与版本记录
安装 STM32CubeIDE(建工程与调试)、STM32CubeProgrammer(烧录和校验)、Arm GNU Toolchain(编译)以及 Python 3.11 或 3.12(构建脚本和串口监视)。安装目录可以不同,但报告中必须记录实际版本。
POWERSHELL · VERIFY TOOLSarm-none-eabi-gcc --version python --version STM32_Programmer_CLI --version
P2.2 驱动与设备识别
用一根确认能传数据的 USB 线连接 ST‑LINK 端口。Windows 设备管理器应出现 ST‑LINK 与一个 COM 端口;Linux 可查看 lsusb 与 /dev/ttyACM*;macOS 可查看 /dev/cu.usbmodem*。只有充电功能的线会让电源灯亮,却不会枚举调试器。
P2.3 下载并检查实验包
下载后解压到不含管理员权限要求的普通目录。不要在 ZIP 内直接运行,也不要把作者路径复制进命令。先读 README 和 project.json,确认目标正是 NUCLEO‑G071RB/STM32G071RBT6。
P2.4 版本矩阵:先固定可复现条件
安装工具时最容易遗漏的是“版本”。同名工具的命令行参数、驱动行为和默认安装目录会随版本变化;同一板卡的硬件修订也可能改变 LED 或 VCP 的连接。为此建立一行版本矩阵:主机系统与架构、Python 版本、Arm GNU Toolchain 版本、STM32CubeProgrammer 版本、STM32CubeIDE 版本、板卡型号/修订、固件包提交或压缩包校验值、记录日期。矩阵不是形式主义,它让失败可以被比较。
稳定版本并不意味着永远不更新。读者可以使用课程锁定的版本完成第一次复现,再单独开一行尝试新版本;如果新版本成功,记录“兼容”;如果失败,保留旧行而不是覆盖。这样课程不会把某个作者电脑的 PATH 或缓存状态误当成必需条件。
| 字段 | 示例 | 为什么要记 |
|---|---|---|
| 主机 | Windows 11 x64 / Ubuntu 24.04 | 决定驱动、路径和设备名 |
| 编译器 | Arm GNU Toolchain 13.x 或锁定包 | 决定警告、链接和库行为 |
| 烧录器 | STM32CubeProgrammer 2.x | 决定连接参数与 verify 输出 |
| 目标 | NUCLEO-G071RB,板卡修订待抄写 | 决定映射、启动和供电条件 |
| 证据 | 命令输出、日志、压缩包 SHA-256 | 让另一台主机可以对照 |
P2.5 PATH、驱动与端口:逐项排除环境变量
“命令找不到”和“设备找不到”是两类不同故障。前者说明当前终端没有找到可执行文件,后者说明操作系统没有把 USB 设备映射出来;先把它们分开,才不会在没有驱动时反复改代码。Windows 可用 where 和设备管理器,Linux/macOS 可用 which、lsusb 或 ls /dev/cu.* /dev/ttyACM*。命令只用于观察,不要把输出中的作者路径复制进自己的脚本。
POWERSHELL / BASH · ENVIRONMENT PROBE# Windows where arm-none-eabi-gcc where STM32_Programmer_CLI python --version # Linux / macOS which arm-none-eabi-gcc which STM32_Programmer_CLI python3 --version
如果 where 返回多个版本,保留完整路径并决定哪个版本优先;如果串口号码每次变化,记录系统分配的名称和板卡序列号,不要把 COM5 写死成“所有读者都一样”。只有在调试器和串口都已稳定枚举后,才进入构建或烧录阶段。
运行上面的命令,把每一项标为“找到、多个、未找到”或“尚未连接”。故意不要安装额外软件来掩盖缺项;先写出下一步最小动作,例如重新打开终端、修正 PATH、换数据线或查看驱动。每次只做一个动作,再重复探针。
P2.6 干净目录复现:不依赖作者电脑
读者拿到 ZIP 后应先解压到自己的普通工作目录,再在目录内运行 README 给出的命令。路径尽量使用短路径和常见字符,避免把工程放在同步盘、压缩包内部或需要管理员权限的目录。若项目提供虚拟环境,虚拟环境只隔离 Python 依赖,不能代替 Arm 编译器、USB 驱动或 STM32CubeProgrammer;这几类依赖必须各自验证。
干净复现的关键是从“没有旧的 build/、没有旧的串口日志、没有临时生成文件”开始。运行 --clean 后保存首次输出;第二次重复构建可以用来判断是否有未声明的生成依赖。若第一次成功、删除构建目录后失败,优先检查脚本是否偷偷依赖缓存,而不是把差异归因于编译器随机性。
复制工程到一个全新的路径,删除 build/ 和本地日志,只保留仓库文件;写下从进入目录到工具探针的完整命令。另一位读者不应需要你的用户名、绝对路径、私有密钥或已经打开的 IDE 才能继续。
P3 · BUILD, FLASH, OBSERVE
从源码到 LED 和 UART
这一步建立课程的第一条完整证据链:源码能编译、产物能烧录、LED 能观察、UART 能记录;任何一项失败都能定位到具体阶段。
P3.1 干净构建
进入解压后的根目录,构建脚本会编译 CMSIS 启动文件、系统文件、板级代码和主程序,输出 ELF、HEX、BIN、MAP、size 与 JSON 构建报告。脚本不会下载隐藏依赖。
POWERSHELL / BASH · BUILDpython build_firmware.py --clean
通过标准:命令退出码为 0,build/ 内同时出现 .elf、.hex、.bin 和 .map。编译成功只证明产物生成,不证明板上行为。
P3.2 连接、烧录与校验
只连接一块 NUCLEO‑G071RB,关闭可能占用 ST‑LINK 的 IDE 会话,然后执行烧录脚本。脚本调用 STM32CubeProgrammer CLI,下载 HEX 并执行 verify;若连接失败,先检查板型、USB 线、驱动和占用程序。
POWERSHELL / BASH · FLASHpython flash_firmware.py
“File download complete”不是最终验收。verify 通过证明 Flash 内容一致,仍需观察复位后的输出。
P3.3 观察 LED 与 UART
复位后 LD4 应约每 500 ms 翻转一次。安装串口依赖后运行监视脚本,端口按实际 COM 或 tty 名替换。
SERIAL · 115200 8N1python -m pip install -r requirements-monitor.txt python monitor_serial.py --list python monitor_serial.py --port COM5
终端应周期出现启动信息和 tick 计数。LED 正常而串口空白时,优先检查端口、波特率和端口占用;串口正常而 LED 不亮时,检查板型与 PA5 映射。
P3.4 第一份可交付记录
保存工具版本、构建命令、build-report.json、烧录日志、串口原始文本、板卡标签照片和 LED 观察时长。结论应写成“在某板卡、某工具版本和某观察窗口内复现”,而不是“STM32 都能运行”。
P3.5 编译到底生成什么:从源文件到制品
一次固件构建不是“把 C 文件变成一个文件”。预处理器展开头文件和宏,编译器把每个翻译单元变成汇编或目标文件,汇编器生成机器码,链接器依据启动文件和链接脚本合并段并分配地址,最后工具把 ELF 转成适合下载的 HEX 或 BIN。每一阶段都有自己的失败方式:头文件缺失属于预处理/编译输入问题,未定义符号属于链接问题,地址越界属于内存布局问题,下载后无现象则已经进入目标机阶段。
| 制品 | 适合检查 | 读者应保存什么 |
|---|---|---|
| ELF | 符号、段、调试信息、入口 | 文件名与构建时间 |
| HEX/BIN | 实际下载的地址范围和字节 | 大小、校验值、下载日志 |
| MAP | Flash/RAM 分布、重复符号 | 关键段和剩余空间 |
| size/JSON 报告 | 构建是否达到脚本合同 | 退出码与完整原始输出 |
P3.6 读构建报告:让成功可被复查
构建退出码为 0 只能说明工具链没有报告错误。还要检查目标是否正确、入口符号是否存在、Flash 与 RAM 使用量是否在板卡限制内、产物是否由本次源码生成。对第一次实验,至少保存命令行、编译器版本、目标宏、产物大小和 build-report.json;报告里若有警告,不要用“最后生成了 HEX”把它们抹掉。
读者可以用文件时间和哈希值把构建与烧录对应起来:烧录日志引用的 HEX 应与刚刚生成的 HEX 是同一个文件。若改了源码却哈希值不变,先检查是否构建到了另一个目录;若产物变了但 MAP 中的目标芯片仍不对,停下来修正工程配置。可复查不是把日志堆在一起,而是让每一行日志能回答一个问题。
POWERSHELL / BASH · BUILD EVIDENCEpython build_firmware.py --clean python -c "import hashlib, pathlib; p=pathlib.Path('build/firmware.hex'); print(p, p.stat().st_size, hashlib.sha256(p.read_bytes()).hexdigest())" # Bash 可把第一行输出重定向到 build-output.txt
上面的哈希只证明文件内容可复查,不证明文件一定适合目标板;目标、地址和启动条件仍要由工程配置与 README 共同确认。
P3.7 一次改动一个变量:把构建和现象连起来
第一次上板不要同时改时钟、LED 引脚、串口波特率和业务逻辑。先保留已知成功版本,只改变一个可预测的量,例如把 LED 周期从 500 ms 改成 1000 ms;构建、烧录、复位和观察窗口都保持不变。若现象按预测变化,说明变量确实经过了源码、构建和目标机;若没有变化,检查你是否烧录了正确产物或观察了正确对象。
把“变慢了”写成可验收的输出:10 秒内约有 10 次边沿,UART 的 tick 计数仍单调递增,误差来自调度和观察分辨率。不要把人眼看到的闪烁频率当成精密计时器,也不要在尚未建立基准的情况下比较两台电脑的终端时间戳。
只改一个周期常量,保留原始 HEX、修改后的 HEX、构建报告和串口日志。记录“预期变化、实际变化、没有变化的部分、仍未知的部分”。如果没有目标板,先在主机模型里完成预测,并明确标记“目标机未执行”。
P4 · FAILURE MAP
失败时按阶段排查
初学者最容易把所有错误都叫作‘板子坏了’。真正可复现的路线要把安装、编译、连接、烧录、启动和观察分开。
P4.1 命令找不到
arm-none-eabi-gcc 找不到时,只修 PATH 或向脚本传入 --toolchain-dir;不要同时重装 IDE、换代码和换板。Python 找不到时确认命令名、版本与终端是否在安装后重开。
P4.2 能编译但连不上
确认 USB 接在 ST‑LINK 端、板卡供电灯正常、系统已枚举 ST‑LINK,并关闭其他占用程序。仍失败时保存 STM32CubeProgrammer 的完整连接日志,不盲目改变 reset mode 和频率。
P4.3 能烧录但没有现象
按下黑色复位键,观察 LD4 与串口。核对下载地址、verify 结果、板卡型号和串口映射。调试暂停会让 LED 停止;串口软件占用同一 COM 口会让监视脚本失败。
P4.4 完成标准
P4.5 故障树:先判定停在哪一层
排障的第一问不是“应该重装什么”,而是“最后一个已经证明的节点在哪里”。工具命令能执行,说明环境的一层通过;源码能编译,说明构建的一层通过;ST-LINK verify 通过,说明 Flash 内容的一层通过;复位后 LED/UART 符合合同,才是行为的一层通过。每层都需要自己的证据,不能用下一层的现象替代上一层的证据。
| 症状 | 优先检查 | 下一动作 | 停止条件 |
|---|---|---|---|
| 命令不存在 | PATH、版本、终端 | 保存探针输出 | 不改源码、不烧录 |
| 编译失败 | 首个错误、目标宏、目录 | 保留完整日志 | 不先改十处警告 |
| 无法连接 | USB 线、驱动、占用 | 重新枚举并记录 | 不盲改 reset/频率 |
| verify 通过但无输出 | 复位、映射、端口、波特率 | 分开观察 LED/UART | 不宣布“固件正确” |
P4.6 证据包:把一次失败交给别人
好的故障报告让别人可以从你的最后一个已知正常状态继续,而不是从“我试了很多次”开始猜。报告开头写对象和版本,随后按时间顺序写命令、原始输出、硬件连接、复位动作和观察窗口;最后单独列出已经排除的假设、尚未验证的假设和停止原因。截图可以辅助,但不能替代可复制的文本命令。
JSON · EVIDENCE RECORD{ "board": "NUCLEO-G071RB", "host": "Windows 11 x64", "last_proven": "build_exit_0", "next_check": "ST-LINK_enumeration", "input": "reset_then_wait_10s", "observed": "LD4_not_visible", "not_proven": ["flash_verify", "uart_output"], "stop_condition": "do_not_change_two_variables" }
字段可以按自己的工具改名,但不能省掉“未证明”。把失败保存下来并不会降低作品质量,反而说明你知道结论边界在哪里。
P4.7 迁移边界:先复制证据,再替换对象
完成基准板路径后,读者当然可以迁移到另一块 STM32、RP2040 或 ESP32,但迁移不是把工程文件夹改名。至少需要重新确认芯片型号和启动文件、Flash/RAM 地址、LED/按键/VCP 网络、供电和电平、调试器协议、串口设备名、工具版本与许可证。每替换一项,就重新跑一次构建—烧录—观察证据链。
迁移练习的目标不是让新板“一次成功”,而是让差异变得可解释:哪些代码是平台无关的,哪些是 HAL 或寄存器相关的,哪些输出在新板上没有等价物。若没有新板,读者可以只制作一份迁移表,不要把主机模型的通过当成目标机已经通过。
从启动地址、GPIO 映射、时钟、供电/电平、串口路径、下载器、观察方法中任选五项,分别写出“来源、验证动作、预期输出、失败时停止”。写不出验证动作的项目仍处于未知状态。
P5 · POWER AND ELECTRICAL LIMITS
先理解供电与电平,再接任何线
USB 供电能让第一次实验变简单,但不会让电气边界消失。本单元把供电入口、3.3 V 逻辑、共享地和停止条件讲清楚。
P5.1 唯一供电入口与回流路径
第一次实验只使用 NUCLEO-G071RB 的 ST-LINK USB 端口供电,并把它看成一条已经由板卡设计定义的路径:电脑 USB 提供能量,板载调试器负责枚举,板上电源网络再给目标 MCU 和板载器件供电。不要因为另一个连接器“也能插”就推断它适合作为并行电源;并行供电会引入电位差、回流和保护问题。
读原理图时沿着电源网络走,而不是只看连接器外形。记录 5 V、3.3 V、GND 和目标电源网名,标出哪些是输入、哪些是板上生成、哪些只在特定跳线状态下有效。若资料没有明确允许某种供电组合,就把组合列为未知并停在阅读阶段。
P5.2 3.3 V 逻辑与共享地
UART、GPIO、I2C 和 SPI 信号都需要共同参考点。两个设备即使各自测得“有电”,没有合适的 GND 也无法保证逻辑电平被正确解释。NUCLEO-G071RB 的目标 I/O 以 3.3 V 逻辑为基准,外接模块的电平、上拉电阻和未上电状态必须按双方手册核对;“能插上”不是电气兼容证明。
| 问题 | 要查的资料 | 未确认时的动作 |
|---|---|---|
| 电压范围 | 芯片数据手册、模块规格 | 不连接信号线 |
| 参考地 | 原理图、接口定义 | 先只做无源阅读 |
| 上拉/下拉 | 外设和板卡说明 | 不并联未知电源 |
| 未上电输入 | 绝对最大额定值 | 断开外部驱动 |
P5.3 安全停止练习:异常就是证据
发热、异味、供电灯异常、USB 反复断连、保护提示或电压读数超出预期,都应触发同一个停止动作:停止程序、断开 USB、保持连接现状、拍照或记录仪器设置,再回到最后一次确认安全的配置。不要用“再试一次”替代原因分析,也不要为了让 LED 亮起来短接未知引脚。
在纸上画出电脑 USB、ST-LINK、目标 MCU、GND、LED/UART 的关系,只允许使用已从手册确认的节点。用红色标出“没有来源就不能接”的线,用绿色标出第一次实验实际需要的线。照片或扫描件都可以作为学习记录。
P5.4 读供电图的简化方法
把一张原理图压缩成学习者能复核的三条线:能量从哪里来、参考地怎样回去、信号经过哪些保护或电平转换。先只追踪目标 MCU、ST-LINK、LED 和 VCP,暂时忽略与本次实验无关的扩展接口;当读者能解释这三条线,再逐步加入按键、传感器和外部电源。这个“先缩小再展开”的方法比一开始背整张图更适合初学者。
每条线旁边写出“来源”和“验收”。例如,USB 供电的来源是板卡手册,验收是供电指示与系统枚举;PA5 的信号来源是原理图,验收是 LD4 的可见变化;USART2 的观察来源是板卡连接说明,验收是 115200 8N1 下的可读文本。若来源只来自博客或照片,就把它降级为线索,不当作硬件合同。
P5.5 供电边界检查表
| 检查 | 是 | 否 |
|---|---|---|
| 目标板型号与手册一致 | 进入工具识别 | 停止并核对标签 |
| 唯一供电入口已确认 | 只接规定 USB | 不并行供电 |
| 信号双方电平已确认 | 按原理图接线 | 保持断开 |
| 异常停止条件已写下 | 准备记录 | 先补安全说明 |
选一个电压、参考地或未上电输入尚未确认的场景,写出为什么保持断开比试接更有信息价值。把“不知道”写成下一步资料和验证动作,而不是一句“应该没问题”。
P6 · PROGRAM AND RESET
烧录、复位、校验:三件事分开验收
下载工具报告完成,不代表固件已经按预期运行。本单元把 Flash 内容、复位过程和启动行为拆成三个可独立验证的阶段。
P6.1 连接调试器的最小条件
烧录前只保留一块目标板和一条数据线,关闭可能占用 ST-LINK 的 IDE 调试会话。确认板卡供电灯稳定、调试器已被系统枚举、目标型号与工程一致;若工具支持自动识别,仍要把识别结果写入日志。连接参数越多越不是越专业,第一次应从默认、低风险、可解释的设置开始。
P6.2 下载与 verify 的命令合同
烧录命令至少要表达四个意图:选择哪个目标、写入哪个产物、是否擦除、写入后怎样校验。课程脚本将这些意图封装起来,读者也应能在日志中看见实际调用的文件和 verify 结果。若下载成功但校验失败,结论只能写“Flash 内容尚未确认”,不要继续观察 LED 来掩盖校验问题。
POWERSHELL / BASH · PROGRAM CONTRACTpython flash_firmware.py --input build/firmware.hex --verify # 等价的图形路径:选择目标型号 -> 载入同一 HEX -> Download -> Verify -> Reset
不同版本的 STM32CubeProgrammer 参数名可能不同,先运行 --help 并以锁定版本的 README 为准;不要把网上另一型号的地址参数直接套用。
P6.3 复位不是重新插拔
复位会让 MCU 从启动地址重新执行,而拔插 USB 还会改变供电、调试器枚举和串口设备状态。观察行为时优先使用板上复位键或工具提供的 reset,再记录复位后的时间点。若固件在调试暂停状态,LED 计时可能停止;若串口监视器先于复位打开,日志顺序也可能不同。
分别写出“下载工具连接通过”“Flash verify 通过”“复位后行为通过”各自需要的证据。故意不要把三句合并成一个“烧录成功”;若第三句没有证据,标记为未完成。
P6.4 烧录地址与启动模式
HEX 文件包含地址信息,BIN 文件通常只是连续字节;它们不能互换成“随便下载都一样”。工程的链接脚本、启动文件和芯片型号共同决定代码应放到哪里,启动模式又决定复位后从用户 Flash、系统存储器还是其他入口开始执行。第一次实验只使用工程已经验证过的产物和默认启动配置,不要拿另一颗芯片的地址参数做尝试。
如果 verify 通过却没有行为,先把“Flash 字节正确”和“CPU 从这些字节启动”分开。检查复位状态、启动脚配置、向量表入口和是否被调试器暂停;每一步都保存工具输出。没有这些证据时,最稳妥的结论是“写入完成,启动尚未证明”。
P6.5 烧录回滚与已知正常版本
每次修改都保留一个已知正常版本的 HEX 和哈希。新版本出现异常时,先按同一命令回滚并验证,确认是代码差异还是连接/供电条件差异;回滚不是删除失败证据,而是建立对照组。对照组应使用同一板卡、同一端口、同一复位方式和相同观察窗口,避免一次又改变多个变量。
记录旧产物哈希、新产物哈希、烧录时间、verify 结果、复位动作和 LED/UART 观察。若需要回滚,写出回滚后哪一条证据恢复,以及仍未解释的差异。
P7 · OBSERVE AND REPORT
用 LED 与 UART 看见固件正在工作
目标机实验的输出必须能被另一位读者观察和记录。LED 提供低门槛现象,UART 提供带时间和计数的文本证据,两者相互补充但不能互相替代。
P7.1 LED:现象与测量不是一回事
人眼能判断 LED 是否有规律变化,却不适合精确测量 500 ms 的边沿时间。先把验收写成窗口,例如“复位后 2 秒内开始变化,连续 10 秒至少看到若干次稳定翻转”;若要验证抖动、占空比或低功耗唤醒,再使用示波器或逻辑分析仪,并记录采样率、参考地和探头条件。LED 正常只能证明某个输出路径可见,不代表所有 GPIO、时钟或任务调度都正确。
P7.2 UART:把行为变成文本证据
课程串口路径固定为 USART2 的虚拟串口,默认 115200、8 数据位、无校验、1 停止位(115200 8N1)。打开终端时选择系统实际分配的端口,关闭其他会独占该端口的软件;若乱码,优先检查波特率、数据位、换行和复位时刻。启动信息应包含固件版本或构建标识,tick 计数应单调递增,错误事件应带有可区分的标签。
EXPECTED SERIAL OUTPUTboot: nucleo-g071rb led-uart v1 board: STM32G071RBT6 uart: USART2 115200 8N1 led: PA5 active-high tick=001 state=ON tick=002 state=OFF
示例输出是格式合同,不保证每台电脑的接收时间戳相同。保留原始文本并注明端口、波特率、复位方式和观察时长,才能与另一位读者的记录比较。
P7.3 日志与交付:把“我看到了”变成“可复查”
一次完整记录至少包含:对象卡、工具版本矩阵、构建命令和报告、烧录与 verify 日志、串口原始文本、LED 观察窗口、一个失败或未执行字段。主机 Python 模型可以帮助预测 tick、解析串口文本和自动测试,但它不产生目标机已经发光或已经输出的证据。没有板卡时照样可以完成模型部分,并把目标机字段明确写成“未执行”。
用同一版本固件完成一次记录,至少保存 10 秒 UART 原文或“未连接”的原因、LED 观察窗口、构建产物哈希和一个不能推出的结论。请另一位读者只看这份记录,判断他还缺少哪一个条件。
P7.4 最小串口解码:先看帧,再看业务
串口窗口里出现的每个字符都经过了多个条件:目标端 TX 引脚、VCP 转换、USB 驱动、终端端口、波特率、数据位、校验、停止位和换行约定。排错时先确认原始字节或可见 ASCII,再讨论“业务状态是否正确”。乱码、缺行、重复行和延迟各自指向不同层次,不能统称为“串口不稳定”。
PYTHON · HOST-SIDE LINE CHECKexpected = ["boot:", "board:", "uart:", "tick="] def check_lines(lines): missing = [prefix for prefix in expected if not any(line.startswith(prefix) for line in lines)] return {"missing": missing, "ok": not missing}
这个主机检查只验证文本格式是否符合约定,不能证明目标板的 TX 电平、VCP 芯片和时序;它与目标机日志应分开归档。
P7.5 观察窗口与重复次数
“看到一次”通常不足以支持周期性行为。为 LED 和 UART 预先规定观察窗口、最少重复次数、允许的启动延迟和异常判定。例如复位后先等待启动文本,再在 10 秒内检查至少若干个连续 tick;若窗口内没有完整启动序列,记录缺失位置并停止,不要通过延长窗口把偶发输出变成通过。
写明何时复位、何时开始计时、看 LED 什么现象、收 UART 哪些行、允许几次丢失、遇到乱码如何处理。没有目标板时,提交协议和主机样例,并标注目标机未执行。