← 返回嵌入式学习资料第 4 章 · GPIO、按键与状态机

CHAPTER 4 · GPIO AND FSM

GPIO、按键与状态机
让引脚行为可预测

从电平、方向、复用和负载开始,追踪输入采样、输出极性、按键去抖和非阻塞状态机;把主机模型、目标机电气事实和安全停止条件明确分开。

6 个一级单元49 个递进小节主机路径可复现

TEXTBOOK MAP

CHAPTER 4 · MAP

从焊盘电平到状态机交付

六个一级单元对应六种能力:理解电气、核对复用、解释读写、过滤按键、设计状态、交付证据。

先把引脚当作真实接口
  • 01 GPIO 电气模型
  • 02 复用与安全配置
再把输入输出变成事件
  • 03 读写路径与极性
  • 04 按键采样与去抖
最后把行为做成可移交系统
  • 05 非阻塞状态机
  • 06 GPIO 证据与交付

小节数量按认知任务变化:电气、去抖和交付需要更多递进步骤;每个单元都保留无目标机主机路径。

使用方式:先从左侧选择一个 GPIO 认知,再按电气、配置、读写、去抖、状态和交付推进。每个单元底部有前后翻页;小节标题直接说明正在追踪的引脚、样本、事件或状态。
主机边界:默认使用标准库模型、C 源文件和事件序列;没有目标板也能完成电平判断、pin manifest、去抖重放和状态机测试。
目标机边界:真实电压、阈值、负载、复用、毛刺、供电、接线和恢复必须回到当前芯片、板卡、原理图和工具链的官方资料。

01 · GPIO ELECTRICAL MODEL

GPIO 电气模型:电平、方向与负载边界

GPIO 不是屏幕上的一个布尔变量,而是焊盘、输入缓冲器、输出驱动、上拉下拉、供电域、外部负载和软件配置共同组成的电气接口。本单元先建立电平、方向、源灌电流和安全边界,再进入寄存器与状态机。

看懂读懂引脚在电路中的角色。
说清把逻辑值和电气条件分开。
开始做为安全测量留下可复核证据。
官方基线UM2324 STM32 Nucleo-64 boards用于核对课程基准板的供电、跳线、LED、按键和虚拟串口映射。锁定:Rev 5 · 核对日期:2026-09-05

4.1.1 GPIO 是焊盘与软件之间的合同

GPIO 的‘值’至少有三层:软件写入的逻辑值、输入缓冲器采样到的逻辑值,以及焊盘上经过负载和保护结构后的电压。三层可能一致,也可能因为输出使能、外部冲突、上拉阻值或电源域状态而不同。记录一个 1 时要注明它属于哪一层。

4.1.2 高、低、电源域与阈值不是同一个词

VIH/VIL 是输入识别的边界,VOH/VOL 是输出在规定电流下能够保证的边界。它们不是把电压轴切成绝对完美的二分线;落在未定义区的信号不能用一次偶然读数证明稳定。不同电源电压、温度和输入模式还可能改变有效条件。

C · LOGIC LEVEL WINDOW
#include <stdbool.h> static bool input_is_high(float voltage, float vih) { return voltage >= vih; }

模型只练习阈值判断;VIH/VIL、供电和温度必须按当前器件电气参数核对。

C · ACTIVE-LOW OUTPUT
#include <stdbool.h> static unsigned led_level(bool on) { return on ? 0u : 1u; }

active-low 只是软件语义转换,不能代替原理图、负载和焊盘电压证据。

4.1.3 推挽与开漏:谁在主动驱动这根线

推挽输出会主动拉高或拉低,开漏输出通常只主动拉低,拉高依赖外部或内部上拉。把两个推挽输出直接相连会形成争用,可能超出绝对最大额定值;开漏共享也需要确认上拉、电平和上升时间。GPIO 配置是电气安全的一部分。

表 1 · GPIO 电气模型:电平、方向与负载边界的证据判断表
层次应留下的证据不能直接推出
软件值锁存/采样自动等于焊盘电压
电气值阈值/负载/电流任何 0/1 都安全
证据参数/原理图/波形截图可替代条件

4.1.4 源电流、灌电流和 LED 极性

LED 亮灭经常是 active-low:引脚拉低时电流从电源经过 LED 流入 MCU,软件写 0 却看到灯亮。不要用变量名 led_on 推断极性,应从原理图、板卡手册和电压/电流测量确认。源电流与灌电流的额定值也不能只看一个总电流数字。

4.1.5 输入漏电、上拉下拉与浮空

内部上拉下拉适合定义默认状态,却有阻值范围、漏电、功耗和速度限制。按键线开路时,输入可能因手指、电缆、邻近信号或测量探头而变化。把‘没有按下’写成一个电压窗口、采样时间和连接条件,才是可复现的输入合同。

图 1.1 · GPIO 电气模型:电平、方向与负载边界的判断路径每一格都要有自己的条件。
输入阈值与漏电
输出驱动与负载
连接电源与保护
证据波形与读数

从左到右是思考顺序,不是把电气、软件和目标机证据合并成一个“通过”。

4.1.6 5 V 容忍、电平转换与保护结构

某些引脚标注 5 V tolerant 只在指定模式、电源状态和复用条件下成立,模拟模式、关闭 I/O 电源或相邻功能可能有额外限制。外部电压未知时先断电并查当前器件数据手册;保护二极管导通不等于可以长期把电流灌进芯片。

4.1.7 逻辑值、物理电平和板载指示的三层证据

一个可靠的 GPIO 结论同时需要软件配置、芯片电气参数、板卡连接和实际观察。寄存器读回可能只反映输出锁存器,不等于焊盘电平;万用表平均值也可能看不出快速边沿。证据要注明带宽、采样位置、负载和时间窗口。

4.1.8 本节交付:一张 GPIO 电气卡

电气卡的字段可以复用到每个外设:引脚身份、供电域、默认状态、输入阈值、输出能力、外部负载、极性、风险和验证方法。下一单元配置复用功能时,先把这张卡中的未知项清零,不能用‘默认 GPIO’替代当前芯片的复位状态。

CHECKPOINT 4.1把“一个引脚为什么能读到高低电平,又为什么可能把板子推向危险状态?”写成一份可复查记录

请围绕“GPIO 电气模型:电平、方向与负载边界”写出对象、输入或电气条件、配置/状态机制、输出、一个约束、一个失败路径和对应证据。没有目标板时,运行主机路径并把未执行字段标为未执行;拥有目标机时,也要补齐芯片、封装、板卡、供电、引脚、工具链、观察条件和恢复方式。不要用一次 LED 亮起或一个寄存器截图覆盖没有做过的验证。

合格记录要让没有现场上下文的读者知道先查什么、先运行什么、看到什么才算通过,以及哪一句结论仍然不能推出。未知项和停止条件不是扣分项,而是交付的一部分。

02 · PIN CONFIGURATION

引脚配置:复用、上下拉与输出能力

引脚配置不是写一个 mode 字段就结束。复用选择、方向、上下拉、输出类型、速度/驱动能力、初始锁存值和切换瞬间的毛刺共同决定外部世界看到什么。本单元用配置表和原子切换顺序把‘引脚已经准备好’拆成可检查动作。

看懂读懂复用与配置寄存器。
说清设计无毛刺的初始化顺序。
开始做把引脚表变成可维护交付物。
官方基线RM0444 STM32G0x1 reference manual寄存器、复位值、时序和外设边界以本参考手册修订版为准。锁定:Rev 6 · 核对日期:2026-09-05

4.2.1 引脚身份:端口、编号与封装脚

一个引脚至少有四个身份:芯片端口与编号、封装物理脚、板卡网络名、应用信号名。数据手册和原理图连接这四层,软件 manifest 再把它们与极性、默认态和复用功能绑定。只写 PA5 或‘LED_PIN’都不足以让另一位读者复查。

4.2.2 复用功能:一个焊盘的多份候选工作

复用选择通常由端口模式位和若干 alternate-function 位共同决定,编号不是跨厂商通用。某些引脚还受调试接口、启动配置、模拟开关或安全控制器占用。每次迁移到另一颗 MCU,都必须重新查封装、复用表和复位默认态。

C · PIN MANIFEST
typedef struct { unsigned port; unsigned pin; unsigned alternate; unsigned pull; unsigned active_level; } pin_spec_t;

结构体记录意图;端口编号、复用值、拉阻和复位态仍需当前芯片资料。

C · SAFE INITIALIZATION
void configure_output(void) { gpio_write_latch(0u); gpio_set_type(PUSH_PULL); gpio_set_pull(NONE); gpio_set_direction(OUTPUT); }

顺序用于讨论无毛刺合同;实际 API、写入原子性和外部负载必须按厂商实现验证。

4.2.3 先写安全锁存值,再打开输出使能

安全初始化常见顺序是:确认电源和外部连接,写输出锁存器的安全值,配置方向/类型/上下拉,再选择复用或打开输出使能,最后用测量或读回验证。对于会驱动继电器、电机或高亮 LED 的脚,启动毛刺本身就是行为错误。

表 2 · 引脚配置:复用、上下拉与输出能力的证据判断表
层次应留下的证据不能直接推出
身份芯片脚/板网/功能信号名就是引脚
初始化安全锁存→配置→使能写 mode 就无毛刺
并发掩码/原子/所有权整端口随便改

4.2.4 上下拉、开漏与驱动能力的配置字段

上下拉的选择要看外部电阻、线长、速度、功耗和断电状态。开漏总线需要确认所有参与者不会主动拉高;推挽输出则要确认没有第二个驱动者。驱动能力或速度设置过高可能增加 EMI 和边沿振铃,过低又可能违反建立时间。

4.2.5 端口寄存器的读改写与原子置位

端口寄存器的读改写包括读旧值、修改、写回三个阶段,中断或 DMA 在中间改变另一个位就可能被覆盖。芯片提供 SET/CLR/TOGGLE 寄存器时,应优先使用原子接口;没有原子接口时再用临界区或明确的所有权合同。

图 2.1 · 引脚配置:复用、上下拉与输出能力的判断路径每一格都要有自己的条件。
身份端口/引脚/复用
默认复位与安全态
配置方向/拉阻/驱动
切换原子与证据

从左到右是思考顺序,不是把电气、软件和目标机证据合并成一个“通过”。

4.2.6 复用切换时的瞬间状态

复用切换不是瞬时的抽象动作。锁存值、输出使能、复用开关和外设状态可能在不同总线周期生效,外部设备可能把这个窗口当作一个真实脉冲。对片选、复位、闸门和中断脚,应定义切换前后的安全电平与最大毛刺宽度。

4.2.7 配置错误为什么会像软件逻辑错误

‘按键读不到’可能来自引脚身份、复用、方向、上下拉、极性、供电或采样代码中的任一层。最小定位顺序应先确认原理图和封装,再读配置寄存器,随后用示波器/万用表看焊盘,最后才修改状态机。

4.2.8 本节交付:可审查的 pin manifest

pin manifest 建议包含 chip_pin、package_pin、board_net、function、mode、pull、drive、active_level、reset_state、owner、source 和验证方式。它既可以是 JSON,也可以生成头文件;关键是让配置值、物理资料和测试输入互相引用。

CHECKPOINT 4.2把“同一个物理引脚怎样在 GPIO、串口和定时器功能之间安全切换?”写成一份可复查记录

请围绕“引脚配置:复用、上下拉与输出能力”写出对象、输入或电气条件、配置/状态机制、输出、一个约束、一个失败路径和对应证据。没有目标板时,运行主机路径并把未执行字段标为未执行;拥有目标机时,也要补齐芯片、封装、板卡、供电、引脚、工具链、观察条件和恢复方式。不要用一次 LED 亮起或一个寄存器截图覆盖没有做过的验证。

合格记录要让没有现场上下文的读者知道先查什么、先运行什么、看到什么才算通过,以及哪一句结论仍然不能推出。未知项和停止条件不是扣分项,而是交付的一部分。

03 · GPIO DATA PATH

读写路径:采样、输出与极性

GPIO 数据路径包含输入采样寄存器、输出锁存器、焊盘状态、同步器和外部负载。读哪个寄存器、写哪个寄存器、是否需要屏障、active-high 还是 active-low,都会改变结论。本单元把数据路径画出来,再把原子更新与可观察行为连接起来。

看懂区分锁存值与焊盘读值。
说清设计无竞争的读写接口。
开始做用极性和时序解释现象。
官方基线RM0444 STM32G0x1 reference manual寄存器、复位值、时序和外设边界以本参考手册修订版为准。锁定:Rev 6 · 核对日期:2026-09-05

4.3.1 读输入寄存器还是读输出锁存器

有些端口提供输入数据寄存器、输出数据寄存器和真实焊盘读回位;有些芯片的读回语义又受模式影响。读取输出锁存器只能说明软件最后写了什么,读取 pad 才可能看到外部冲突或负载结果。接口命名应把这两个对象明确区分。

4.3.2 同步器、采样延迟与边沿观察

外部按键或传感器输入通常先经过同步器,采样值可能比焊盘边沿晚几个时钟。轮询周期、同步延迟和脉冲宽度共同决定是否能观察到事件;示波器看到一个脉冲而软件没有看到,并不自动证明代码丢失了中断。

C · MASKED SET/CLEAR
void led_set(bool on) { if (on) GPIO_SET = LED_MASK; else GPIO_CLEAR = LED_MASK; }

SET/CLR 是否存在、写入宽度和可见时序由芯片参考手册决定。

C · INPUT SEMANTICS
bool button_pressed(void) { const bool raw = (GPIO_INPUT & BUTTON_MASK) != 0u; return BUTTON_ACTIVE_HIGH ? raw : !raw; }

接口隐藏极性但保留原始值;同步延迟、去抖和外部电平仍是独立条件。

4.3.3 active-high 与 active-low 的接口设计

active-low 的正确做法是把物理层转换放在边界函数中,例如 `button_pressed()` 返回‘按下’语义,`led_set(on)` 内部处理反相。这样状态机不用到处写 `!level`,测试也能分别覆盖极性。原始电平仍应在证据记录中保存。

表 3 · 读写路径:采样、输出与极性的证据判断表
层次应留下的证据不能直接推出
读取pad/采样/同步输出锁存就是外部状态
写入SET/CLR/可见性RMW 永远安全
语义极性/时间/所有权变量名可证明极性

4.3.4 掩码写入与端口所有权

端口所有权要写到 bit 级:一个驱动负责片选,另一个负责 LED,是否允许整端口写入?如果没有所有权,任何 `port = value` 都可能覆盖别人的位。掩码、SET/CLR 或锁保护可以把并发合同变成可执行规则。

4.3.5 SET/CLR/TOGGLE 与读改写竞争

RMW 的典型丢更新是:主循环读端口、ISR 修改另一位、主循环把旧快照写回。SET/CLR/TOGGLE 让修改只作用于目标位,或把端口更新集中到一个所有者。修复时应保存并发上下文、时间和两次写入的原始证据。

图 3.1 · 读写路径:采样、输出与极性的判断路径每一格都要有自己的条件。
输入pad→同步→采样
输出锁存→驱动→负载
接口掩码与原子
行为极性与时间

从左到右是思考顺序,不是把电气、软件和目标机证据合并成一个“通过”。

4.3.6 写入顺序、屏障与外部设备看到的时间

总线写入可能先进入写缓冲,外设或外部设备在下一个动作前未必已经看到它。需要屏障时,应按架构和芯片手册使用;屏障不能替代等待外设状态位,也不能把一个错误的时序合同变成正确。波形是最直接的时间证据。

4.3.7 错误读写的证据链

定位读写错误可以按四层走:源码 API 的对象,寄存器位的语义,编译后的访问宽度/顺序,焊盘和负载的波形。只看最后一层会漏掉极性,只看第一层会漏掉复用和外部冲突。每层都应记录已排除的条件。

4.3.8 本节交付:GPIO 数据路径卡

GPIO 数据路径卡至少包含 read_source、write_target、mask、active_level、sampling_period、write_visibility、owner 和 evidence。它是去抖器与状态机的输入合同:上层只接收‘按下事件’或‘输出已请求’,不再猜寄存器细节。

CHECKPOINT 4.3把“软件读写的每一个 0/1,怎样对应到真实的输入采样和输出动作?”写成一份可复查记录

请围绕“读写路径:采样、输出与极性”写出对象、输入或电气条件、配置/状态机制、输出、一个约束、一个失败路径和对应证据。没有目标板时,运行主机路径并把未执行字段标为未执行;拥有目标机时,也要补齐芯片、封装、板卡、供电、引脚、工具链、观察条件和恢复方式。不要用一次 LED 亮起或一个寄存器截图覆盖没有做过的验证。

合格记录要让没有现场上下文的读者知道先查什么、先运行什么、看到什么才算通过,以及哪一句结论仍然不能推出。未知项和停止条件不是扣分项,而是交付的一部分。

04 · BUTTON DEBOUNCE

按键与去抖:把抖动变成一次事件

机械触点在闭合和释放时会抖动,线路还会受到上拉、电缆、EMI 和采样时钟影响。去抖不是简单延时,而是用时间、连续样本和状态记忆把物理波形转换为一次可解释事件。本单元从波形到过滤器,再到延迟与误触发预算。

看懂用时间窗口解释按键抖动。
说清实现非阻塞去抖模型。
开始做为误触发和响应延迟设预算。
官方基线STM32CubeG0课程设备支持、启动代码与示例的锁定来源;链接指向固定 tag。锁定:v1.6.3 · 核对日期:2026-09-05

4.4.1 触点抖动是一个时间问题

机械按键的抖动波形可能在几百微秒到数十毫秒范围内变化,具体数值取决于器件、老化、按压力度和电路。不要把某个博客的 20 ms 当作芯片事实;先测量或明确采用的工程假设,再把窗口作为可调整参数。

4.4.2 采样周期决定能看到什么

轮询周期太长会漏掉短按,太短则增加 CPU 唤醒和日志量;边沿中断能捕获开始,却不能直接分辨抖动和稳定按下。采样器需要一个时间基准,且时间基准本身要有时钟误差和低功耗暂停的说明。

C · STABLE SAMPLE
typedef struct { unsigned stable; bool candidate; bool state; } debounce_t; static bool debounce_step(debounce_t *d, bool sample, unsigned limit) { if (sample != d->candidate) { d->candidate = sample; d->stable = 0u; } if (d->stable < limit) ++d->stable; if (d->stable >= limit) d->state = d->candidate; return d->state; }

模型用于主机重放;limit 与采样周期要由真实按键波形和响应预算决定。

C · EDGE EVENT
bool pressed_event(bool previous, bool current) { return !previous && current; }

事件应建立在稳定状态上;这段代码不负责触点抖动、队列满和时间戳。

4.4.3 连续稳定计数过滤器

连续稳定计数的规则是:样本与候选状态相同就累加,不同就重置或改变候选;达到阈值才发布状态事件。阈值乘采样周期给出最小延迟,但释放和按下可以使用不同阈值,形成迟滞以减少边界抖动。

表 4 · 按键与去抖:把抖动变成一次事件的证据判断表
层次应留下的证据不能直接推出
原始触点/噪声/周期一次动作一个样本
过滤连续/积分/迟滞固定 delay 覆盖所有情况
事件按下/释放/长按每轮循环都发 pressed

4.4.4 积分器与迟滞:不是只有一种去抖

积分器把样本映射为向上/向下的置信度,双阈值再把置信度转换为稳定状态。它适合噪声较多的输入,但要记录饱和范围、初值和复位行为。选择算法不能只看代码行数,还要比较响应、功耗、误触发和可解释性。

4.4.5 按下、释放、长按与重复事件

事件接口应区分 pressed、released、long_press 和 repeat;一个稳定状态只能生成一次 pressed,不能每次循环都重复。长按计时从稳定按下开始,释放应取消未完成的长按。事件队列满、系统休眠或复位时的丢失策略也要写明。

图 4.1 · 按键与去抖:把抖动变成一次事件的判断路径每一格都要有自己的条件。
波形触点抖动
采样周期与时间
过滤计数/迟滞
事件按下/释放

从左到右是思考顺序,不是把电气、软件和目标机证据合并成一个“通过”。

4.4.6 非阻塞去抖与主循环时间预算

阻塞式延时会停止其他 GPIO、通信、看门狗和安全任务,按键看似稳定,系统却失去可预测性。非阻塞去抖每次只处理一个样本,把状态放在结构体里,循环或定时器按 deadline 调度。执行时间和最大间隔都应进入预算。

4.4.7 用原始样本复盘误触发

误触发复盘要保留原始采样序列而不只保留‘发生了一次按下’。至少记录单调时间、原始电平、候选状态、稳定计数、发布事件、软件版本和采样周期。这样可以在主机上重放同一序列,判断问题属于物理波形还是过滤规则。

4.4.8 本节交付:一个可测试的按键合同

按键合同应让上层看到清楚的输入、时间窗、事件语义、错误和未知。目标机没有示波器时,仍可先在主机重放样本序列;但主机通过不等于触点、上拉和 EMI 已在板上验证,页面必须保留这条边界。

CHECKPOINT 4.4把“一个机械按键的一次按下,为什么会在软件里看起来像十几次?”写成一份可复查记录

请围绕“按键与去抖:把抖动变成一次事件”写出对象、输入或电气条件、配置/状态机制、输出、一个约束、一个失败路径和对应证据。没有目标板时,运行主机路径并把未执行字段标为未执行;拥有目标机时,也要补齐芯片、封装、板卡、供电、引脚、工具链、观察条件和恢复方式。不要用一次 LED 亮起或一个寄存器截图覆盖没有做过的验证。

合格记录要让没有现场上下文的读者知道先查什么、先运行什么、看到什么才算通过,以及哪一句结论仍然不能推出。未知项和停止条件不是扣分项,而是交付的一部分。

05 · NON-BLOCKING FSM

非阻塞状态机:让 GPIO 行为可预测

有限状态机把输入事件、当前状态、动作和下一个状态分开。它比在主循环里堆叠 delay、布尔变量和隐式分支更容易测试,也更容易说明超时、恢复和未知输入。本单元从状态图开始,落到可运行的非阻塞 C 模型。

看懂画出状态和事件边界。
说清写出不阻塞的状态转移。
开始做把超时与故障纳入行为合同。
官方基线STM32CubeG0课程设备支持、启动代码与示例的锁定来源;链接指向固定 tag。锁定:v1.6.3 · 核对日期:2026-09-05

4.5.1 状态、事件与动作的三分法

状态表示系统当前承诺,事件表示一次发生的事实,动作表示改变外部世界或记录证据的操作。持续为低的按键不是每轮循环一个新事件;只有经过去抖的上升/下降语义才应触发转移。三者混在一起会制造重复动作和隐式状态。

4.5.2 从状态图到转移表

转移表比一段嵌套 if 更适合审查,因为每个状态和事件组合都能看到守卫、输出和下一状态。表中也应有 default 行,说明未知事件、非法状态和缺失时间戳如何处理。状态数量可以不同,但遗漏的组合不能靠‘代码应该不会走到’来掩盖。

C · NON-BLOCKING FSM
typedef enum { IDLE, ACTIVE, FAULT } state_t; state_t step(state_t state, event_t event, uint32_t now) { switch (state) { case IDLE: return event == PRESSED ? ACTIVE : IDLE; case ACTIVE: return event == TIMEOUT ? IDLE : ACTIVE; default: return FAULT; } }

示例展示显式状态和默认分支;tick 溢出、输出动作和真实时间基准仍需工程定义。

C · DEADLINE CHECK
static bool deadline_reached(uint32_t now, uint32_t deadline) { return (int32_t)(now - deadline) >= 0; }

无符号 tick 的比较要按目标整数宽度和溢出规则验证,不能把主机时间函数直接当作硬件 tick。

4.5.3 tick、deadline 与非阻塞等待

单调 tick 只提供时间参照,不会自动保证时钟准确或任务按时运行。deadline 判断要处理溢出,周期动作要说明抖动和最大调度间隔。闪烁 LED 可以容忍几十毫秒,安全输出或通信超时可能需要更严格的预算。

表 5 · 非阻塞状态机:让 GPIO 行为可预测的证据判断表
层次应留下的证据不能直接推出
输入事件与时间持续电平就是事件
状态合同与历史布尔变量越多越清晰
输出动作/故障/恢复default 可以忽略

4.5.4 进入动作、持续动作与退出动作

进入动作适合设置一次安全输出和记录时间,持续动作适合在每轮检查 deadline,退出动作适合清理或发布事件。动作最好幂等,重复调用不会增加脉冲或重置计时器;若动作必须只执行一次,就用显式 entry/exit 处理而不是依赖调用顺序猜测。

4.5.5 默认分支与未知事件

默认分支不是把问题吞掉。未知事件可以计数并忽略,非法状态可以保存快照后进入故障态,涉及危险输出时应优先关闭驱动。记录原因码、状态值、最后事件和固件版本,下一次启动才有机会解释为什么进入默认分支。

图 5.1 · 非阻塞状态机:让 GPIO 行为可预测的判断路径每一格都要有自己的条件。
输入事件与时间
状态当前合同
转移守卫与动作
输出GPIO/证据

从左到右是思考顺序,不是把电气、软件和目标机证据合并成一个“通过”。

4.5.6 故障态、恢复和人工确认

恢复策略分为自动清除、有限重试、降级运行、人工确认和受控复位。GPIO 短路、过流或外部急停不能仅凭软件状态判断已经安全;状态机应先关闭输出、等待条件恢复,再按次数和时间窗决定下一步。

4.5.7 状态机的测试证据

主机测试可以把事件序列和 tick 作为输入,断言状态、输出请求、进入时间和故障原因。测试要覆盖边界:恰好到 deadline、重复 pressed、未知事件、tick 溢出和队列丢失。目标机还要增加波形、供电和复位证据,不能把模型覆盖当成硬件覆盖。

4.5.8 本节交付:一张 GPIO 行为状态图

行为状态图的交付字段包括状态定义、事件来源、时间基准、输出极性、进入/持续/退出动作、异常分支、恢复上限和证据。它会成为定时器、通信和 RTOS 章节的共同语言,减少每个驱动各自发明一套隐式流程。

CHECKPOINT 4.5把“怎样把按键、LED、超时和故障组合成不会互相卡住的控制流?”写成一份可复查记录

请围绕“非阻塞状态机:让 GPIO 行为可预测”写出对象、输入或电气条件、配置/状态机制、输出、一个约束、一个失败路径和对应证据。没有目标板时,运行主机路径并把未执行字段标为未执行;拥有目标机时,也要补齐芯片、封装、板卡、供电、引脚、工具链、观察条件和恢复方式。不要用一次 LED 亮起或一个寄存器截图覆盖没有做过的验证。

合格记录要让没有现场上下文的读者知道先查什么、先运行什么、看到什么才算通过,以及哪一句结论仍然不能推出。未知项和停止条件不是扣分项,而是交付的一部分。

06 · GPIO DELIVERY

GPIO 交付:从 pin map 到可复查行为

GPIO 交付不是一张‘LED 已点亮’的截图,而是能从干净目录复查的对象包:芯片与板卡身份、pin manifest、电气约束、初始化代码、去抖模型、状态图、主机测试、目标机波形和未验证边界都彼此链接。本单元把前五个单元收束为可移交记录。

看懂建立 GPIO 证据包。
说清分离主机模型与目标机事实。
开始做用单变量实验维护行为合同。
官方基线STM32CubeG0课程设备支持、启动代码与示例的锁定来源;链接指向固定 tag。锁定:v1.6.3 · 核对日期:2026-09-05

4.6.1 证据包最小集合

GPIO 证据包应能回答:这根线在什么芯片和板卡上、复位时是什么状态、谁拥有它、外部负载是什么、软件如何配置、输入如何采样、事件如何去抖、状态机如何输出、目标机看到了什么。缺少任何一层时,结论要降级为模型或待核对。

4.6.2 目标身份与资料版本

目标身份至少包括芯片完整料号与修订、封装、板卡版本、供电方式、调试器、工具链目标和资料访问日期。‘STM32’或‘GPIOA’不是充分身份;不同器件的复用、耐压、寄存器和板载网络都可能不同。

PYTHON · EVENT REPLAY
from dataclasses import dataclass @dataclass class Sample: tick: int raw: int for sample in [Sample(0, 0), Sample(1, 1), Sample(2, 1)]: print(sample.tick, sample.raw)

脚本只重放样本和记录,不会测量目标板电平、负载或波形。

SHELL · GPIO EVIDENCE
arm-none-eabi-size build/firmware.elf arm-none-eabi-objdump -h -t build/firmware.elf > build/gpio.sections.txt sha256sum build/firmware.elf build/gpio.sections.txt

目标工具链未安装时继续完成主机路径;命令、版本和输出文件必须写入交付记录。

4.6.3 pin manifest 与原理图交叉核对

pin manifest 与原理图交叉核对时,先确认板卡网络名,再追到封装脚和端口编号,最后查复用与复位默认值。若资料出现冲突,保留原始页面/图号和冲突字段,不要用软件命名强行覆盖硬件事实。

表 6 · GPIO 交付:从 pin map 到可复查行为的证据判断表
层次应留下的证据不能直接推出
对象身份/电气/pin map板载名称已足够
主机样本/模型/测试通过即证明硬件
目标波形/日志/限制一张截图交付全部

4.6.4 主机路径:重放按键与状态机

没有开发板时,读者仍可用主机模型重放按键序列、测试去抖、验证状态转移、阅读 C 配置和填写证据模板。必须明确未测量电平、负载、电流、毛刺、复用和 EMI;主机输出只能证明抽象输入下的算法行为。

4.6.5 目标机路径:安全上电与测量

目标机上电前要确认低压供电、地线、限流、接线、探头负载和可恢复固件路径。未知电压、未确认 5 V 容忍、两个输出相连或外部模块没有共地时停止。安全测量比‘先烧进去看看’更重要。

图 6.1 · GPIO 交付:从 pin map 到可复查行为的判断路径每一格都要有自己的条件。
身份芯片/板卡/pin
配置电气与复用
行为去抖/FSM
交付测试/波形/限制

从左到右是思考顺序,不是把电气、软件和目标机证据合并成一个“通过”。

4.6.6 波形、日志与状态转移对齐

把波形和日志对齐需要统一时间参考:采样 tick、事件时间、状态进入时间、GPIO 翻转标记和示波器触发点。若日志延迟、串口阻塞或调试 halt 改变时序,要在记录里标出,不能把两个时间轴直接比较。

4.6.7 单变量 GPIO 回归

单变量回归可以改变 active level、一个 pull、采样周期或一个状态转移,但不能同时换板、换引脚、换过滤器和换时钟。先预测 pin 电压、事件次数、状态和波形哪一项变化,再保存差异与限制。

4.6.8 资料卡:HAL、Zephyr、Linux 与 ESP-IDF

HAL 往往隐藏寄存器细节,Zephyr 通过 devicetree 和 gpio_dt_spec 提供可移植描述,Linux 新驱动偏向 gpiod 描述符,ESP-IDF 的 GPIO API 又有芯片特定的输入限制。抽象层能统一调用方式,却不能替代当前芯片的电气参数和板卡连接。

4.6.9 本章结业:交给定时器章节的接口

交给定时器章节的接口包括:GPIO 输出的安全默认态、输入采样周期、事件时间戳、状态机 tick 需求、故障/恢复字段和仍未验证的电气条件。后续讨论时间精度时,应从这份 GPIO 记录中的真实预算开始,而不是重新假设引脚行为。

CHECKPOINT 4.6把“怎样把引脚表、按键波形、状态机和目标机证据交给下一位读者?”写成一份可复查记录

请围绕“GPIO 交付:从 pin map 到可复查行为”写出对象、输入或电气条件、配置/状态机制、输出、一个约束、一个失败路径和对应证据。没有目标板时,运行主机路径并把未执行字段标为未执行;拥有目标机时,也要补齐芯片、封装、板卡、供电、引脚、工具链、观察条件和恢复方式。不要用一次 LED 亮起或一个寄存器截图覆盖没有做过的验证。

合格记录要让没有现场上下文的读者知道先查什么、先运行什么、看到什么才算通过,以及哪一句结论仍然不能推出。未知项和停止条件不是扣分项,而是交付的一部分。

资料卡(访问日期:2026-09-03):ST HAL、Zephyr、Linux gpiod 和 ESP-IDF 文档支撑不同生态的 GPIO 抽象;ST UM3256 支撑具体 Nucleo 板卡对象核对。通用 API 不能替代当前芯片的电气参数、复用表、原理图和目标机测量;本站的主机/目标机边界是教学解释。