系列总览:Zig 裸机开发的定位、生态与平台全景
本篇是《Zig 裸机开发实战:STM32F103ZET6 全栈解析》系列第 1 篇。下一篇:开发环境搭建:Zig 0.17、microzig 与 probe-rs,目录见文末。
系列总览:Zig 裸机开发的定位、生态与平台全景
导读
这是一套写给"会 C 单片机、想用 Zig 做裸机"的工程师的教程。我们不假设你写过 Zig,但假设你知道什么是寄存器、时钟树、中断优先级和 PWM——这些概念在 C 的世界里你已经用过,现在的问题是:换一门语言,这些经验还能剩下多少?
这一篇不写代码,只回答三个问题:
- Zig 在裸机开发里到底卖什么?代价是什么?
- microzig 是什么、不是什么?它的 HAL 能力边界在哪里?
- 为什么选 STM32F103ZET6 这颗 2007 年架构的老芯片,而不是人人皆知的 Blue Pill?
先给出全系列的观点立场,方便你决定要不要继续读:Zig 在裸机上的真正卖点不是语法糖,而是"零成本 + 编译期计算 + 内置交叉编译";代价是生态薄弱、标准库面向操作系统的部分完全不可用、上游 HAL 仍有 bug。 本系列会明确写出哪些地方必须退回寄存器层、哪些地方必须自己补,而不是假装一切开箱即用。
为什么需要 Zig 裸机开发
Zig 的四个卖点
卖点一:自带 LLVM 与 lld,交叉编译零依赖。 Zig 的工具链是一个 55 MB 左右的压缩包,解压即用。它内置 LLVM 后端和 lld 链接器,zig build 直接产出 thumb-freestanding-eabi 目标的 ARM ELF。不需要 arm-none-eabi-gcc,不需要装 ld、objcopy,不需要配置 sysroot。对 C 老手来说,这意味着"新同事入职第一天从装工具链到点灯"的体验。实测同一个最小固件:Debug 构建约 357 KB(带 DWARF 与回溯),ReleaseSmall 构建只有 644 字节——工具链本身不给你塞任何运行时。
卖点二:comptime,编译期计算是一等公民。 寄存器访问器、按芯片名选引脚、时钟树分频计算,都可以在编译期完成。这不是 C 模板或宏的模仿者:comptime 代码就是普通 Zig 代码,用普通 if/for 写,编译器只是把参数换成编译期已知值再跑一遍。本系列会反复用到这个特性:microzig 的时钟配置 rcc.apply(config) 参数就是 comptime 的,时钟树在编译期算完,运行期只剩几条 store 指令。
卖点三:错误联合类型替代返回码。 read_blocking(buf, timeout) ReceiveError!usize 这个签名把"可能出什么错、返回什么"写进了类型系统。C 里靠 int 返回值和 errno 约定,负数是错误、非负是长度,调用方忘了检查编译器不吭声;Zig 里 try 一路向上传播,catch |e| 强制你面对它。裸机场景下这直接消灭了"返回值没检查导致超时被当成数据长度"这类经典 bug。
卖点四:没有隐式控制流。 没有运算符重载,没有构造/析构函数,没有异常展开,没有隐式类型转换(u16 传给要 u32 的参数必须显式转换)。你看到的赋值就是赋值,看到的函数调用就是调用。对资源极度敏感的裸机代码来说,这意味着固件体积和时序是可推理的——toggle() 就是读改写一次 ODR,不会在背后藏一个虚函数表。
Zig 的三个代价
代价一:生态薄。 协议栈(lwIP、TinyUSB、FatFs)、RTOS(FreeRTOS、Zephyr)、厂商 SDK(CubeMX)全是 C。Zig 侧没有 defmt(Rust 生态的编译期日志框架),没有认证级 RTOS,GitHub 上 Zig 嵌入式项目数量比 C 少两三个数量级。现实做法是"纯逻辑用 Zig 写,协议栈与认证组件继续用 C",Zig 0.17 移除了 @cImport,引 C 头文件要走 translate-c 独立包或手写 extern 声明——门槛比以前高了。
代价二:std 面向操作系统。 std.fs.cwd()、std.process.argsAlloc 在 0.17 已经移除;std.debug.print 和默认的 std.log 在 freestanding 目标下会拉进 std.Io.Threaded 与 std.posix,直接编译失败。裸机上能放心用的 std 子集是:std.mem、std.fmt(bufPrint/comptimePrint)、std.math 纯函数、std.atomic,外加自定义 logFn 之后的 std.log。这个边界每一篇都会用到。
代价三:语言未到 1.0。 Zig 0.15 删除了 async/await,0.17 移除了 @cImport,把 @intFromEnum 弃用为 @backingInt,数组乘法 a ** b 换成了 @splat。每一个版本都有破坏性变更,网上 90% 的 microzig 教程写于 0.11–0.14 时代,API 已经完全不能用。本系列所有代码以 Zig 0.17.0 与 MicroZig 0.17.26 源码为准,并在每一篇的"常见问题"里列出老写法与新写法的对照。
一句话总结取舍:如果你要的是生态和开箱即用,留在 C;如果你要的是编译期可检查的抽象、单一工具链、以及"读代码就能确信它没有隐藏开销",Zig 值得一试。
为什么需要 microzig
裸机 Zig 不是只有 microzig 一条路——你可以手写链接脚本、手写向量表、手写 .data/.bss 初始化(本系列第 05 篇会演示这个底层)。但每次换芯片都要重做一遍这些 plumbing,于是有了 microzig:ZigEmbeddedGroup 维护的嵌入式工具链,当前版本 0.17.26,明确要求 Zig 0.17.0 严格配套。
microzig 的定位要讲精确,它不是三样东西:
- 不是 RTOS。 它的
concurrency模块全文只有 162 行,只提供一个原子位集合AtomicStaticBitSet。没有任务、没有调度器、没有信号量。它自带的 FreeRTOS 封装目前只支持 RP2040/RP2350,F103 上不可用。 - 不是 HAL 标准。 它没有"HAL 规范",每个芯片的 HAL 是独立实现,能力参差不齐。F103 的 HAL 里没有 CAN、没有内部 Flash 编程、没有 DAC、没有看门狗、没有低功耗进入函数——这些外设芯片明明有,microzig 就是不提供。
- 不是操作系统抽象。 没有多任务、没有内存管理,它交付的就是"能跑在裸金属上的最小运行时"。
它是的东西可以概括为四件套:芯片描述(1372 个 STM32 型号的寄存器与内存映射数据)+ 启动代码(向量表、.data 拷贝、.bss 清零、_start 入口)+ 由 regz 工具按型号生成的寄存器定义(PAC 层)+ 部分外设的 HAL(F103 上有 gpio/rcc/uart/i2c/spi/adc/dma/timer/exti/rtc 等 17 个模块)。你可以只用前三件,把 HAL 当成"可参考、可绕过"的实现样本——这正是本系列第 05、06 篇的做法。
能力边界的诚实清单(本系列会逐一展开):
| 你可能以为有 | F103 HAL 的实际状态 | 替代方案 |
|---|---|---|
hal.can |
不存在 | 第 28 篇寄存器直写 bxCAN |
| 内部 Flash 编程 | 不存在 | 第 17 篇直接操作 FLASH 外设 |
hal.dac、hal.iwdg、hal.wwdg |
不存在 | 寄存器层 |
pin.set_high() / set_low() |
不存在,只有 put(value: u1) |
put(1) / put(0) |
time.sleep_ns() |
不存在 | sleep_us(n / 1000) |
| UART 中断/DMA API | 不存在 | 第 12 篇寄存器直写 RXNEIE |
power.enter_stop() |
不存在 | power.apply + microzig.cpu.wfi() |
为什么选 STM32F103ZET6
F103ZET6 参数表
| 项目 | 参数 |
|---|---|
| 内核 | ARM Cortex-M3,r1p1 版本,3 级流水 |
| 主频 | 72 MHz(1.25 DMIPS/MHz) |
| Flash | 512 KB,2 KB/页,共 256 页,起始 0x08000000(microzig 区域名 BANK_1) |
| SRAM | 64 KB,起始 0x20000000(区域名 SRAM) |
| 封装 | LQFP144 |
| GPIO | 112 个(PA–PG 七个端口各 16 位) |
| ADC | 3 × 12 位,最多 21 通道 |
| DAC | 2 × 12 位 |
| USART | 5 个(USART1/2/3 + UART4/5) |
| SPI | 3 个 |
| I2C | 2 个 |
| CAN | 1 × CAN 2.0B |
| USB | USB 2.0 Full Speed Device |
| DMA | DMA1 7 通道 + DMA2 5 通道 |
| 其它 | SDIO、FSMC、CRC 单元、96 位唯一 ID、RTC + 备份寄存器、独立/窗口看门狗 |
这是 ST 的"高密度"(high-density)型号:在人人熟悉的 Blue Pill(F103C8,64 KB Flash / 20 KB RAM / LQFP48)之上,把外设全数展开。Cortex-M3 r1p1 虽然是 2007 年的架构,但它是全世界资料最丰富的 32 位 MCU 之一,RM0008 参考手册 1100 多页把每个寄存器都写透了——这对"教寄存器层"是巨大的优势。
为什么不是 Blue Pill
三个原因。第一,引脚和外设数量。F103ZET6 的 112 个 GPIO、5 个 USART、3 个 SPI 才能演示 FSMC、多串口、双 ADC 同步这类"大芯片"话题;C8 的 48 脚根本接不下本系列的 I2C OLED + SPI Flash + ADC 电位器 + 捕获回环 + USB + CAN 全部实验。第二,512 KB / 64 KB 的余量。我们要在中后期手写 RTOS 内核、跑 lwIP 级别的实验,20 KB RAM 的 C8 连一个像样的日志缓冲都挤不出来。第三,也是最有教学价值的一点:ZET6 有 PE/PF/PG 三个端口,而 microzig 的 F103 GPIO HAL 在这三个端口上有一个上游 bug——gpio.Pin.get_port() 对 GPIOE/F/G 返回的是 GPIOA(源码 hals/STM32F103/gpio.zig 第 102–104 行,三个 case 全部写成了 peripherals.GPIOA)。用 HAL 操作 PE5 会静默点亮 PA5,不报任何错。这对只有 PA/PB/PC 的 C8 用户无感,对 ZET6 用户是硬伤。本系列的策略是:HAL 示例只用 PA/PB/PC;PE/PF/PG 留到第 05 篇用寄存器层演示——bug 反而成了"为什么你需要懂寄存器"的最好论据。
接线约定
全系列按统一接线表做实验,读者照表接线即可复现,不依赖板载 LED 丝印:
| 功能 | 引脚 | 配置 |
|---|---|---|
| LED1 | PB5 | 推挽输出(第 10 篇复用为 TIM3_CH2 PWM) |
| LED2 | PC0 | 推挽输出 |
| KEY1 | PA0 | 下拉输入 + EXTI0 上升沿 |
| USART1 | PA9 / PA10 | AF 推挽 / 浮空输入,115200 8N1 |
| I2C1 | PB6 / PB7 | AF 开漏 + 4.7 kΩ 上拉 |
| SPI1 | PA5/PA6/PA7 + PA4 | AF 推挽 / 浮空 / AF 推挽 + 软件片选 |
| ADC1_IN1 | PA1 | 模拟输入 |
| TIM2_CH4 | PA3 | 浮空输入(捕获) |
| USB | PA11 / PA12 | D+ 需外部 1.5 kΩ 上拉 |
| CAN | PB8 / PB9 | AF 推挽(RX 浮空) |
| SWD | PA13 / PA14 | ST-Link V2 |
| BOOT0 | 接地 | 从主 Flash 启动 |
代码案例:三方对比
选语言不是选宗教,是选工程权衡。下表把 Zig(microzig)、C(HAL 库 / 寄存器)、Embedded Rust(embassy / stm32-hal)放在同一张表里,逐维度比较。评价基于本系列的实际调研:microzig 0.17.26 全量源码、ST HAL 库的使用经验、以及 embassy 的公开文档。
| 维度 | C + ST HAL / 寄存器 | Zig + microzig | Embedded Rust (embassy) |
|---|---|---|---|
| 学习曲线 | 最低,资料最多(RM0008 + 二十年教程) | 中:语言新概念(comptime、错误联合)+ 生态资料少 | 中高:借用检查 + async 是双重新范式 |
| 生态 | 最厚:CubeMX、FreeRTOS、lwIP、全部认证组件 | 薄:协议栈靠 C,无成熟 RTOS | 中:embassy 异步框架活跃,驱动 crate 多 |
| 实时能力 | 任意,从裸循环到 RTOS | 任意,但 RTOS 要手写(第 25–26 篇) | 异步执行器 + 中断,抢占式 RTOS 不在主线 |
| 工具链 | arm-none-eabi-gcc + OpenOCD/CubeProgrammer | 单一 zig 包,自带 LLVM/lld | rustup + cargo + probe-rs(体验最好) |
| 安全网 | 无(UB 满天飞,靠 MISRA 与纪律) | 中:越界/溢出 Debug 下 panic,无数据竞争检查(单核裸机) | 最强:编译期内存安全 |
| 团队接受度 | 最高,招人最容易 | 低:语言未 1.0,面试官认知少 | 中:概念可迁移,但招聘仍难 |
| 固件体积 | 小(可控) | 小(ReleaseSmall 激进裁剪) | 中(async 状态机有固定开销) |
三个诚实的结论:教寄存器和体系结构,C 依然是第一语言——本系列的电路与寄存器讲解会大量引用 C 世界的成熟资料。Zig 的比较优势在"编译期生成 + 类型化错误":comptime 时钟树、错误联合的串口 API,这些在 C 里要么靠宏要么靠约定。Rust 的比较优势在安全性,但代价是所有权模型对中断共享数据的表达(Mutex<RefCell<...>>)比 Zig 的"裸 volatile + 临界区"陡峭得多。如果你维护的是要过认证的产品,今天的答案仍然是 C;如果你在做个人项目、原型、或者想借新语言重学一遍单片机底层,Zig 是性价比很高的选择。
逐段解析:系列三条主线与阅读路径
本系列 30 篇,三条主线交织:
语言线(第 01、21 篇为主,贯穿全部):Zig 0.17 的语言特性如何映射到裸机——comptime 生成寄存器访问、错误联合替代返回码、defer/errdefer 管理外设生命周期、packed struct 描述寄存器位域、0.17 的破坏性变更清单。
平台线(第 02–20、27–29 篇):STM32F103ZET6 的硬件细节,按"先跑通、再讲透"排序:环境与构建系统(02–03)→ 启动与点灯(04–05)→ GPIO/时钟/中断/串口/定时器(06–10)→ 输入捕获与中断驱动串口(11–12)→ DMA/I2C/SPI/ADC/Flash/看门狗/低功耗/内存布局(13–20)→ USB/CAN/调试(27–29)。
系统线(第 22–26 篇):实时系统的核心问题——中断与主循环的竞态、临界区、可重入性;协作式调度器与状态机;中断延迟测量;最后手写一个基于 PendSV 的抢占式 RTOS 内核(任务控制块、上下文切换汇编、信号量、优先级继承)。
建议的阅读路径有三条:
- 快速上手线(1 个周末):02 → 03 → 04 → 09。装好环境、看懂构建、点灯、串口打日志。
- 系统学习线(按顺序读):01 → 30 全顺序。每一篇的代码都建立在前一篇的概念上。
- 查阅线:每篇文末的"面试考点"与"常见问题"可以独立阅读;第 03 篇的构建系统解析、第 05 篇的 volatile 语义、第 08 篇的中断三层覆盖模型,是全系列被引用最多的三块基石。
两个贯穿全系列的写作约定。第一,所有代码针对 Zig 0.17.0 + MicroZig 0.17.26,目标写法只有一种:stm32.chips.STM32F103ZE(microzig 没有 F103ZE 的 board 定义,只有 6 块 F3/F4/L4 板,所以 microzig.board 是 void,不能访问任何板级字段)。第二,凡是上游源码里确认不了的 API 一律不写;凡是有 bug 的地方(PE/PF/PG 端口映射、PWM invert 死字段、NVIC 优先级写法、DMA 100 字节缓冲)都明确指出并给出绕过方案。
运行现象
本篇是总览,没有固件可跑。但为了让你对"终点"有感觉,这里预告第 04 篇的最终形态:约 30 行 Zig 源码,zig build 产出不到 1 KB 的 ELF,烧进 ZET6 后 PB5 上的 LED 以 100 ms 周期闪烁。同样的代码在 Debug 模式下 ELF 会膨胀到几百 KB——工具链对你的默认假设是"调试优先",-Doptimize=ReleaseSmall 才是固件的出厂形态。这个体积落差本身就是 Zig 工具链哲学的一个缩影:默认给你全部诊断能力,让你显式选择放弃它们。
常见问题
Q1:Zig 什么时候到 1.0?现在投入学习会不会白费?
成因:Zig 官方从未承诺 1.0 时间表,且每个版本都有破坏性变更(0.15 删 async、0.16 弃用 @cImport、0.17 改内建函数名)。解决方案:把"语言演进"和"概念投资"分开算。指针、volatile 语义、时钟树、中断向量、链接脚本这些概念在任何语言里都一样,学一遍终身受用;Zig 特有的 comptime 与错误联合即使语法再变,思想也会保留(0.17 把 @intFromEnum 改名 @backingInt 时,旧名只是弃用而非删除,zig fmt 还能自动迁移)。工程上锁定版本(0.17.0 配 0.17.26)即可把风险关在笼子里。
Q2:microzig 是官方的东西吗?会不会弃坑?
成因:它是 ZigEmbeddedGroup(社区组织)维护的开源项目,不是 ST 官方产品。解决方案:把它当成"高质量的参考实现 + 生成器"而不是"平台"。寄存器定义来自 embassy 的 stm32-data 数据(业界维护最勤的 STM32 数据源之一),启动代码不到两千行且源码可读——即使项目停更,你拿到的所有部件都能自己维护。本系列刻意教你读它的源码(哪一行生成向量表、哪一行算波特率),就是为了让你不依赖任何单一项目的存续。
Q3:Cortex-M3 r1p1 是 2007 年的核,学它过时吗?
成因:新 MCU(M33/M55、RISC-V)确实在普及。解决方案:Cortex-M3 恰恰是"教学最优密度"的核——它有 NVIC、PendSV、SysTick、位带这些现代 Cortex-M 的全部核心机制,又没有 TrustZone/FPU/双核的额外复杂度。你在 M3 上手写的 RTOS 上下文切换(第 25 篇),移植到 M4/M33 只需要处理 FPU 栈帧和安全扩展,核心逻辑一字不变。片上外设层面,F103 的 USART/SPI/I2C/TIM 寄存器风格(v1 外设)是 ST 后来所有系列的祖先,RM0008 读懂了,F4/H7 的手册只是换名字。
Q4:为什么不用 Zephyr 或 RT-Thread 配 Zig 写应用?
成因:这两个 RTOS 都是 C 实现,Zig 调 C 需要 translate-c 独立包(0.17 已删 @cImport),且 RTOS 的线程模型与 Zig 的无运行时设计没有天然契合点。解决方案:如果项目已经绑定某个 RTOS,把 Zig 用于纯逻辑模块(协议解析、状态机、CRC)是可行的,用 extern 声明对接 RTOS API;但本系列选择另一条路——前 23 篇不用任何 RTOS,第 25–26 篇直接手写一个能跑的内核。手写的意义不是替代 FreeRTOS,而是把"上下文切换到底发生了什么"变成你亲手写过的 60 行汇编。
Q5:F103ZET6 核心板和最小系统板有区别吗?买哪块?
成因:市面上两种板都有,核心板(LQFP144 全引脚引出 + 双排针)和"大红板"之类最小系统引脚较少。解决方案:买核心板,且确认三点——板载 8 MHz 晶振(本系列时钟配置全部按 8 MHz 计算)、BOOT0 有跳线可接地、SWD 排针包含 3.3V/GND/SWDIO/SWCLK/NRST 五根。板上自带 LED 的话注意它接在哪个脚(常见 PB5/PE5/PC13),本系列统一外接 LED 到 PB5 与 PC0,与板载灯不冲突。
Q6:系列里的代码能直接用在产品上吗?
成因:教程代码以"讲清楚"为第一目标,没有做产品化处理(无看门狗、无错误恢复全路径、无静态分析)。解决方案:把教程代码当骨架,产品化时补三件事——ReleaseSmall 之外再加 .asserts = true 让 microzig.assert 生效(第 29 篇详述)、给所有阻塞调用加超时参数、把第 18 篇的独立看门狗接进主循环。上游 HAL 的已知 bug 清单(PE/PF/PG 映射、I2C write_then_read、DMA 100 字节限制)在对应篇章都有绕过代码,发布前逐条核对。
面试考点
Q1:Zig 相比 C,在裸机开发中最有价值的三个特性是什么?各自的代价是什么?
参考答案:一是 comptime——编译期执行普通代码生成常量与类型,让寄存器访问器和时钟树计算零运行时开销,代价是编译时间增加且错误信息有时难读;二是错误联合类型,把错误集写进函数签名,try/catch 强制处理,代价是与 C 库对接时要做错误映射;三是零隐式控制流(无运算符重载、无构造析构、无隐式转换),让固件时序可推理,代价是代码更啰嗦、缺少 C 里"顺手"的表达。同时必须说出代价的另一面:生态薄、std 面向 OS 的部分(fs/process/默认日志)在 freestanding 下不可用或已移除、语言未 1.0 有破坏性变更。
Q2:microzig 在嵌入式 Zig 生态中的定位是什么?它不提供什么?
参考答案:定位是"芯片描述 + 启动运行时 + 按型号生成的寄存器层(regz 从 embassy stm32-data 生成)+ 部分外设 HAL"的组装器,通过 MicroBuild 构建接口把这几件按目标芯片拼成一个固件工程。它不提供 RTOS(concurrency 模块只有原子位集合)、不提供统一的 HAL 规范(各芯片能力参差,F103 没有 CAN/Flash/DAC/看门狗/低功耗 API)、不提供烧录工具(microzig 本身没有 flash 命令,要配 probe-rs 或 OpenOCD)。评价一个嵌入式框架时,"它不做什么"和"它做什么"同样重要。
Q3:为什么本系列选 STM32F103ZET6 而不是更流行的 Blue Pill(F103C8)?这个选择暴露了 microzig 的什么问题?
参考答案:三点——引脚与外设全(112 GPIO、5 USART、3 SPI、2 DAC、FSMC,能撑起 30 篇实验);存储余量大(512 KB Flash / 64 KB RAM,够手写 RTOS 与日志缓冲);有 PE/PF/PG 端口,而 microzig 的 F103 GPIO HAL 有一个上游 bug:Pin.get_port() 对端口序号 4/5/6(E/F/G)返回的是 GPIOA,用 HAL 操作这 48 个引脚会静默写错端口。这暴露了"microzig 的 HAL 对非主流引脚覆盖不足、且示例只用 C8/CB 验证"的现实——大容量芯片用户必须懂寄存器层才能绕过,这正是把 ZET6 选作教学平台的价值。
Q4:对比 C、Zig、Rust 三种语言的嵌入式生态,各自的"不可替代点"是什么?
参考答案:C 的不可替代点是认证与人力——MISRA、功能安全认证的 RTOS(FreeRTOS/ThreadX)、二十年积累的厂商 SDK 与工程师池,短期没有替代者。Zig 的不可替代点是"编译期计算 + 单一工具链"的组合——comptime 让同一份代码在不同芯片上生成不同实现(microzig 的时钟树、引脚配置都靠它),工具链一个压缩包自带 LLVM/lld 交叉编译,CI 配置几乎为零。Rust 的不可替代点是编译期内存安全——所有权系统把"中断与主循环共享数据"这类并发错误挡在编译期,embassy 的异步执行器也最成熟。三者当前的现实分工:C 承接产品,Rust 承接安全关键的新项目,Zig 承接学习、原型与工具。
Q5:std.debug.print 在 STM32 固件里能直接用吗?为什么?
参考答案:不能。0.17 的 std.debug.print 和默认 std.log 的 logFn 都需要一个 stderr writer,它由 std.Io.Threaded 提供,而 Threaded 依赖线程与系统调用(epoll/getrandom 等),在 freestanding 目标下链接失败,报错指向 std/Io/Threaded.zig 的 posix 依赖,与用户代码无关。正确做法是在根文件写 pub const std_options = microzig.std_options(.{ .logFn = stm32.uart.log });,把日志重定向到 UART,再在 main 里 stm32.uart.init_logger(&uart)。这是 Zig "std 面向 OS"这一代价最具体的体现。
小结
- Zig 裸机的四个卖点:自带 LLVM/lld 的零依赖交叉编译、comptime 编译期计算、错误联合类型、无隐式控制流;三个代价:生态薄、std 面向 OS、语言未 1.0。
- microzig 0.17.26 是"芯片描述 + 启动代码 + regz 生成寄存器 + 部分外设 HAL"的组装器,不是 RTOS、不是 HAL 标准;F103 HAL 缺 CAN/Flash/DAC/看门狗/低功耗 API,边界必须记清。
- F103ZET6:Cortex-M3 r1p1 / 72 MHz / 512 KB Flash / 64 KB SRAM / LQFP144 / 112 GPIO / 3 ADC / 5 USART / 3 SPI / 2 I2C / 1 CAN / USB FS / DMA1+DMA2 共 12 通道。
- 选 ZET6 的第三个理由最有教学价值:PE/PF/PG 会踩中上游
get_port()返回 GPIOA 的 bug,正好逼出寄存器层。 - 全系列三条主线:语言、平台、系统;下一篇开始动手装环境。
系列目录
- 系列总览:Zig 裸机开发的定位、生态与平台全景
- 开发环境搭建:Zig 0.17、microzig 与 probe-rs
- 工程结构剖析:build.zig、MicroBuild 与固件产物
- 第一个固件:启动流程、向量表与 GPIO 点灯
- 寄存器级编程:PAC、MMIO 与 volatile 语义
- GPIO 子系统:输入输出模式、上下拉与端口映射陷阱
- 时钟树配置:HSE、PLL 与总线分频
- 中断系统:NVIC、优先级分组与向量注册
- USART 串口通信:轮询收发与日志重定向
- 定时器基础:时基、PWM 与呼吸灯
- 输入捕获:频率与占空比测量
- 中断驱动串口:环形缓冲区与临界区设计
- DMA 传输:从外设搬运到内存
- I2C 总线:SSD1306 OLED 显示实战
- SPI 总线:W25Q64 Flash 读写与 ID 识别
- ADC 采样:单次、扫描与内部温度传感器
- 内部 Flash 编程:参数持久化与页擦除
- 独立看门狗:复位诊断与可靠性设计
- 低功耗模式:Sleep、Stop、Standby 与唤醒
- 内存布局与链接脚本:512 KB Flash 与 64 KB RAM 规划
- Zig 语言进阶:comptime、错误处理与零成本抽象
- 并发模型:中断与主循环的协作与临界区
- 协作式调度器:状态机与时间片轮转
- 实时性分析:中断延迟、抖动与 WCET
- RTOS 内核实现(上):任务控制块与上下文切换
- RTOS 内核实现(下):信号量、消息队列与优先级继承
- USB 设备开发:CDC 虚拟串口
- CAN 总线:bxCAN 过滤器与环回自测
- 调试与测试:probe-rs、RTT 与硬件在环
- 收官:分层架构、可移植性与 Zig 生态展望

浙公网安备 33010602011771号