Pārlūkot izejas kodu

ingest: 尚硅谷STM32 基础篇笔记导入(01~06)

OpenCode 2 dienas atpakaļ
vecāks
revīzija
65520c9699
19 mainītis faili ar 3077 papildinājumiem un 0 dzēšanām
  1. 295 0
      X-Knowledge-Base/raw/Joplin/嵌入式+Linux/STM32学习笔记/01-STM32概述与开发环境搭建.md
  2. 445 0
      X-Knowledge-Base/raw/Joplin/嵌入式+Linux/STM32学习笔记/02-GPIO寄存器详解与三步进化法.md
  3. 463 0
      X-Knowledge-Base/raw/Joplin/嵌入式+Linux/STM32学习笔记/03-GPIO输出:LED控制.md
  4. 287 0
      X-Knowledge-Base/raw/Joplin/嵌入式+Linux/STM32学习笔记/04-GPIO输入与NVIC中断系统.md
  5. 223 0
      X-Knowledge-Base/raw/Joplin/嵌入式+Linux/STM32学习笔记/05-系统时钟RCC详解.md
  6. 369 0
      X-Knowledge-Base/raw/Joplin/嵌入式+Linux/STM32学习笔记/06-串口USART通信.md
  7. BIN
      X-Knowledge-Base/raw/Joplin/嵌入式+Linux/STM32学习笔记/assets/gpio_内部结构.png
  8. BIN
      X-Knowledge-Base/raw/Joplin/嵌入式+Linux/STM32学习笔记/assets/gpio_端口布局.png
  9. BIN
      X-Knowledge-Base/raw/Joplin/嵌入式+Linux/STM32学习笔记/assets/led_电路原理图.png
  10. BIN
      X-Knowledge-Base/raw/Joplin/嵌入式+Linux/STM32学习笔记/assets/stm32f103zet6_复位电路.png
  11. BIN
      X-Knowledge-Base/raw/Joplin/嵌入式+Linux/STM32学习笔记/assets/stm32f103zet6_开发板实物图.png
  12. BIN
      X-Knowledge-Base/raw/Joplin/嵌入式+Linux/STM32学习笔记/assets/stm32f103zet6_时钟电路.png
  13. BIN
      X-Knowledge-Base/raw/Joplin/嵌入式+Linux/STM32学习笔记/assets/stm32f103zet6_电源电路.png
  14. BIN
      X-Knowledge-Base/raw/Joplin/嵌入式+Linux/STM32学习笔记/assets/stm32f103zet6_芯片引脚图.png
  15. BIN
      X-Knowledge-Base/raw/Joplin/嵌入式+Linux/STM32学习笔记/assets/stm32f103zet6_调试接口.png
  16. 18 0
      X-Knowledge-Base/wiki/log.md
  17. 24 0
      X-Knowledge-Base/wiki/source-stm32-basic.md
  18. 788 0
      docs/superpowers/plans/2026-07-15-stm32-ingest.md
  19. 165 0
      docs/superpowers/specs/2026-07-15-stm32-silicon-valley-ingest-design.md

+ 295 - 0
X-Knowledge-Base/raw/Joplin/嵌入式+Linux/STM32学习笔记/01-STM32概述与开发环境搭建.md

@@ -0,0 +1,295 @@
+---
+tags: [source-summary]
+type: source
+source: "尚硅谷嵌入式技术之STM32单片机(基础篇)V1.0.2 — 第1~3章:STM32概述、开发工具、开发板与最小系统"
+author: "尚硅谷研究院"
+date: 2026-07-15
+created: 2026-07-15
+---
+
+# STM32概述与开发环境搭建
+
+> **用生活理解**:如果把 STM32 比作一台微型电脑——ARM Cortex-M3 内核就像 CPU,Keil MDK 就是 Visual Studio,开发板就是一台迷你主机,最小系统相当于电脑能开机的最低配置(主板 + CPU + 内存 + 电源)。
+
+---
+
+## STM32概述
+
+### 关于ARM内核
+
+ARM(Advanced RISC Machines)是一家英国芯片设计公司,只出售**知识产权(IP)授权**,不生产芯片。ST(意法半导体)购买了 ARM 的 IP 授权,在 Cortex-M3 内核基础上添加自己的外设(GPIO、USART、I2C、CAN 等),造出了 STM32 系列 MCU。
+
+> **参考**:《Cortex-M3 权威指南》第2章 — Cortex-M3 内核架构
+
+ARM Cortex-M3 核心特性:
+- 32位 RISC 处理器(一次处理 32 位数据)
+- 3级流水线(取指 → 译码 → 执行)
+- Thumb-2 指令集(16/32位混合指令,兼顾代码密度和性能)
+- 内置 NVIC(嵌套向量中断控制器),支持 240 个中断源
+- 低功耗设计,适合嵌入式应用
+
+### 什么是STM32
+
+- **S**T — STMicroelectronics(意法半导体)
+- **T** — 32位微控制器(实际是 ARM Cortex-M 系列内核)
+- 基于 ARM Cortex-M 内核的 32 位 MCU 产品线
+
+### STM32应用场景
+
+- 工业自动化(PLC、电机控制)
+- 物联网终端(传感器采集、无线通信)
+- 消费电子(智能家电、无人机)
+- 医疗设备(便携式监护仪)
+- 汽车电子(CAN 总线、车窗控制)
+
+### STM32系列MCU命名规则
+
+STM32 系列命名反映了芯片的各个特性。以我们使用的 **STM32F103ZET6** 为例:
+
+```
+STM32  F   1   03   Z   E   T   6
+ ①    ②   ③   ④   ⑤  ⑥   ⑦  ⑧
+```
+
+| 位置 | 含义 | 我们的值 | 说明 |
+|------|------|---------|------|
+| ① | 产品系列 | STM32 | 标准32位MCU |
+| ② | 类型 | F | 通用型(F = 基础型,L = 低功耗,H = 高性能) |
+| ③ | 子系列 | 1 | Cortex-M3 内核 |
+| ④ | 具体型号 | 03 | 增强型(03 = 增强型,01 = 基本型) |
+| ⑤ | 引脚数 | Z | Z = 144脚(L=48,C=48/49,R=64,M=80,V=100,Z=144,I=176) |
+| ⑥ | Flash大小 | E | E = 512KB(B=128,C=256,D=384,E=512) |
+| ⑦ | 封装 | T | T = LQFP(表贴封装) |
+| ⑧ | 温度 | 6 | 6 = -40~85°C(工业级) |
+
+> **参考**:STM32F103xCDE 数据手册 §1(器件概览与选型表)
+> 数据手册命名规则从 ST 官网下载,不同系列命名有所差异。
+
+**STM32 选型速查**:
+- 访问 [ST 官网 MCU 选型器](https://www.st.com/en/microcontrollers-microprocessors/stm32-32-bit-arm-cortex-mcus.html)
+
+### STM32开发方式
+
+目前 STM32 开发有三种方式:
+
+| 方式 | 特点 | 适用人群 |
+|------|------|---------|
+| **寄存器** | 直接操作内存地址,代码最小,最深理解硬件 | 学习硬件原理、裸机开发 |
+| **标准库(StdPeriph)** | ST 官方封装寄存器操作,函数名规范 | 经典项目,教程最多 |
+| **HAL库 + CubeMX** | 图形化配置,移植性好,代码量大 | 快速原型、多平台移植 |
+
+本教程以**寄存器 + HAL 库双版并行**教学,既能深入硬件底层,又能快速实际开发。
+
+---
+
+## 开发环境搭建
+
+### Keil MDK 介绍
+
+KEIL 是 ARM 公司推出的基于 ARM 平台的 C/C++ IDE,支持代码编写、编译、下载、调试一体化。
+
+### 下载与安装
+
+**下载地址**:<https://www.keil.com/download/product/>
+
+### 离线安装芯片支持包
+
+Keil MDK 不内置 STM32 芯片支持,需要手动安装芯片支持包(Device Family Pack):
+
+**下载地址**:<https://www.keil.arm.com/devices/> 搜索 STM32F103ZE
+
+**安装方式二选一**:
+- 在线安装(速度慢,国内不推荐)
+- 下载 `Keil.STM32F1xx_DFP.xxx.pack` 后双击离线安装(推荐)
+
+### 编译器版本配置
+
+最新 Keil MDK 默认使用 Compiler version 6,但与旧的 `core_cm3.c` 文件不兼容。
+
+**解决方法**:安装 Compiler version 5
+
+**下载地址**:<https://developer.arm.com/downloads/view/ACOMP5>
+解压后放到 Keil MDK 安装目录下的 `ARM/ARMCC/` 文件夹。
+然后在 Keil 项目配置中切换编译器版本为 V5。
+
+### 注册
+
+Keil MDK 需要注册(License),否则代码大小限制在 32KB 以内。
+
+---
+
+## 开发板简介
+
+### 开发板资源
+
+![开发板实物图](assets/stm32f103zet6_开发板实物图.png)
+
+我们使用的是一款 STM32F103ZET6 开发板,板载资源包括:
+- 主芯片:**STM32F103ZET6**(Cortex-M3, 72MHz, 512KB Flash, 64KB SRAM)
+- 4 个 LED(LED1~LED4,其中 LED4 为电源指示灯)
+- 多个按键(KEY_UP、KEY_1~KEY_3)
+- USB 转串口(CH340G)
+- W25Q64 Flash 芯片(SPI 接口)
+- 24C02 EEPROM(I2C 接口)
+- 引出所有 GPIO 引脚
+
+### STM32最小系统
+
+STM32 正常工作的最小外围电路包括 5 个部分:
+
+| 部件 | 功能 | 原理图位置 |
+|------|------|-----------|
+| **STM32芯片** | 主控制器 STM32F103ZET6 | 原理图第1页 |
+| **电源** | 3.3V 供电,USB Type-C → AMS1117-3.3 | 原理图电源部分 |
+| **时钟** | 8MHz HSE + 32.768KHz LSE 晶振 | 原理图晶振部分 |
+| **复位** | NRST + 按键 + RC 电路 | 原理图复位部分 |
+| **下载调试** | SWD 接口(SWDIO/SWCLK) | 原理图调试部分 |
+
+#### 1. STM32F103ZET6芯片
+
+![STM32F103ZET6 引脚图](assets/stm32f103zet6_芯片引脚图.png)
+
+STM32F103ZET6 采用 LQFP144 封装,共有 144 个引脚,包括:
+- **I/O 引脚**:多达 112 个通用 I/O(GPIOA~GPIOG,每组 16 个)
+- **电源引脚**:VDD/VSS(数字电源)、VDDA/VSSA(模拟电源)、VREF+/VREF-(ADC 参考电压)
+- **特殊功能引脚**:BOOT0/BOOT1(启动模式选择)、NRST(复位)
+
+> **参考**:STM32F103ZET6 数据手册 §3(引脚定义与功能表)
+
+#### 2. 电源电路
+
+采用双路供电方案:
+
+**方案一**:USB Type-C(5V)→ AMS1117-3.3 稳压芯片 → 3.3V
+**方案二**:ST-Link 直接提供 3.3V 供电
+
+> **参考**:原理图电源部分,AMS1117 数据手册
+> **注意**:AMS1117 最大输出电流 800mA,适合大多数应用。
+
+#### 3. 时钟电路
+
+STM32 提供两路外部时钟:
+
+- **HSE(外部高速时钟)**:8MHz 晶振 → PLL 倍频 → 最高 72MHz 系统时钟
+- **LSE(外部低速时钟)**:32.768KHz 晶振 → RTC 实时时钟
+
+内部也集成了 RC 振荡器(HSI 8MHz、LSI 40KHz),精度较低但无需外部元件。
+
+> **参考**:原理图晶振部分;参考手册 §7.2(时钟特性)
+
+#### 4. 复位电路
+
+NRST 引脚通过上拉电阻连接到 VCC,按下复位按键将 NRST 拉低使芯片复位。
+RC 电路提供上电复位延时(确保电源稳定后再释放复位)。
+
+> **参考**:原理图复位部分;参考手册 §7.1(复位与电源控制)
+
+#### 5. 下载调试电路
+
+支持两种下载方式:
+
+| 方式 | 接口 | 特点 |
+|------|------|------|
+| **ST-Link SWD** | SWDIO + SWCLK + VCC + GND(4线) | 可调试,速度快 |
+| **串口 ISP** | USART1(PA9/PA10)+ FlyMcu 软件 | 仅下载,无需专用工具 |
+
+> **参考**:原理图调试部分;STM32 系统存储器启动模式文档
+
+---
+
+## 项目工程结构
+
+一个典型的 STM32 寄存器/标准库项目目录结构如下:
+
+```
+Project_Name/
+├── Start/              # 启动文件 + 内核文件
+│   ├── startup_stm32f10x_hd.s    # 启动文件(HD = 高密度)
+│   ├── stm32f10x.h               # 外设寄存器结构体定义
+│   ├── system_stm32f1xx.c       # 系统初始化(SystemInit)
+│   └── core_cm3.h               # Cortex-M3 内核定义
+├── User/               # 用户代码
+│   └── main.c          # 主函数
+├── Hardware/           # 外设驱动(逐步创建)
+│   ├── LED/
+│   └── KEY/
+├── Library/            # 标准库文件(使用标准库时)
+├── System/             # 系统配置文件
+└── Objects/            # 编译输出(Keil 自动生成)
+```
+
+### 启动文件的选择
+
+启动文件根据芯片 Flash 大小的不同,选择不同的版本:
+
+| 启动文件 | 适用芯片 | 对应 Flash 范围 |
+|----------|---------|----------------|
+| `startup_stm32f10x_ld.s` | 低密度 | 16~32KB |
+| `startup_stm32f10x_md.s` | 中密度 | 64~128KB |
+| `startup_stm32f10x_hd.s` | 高密度 | 256~512KB |
+
+> **注意**:STM32F103ZET6 的 Flash 是 512KB → 选择 `startup_stm32f10x_hd.s`
+
+启动文件的作用:
+1. 设置堆栈指针(SP)
+2. 初始化中断向量表
+3. 调用 `SystemInit()` 配置时钟
+4. 跳转到 `main()` 函数
+
+### 标准外设库下载地址
+
+下载标准外设库用于提取启动文件、系统文件和头文件:
+
+<https://www.st.com/zh/embedded-software/stm32-standard-peripheral-libraries/products.html>
+
+### Keil 项目配置要点
+
+1. **添加设备组(Group)**:Start(启动文件)、User(用户代码)
+2. **添加源文件**:将启动文件和系统文件添加到对应组
+3. **魔术棒(Options for Target)配置**:
+   - Output:选择输出目录为 Objects
+   - C/C++:Define 中添加 `USE_STDPERIPH_DRIVER`
+   - Debug:选择 ST-Link Debugger,配置 SWD 接口
+4. **编译器版本**:设置为 V5(与旧版 core_cm3.c 兼容)
+
+---
+
+## 烧录方法
+
+### ST-Link SWD 方式
+
+1. 连接 4 根线:SWDIO、SWCLK、VCC、GND
+2. Keil 中配置 Debug → ST-Link Debugger → SWD 接口
+3. 点击 Download(快捷键 F8)下载程序
+
+### ST-Link 驱动安装
+
+Keil MDK 安装目录自带的 ST-LINK USB 驱动位置:
+`Keil_v5\ARM\STLink\USBDriver\dpinst_amd64.exe`
+
+### ST-Link 固件升级
+
+如果 Keil 提示 ST-Link 固件版本过低,需要升级:
+Keil → Flash → Configure Flash Tools → Debug → Settings → Firmware Upgrade
+
+---
+
+## 核心概念速查表
+
+| 概念 | 说明 | 参考 |
+|------|------|------|
+| ARM Cortex-M3 | 32位RISC内核,3级流水线,Thumb-2指令集 | Cortex-M3权威指南§2 |
+| STM32F103ZET6 | 144脚,512KB Flash,72MHz | 数据手册§1 |
+| 最小系统 | 芯片+电源+时钟+复位+下载调试 | 原理图第1~3页 |
+| Keil MDK | ARM平台IDE,含编译/下载/调试 | — |
+| startup_hd.s | 高密度芯片的启动文件 | — |
+| ST-Link SWD | 4线调试接口,支持烧录+调试 | — |
+
+## 常见问题与避坑
+
+1. **芯片支持包在线安装太慢** → 从官网下载 `.pack` 文件后双击离线安装
+2. **Keil MDK 需要注册** → 使用注册机生成 License
+3. **编译报错 core_cm3.c 不兼容** → 安装 Compiler V5 并切换编译器版本
+4. **ST-Link 连接失败** → 检查驱动是否安装、SWD 接线是否正确、固件是否需要升级
+5. **启动文件选择错误** → 检查芯片 Flash 容量,选择对应的 `ld/md/hd` 版本
+6. **下载后程序不运行** → 检查 BOOT0/BOOT1 跳线(BOOT0=0 从 Flash 启动)

+ 445 - 0
X-Knowledge-Base/raw/Joplin/嵌入式+Linux/STM32学习笔记/02-GPIO寄存器详解与三步进化法.md

@@ -0,0 +1,445 @@
+---
+tags: [source-summary]
+type: source
+source: "尚硅谷嵌入式技术之STM32单片机(基础篇)V1.0.2 — 第4~5章:点亮LED案例 + GPIO详解"
+author: "尚硅谷研究院"
+date: 2026-07-15
+created: 2026-07-15
+---
+
+# GPIO寄存器详解与三步进化法
+
+> **用生活理解**:GPIO 就像一排开关(每个引脚一个),你可以用程序控制每个开关输出高/低电平(控制 LED),也可以读取每个开关的状态(读取按键)。"三步进化法"就是操作这些开关的方式从"直接掰电线"进化到"用遥控器按按钮"再到"声控"的过程。
+
+---
+
+## GPIO概述
+
+GPIO(General-purpose input/output,通用型输入输出)是 STM32 芯片与外界交互的最基本途径。
+
+### 总体说明
+
+- STM32F103ZET6 共有 **7 组 GPIO 端口**:GPIOA~GPIOG,每组 16 个引脚,共 112 个 GPIO
+- 每个引脚电平范围:0~3.3V,部分引脚可兼容 5V
+- 最快翻转速度:每 2 个时钟周期翻转一次(最高 50MHz)
+- 每个 GPIO 均可作为外部中断输入
+- 每个引脚可配置为 8 种工作模式之一
+
+> **参考**:STM32F103ZET6 数据手册 §3(引脚功能定义表)
+> **参考**:开发板原理图(LED/KEY 电路部分)
+
+### GPIO的主要特点
+
+| 特性 | 说明 |
+|------|------|
+| 引脚电平 | 0~3.3V(FT 引脚兼容 5V) |
+| 翻转速度 | 最快 50MHz(2 个时钟周期) |
+| 上下拉 | 内置可配置上下拉电阻(约 40KΩ) |
+| 驱动能力 | 最大 ±25mA 拉/灌电流 |
+| 中断能力 | 每个引脚均可作为 EXTI 中断输入 |
+
+---
+
+## GPIO内部结构详解
+
+![GPIO 内部结构图](assets/gpio_内部结构.png)
+
+### 保护二极管
+
+GPIO 引脚内部有两个保护二极管,分别连接到 VDD(3.3V)和 VSS(0V):
+- 当输入电压高于 VDD+0.3V 时,上方二极管导通,将电压钳位到 VDD
+- 当输入电压低于 VSS-0.3V 时,下方二极管导通,将电压拉高到 VSS
+
+> **实际意义**:防止静电或意外的高/低电压损坏芯片。但这不是绝对的,超过极限电压仍会烧毁。
+
+### 上下拉电阻
+
+两个开关控制引脚内部的上下拉电阻(典型值 40KΩ):
+- **上拉**:上开关闭合 → 引脚默认高电平
+- **下拉**:下开关闭合 → 引脚默认低电平
+- **浮空**:两个开关都断开 → 引脚电平不确定(高阻态)
+- **两个同时闭合**:VDD 到 VSS 短路 → 费电且无意义,不会这么用
+
+### 施密特触发器(Schmitt Trigger)
+
+施密特触发器是一个带**迟滞特性**的比较器电路:
+- 输入信号从低到高:阈值约为 1.8V
+- 输入信号从高到低:阈值约为 1.2V
+- 这种**滞回特性**可以滤除信号上的噪声抖动,实现波形整形
+
+施密特触发器的输出进入输入数据寄存器(IDR),供 CPU 读取。
+
+> **注意**:在模拟输入模式下,施密特触发器被**关闭**以降低功耗。
+
+### 输出驱动电路
+
+- **P-MOS**(上管):导通时输出高电平(VDD)
+- **N-MOS**(下管):导通时输出低电平(VSS)
+- **推挽输出**:P-MOS 和 N-MOS 交替导通,可输出高或低电平
+- **开漏输出**:P-MOS 始终关断,只有 N-MOS 工作(只能输出低电平,高电平靠外部上拉电阻)
+
+---
+
+## GPIO的8种工作模式
+
+| 模式 | 类型 | 用途 | P-MOS | N-MOS | 施密特触发器 | 上下拉 |
+|------|------|------|-------|-------|------------|-------|
+| 输入浮空 | 输入 | 按键、通信引脚 | 关闭 | 关闭 | 开 | 禁止 |
+| 输入上拉 | 输入 | 按键(默认高电平) | 关闭 | 关闭 | 开 | 上拉 |
+| 输入下拉 | 输入 | 按键(默认低电平) | 关闭 | 关闭 | 开 | 下拉 |
+| 模拟输入 | 输入 | ADC 采集 | 关闭 | 关闭 | **关闭** | 禁止 |
+| 通用推挽输出 | 输出 | LED、普通信号 | 交替 | 交替 | 开 | 禁止 |
+| 通用开漏输出 | 输出 | I2C 总线、电平转换 | 关闭 | 交替 | 开 | 禁止 |
+| 复用推挽输出 | 输出 | USART_TX、SPI_SCK | 交替 | 交替 | 开 | 禁止 |
+| 复用开漏输出 | 输出 | I2C_SCL/SDA | 关闭 | 交替 | 开 | 禁止 |
+
+### 常见模式选择指导
+
+| 应用场景 | 推荐模式 |
+|----------|---------|
+| 驱动 LED | 推挽输出 |
+| 读取按键 | 上拉输入 或 下拉输入 |
+| I2C 通信 | 复用开漏输出(需要外部上拉) |
+| 串口 TX | 复用推挽输出 |
+| 串口 RX | 浮空输入 或 上拉输入 |
+| ADC 采样 | 模拟输入 |
+| SPI 通信 | 复用推挽输出 |
+| PWM 输出 | 复用推挽输出 |
+
+---
+
+## GPIO的7个关键寄存器
+
+每个 GPIO 端口有 7 个 32 位寄存器,基地址如下:
+- GPIOA: `0x4001 0800`
+- GPIOB: `0x4001 0C00`
+- GPIOC: `0x4001 1000`
+- GPIOD: `0x4001 1400`
+- GPIOE: `0x4001 1800`
+- GPIOF: `0x4001 1C00`
+- GPIOG: `0x4001 2000`
+
+> **参考**:参考手册 §1(存储器映射)+ §8(GPIO 寄存器描述)
+
+### 1. GPIOx_CRL — 端口配置低寄存器(Address: 0x00)
+
+控制 **Pin0~Pin7** 的配置模式。
+
+| 位域 | 名称 | 说明 |
+|------|------|------|
+| 31:30 | CNF7[1:0] | Pin7 配置位 |
+| 29:28 | MODE7[1:0] | Pin7 模式位 |
+| ... | ... | ... |
+| 3:2 | CNF0[1:0] | Pin0 配置位 |
+| 1:0 | MODE0[1:0] | Pin0 模式位 |
+
+**MODE 位含义**:
+| MODE[1:0] | 模式 |
+|-----------|------|
+| 00 | 输入模式(复位状态) |
+| 01 | 输出,最大速度 10MHz |
+| 10 | 输出,最大速度 2MHz |
+| 11 | 输出,最大速度 50MHz |
+
+**CNF 位含义(输入模式下,即 MODE=00)**:
+| CNF[1:0] | 模式 |
+|----------|------|
+| 00 | 模拟输入 |
+| 01 | 浮空输入(复位状态) |
+| 10 | 上拉/下拉输入 |
+| 11 | 保留 |
+
+**CNF 位含义(输出模式下,即 MODE>00)**:
+| CNF[1:0] | 模式 |
+|----------|------|
+| 00 | 通用推挽输出 |
+| 01 | 通用开漏输出 |
+| 10 | 复用功能推挽输出 |
+| 11 | 复用功能开漏输出 |
+
+> **配置示例**:PA0 推挽输出 50MHz → MODE0[1:0]=11, CNF0[1:0]=00 → CRL 低 4 位 = 0011 = 0x3
+
+### 2. GPIOx_CRH — 端口配置高寄存器(Address: 0x04)
+
+与 CRL 结构完全相同,控制 **Pin8~Pin15**。
+
+### 3. GPIOx_IDR — 端口输入数据寄存器(Address: 0x08)
+
+| 位 | 说明 |
+|----|------|
+| 31:16 | 保留 |
+| 15:0 | IDRy:读取 Pin y 的输入电平(0=低,1=高) |
+
+### 4. GPIOx_ODR — 端口输出数据寄存器(Address: 0x0C)
+
+| 位 | 说明 |
+|----|------|
+| 31:16 | 保留 |
+| 15:0 | ODRy:写入 Pin y 的输出电平(0=低,1=高) |
+
+### 5. GPIOx_BSRR — 端口位设置/清除寄存器(Address: 0x10)
+
+| 位 | 名称 | 功能 |
+|----|------|------|
+| 31:16 | BRy | 清除 ODR 的对应位(写 1 清 0) |
+| 15:0 | BSy | 设置 ODR 的对应位(写 1 置 1) |
+
+> **特点**:BSRR 是**原子操作**,同时写低 16 位和高 16 位不会冲突。
+> **对比**:`GPIOA->BSRR = (1<<0)` 相当于 `GPIOA->ODR |= (1<<0)`,但 BSRR 不需要"读-改-写"三步,不会被打断。
+
+### 6. GPIOx_BRR — 端口位清除寄存器(Address: 0x14)
+
+| 位 | 说明 |
+|----|------|
+| 31:16 | 保留 |
+| 15:0 | BRy:清除 ODR 的对应位(写 1 清 0) |
+
+相当于 BSRR 高 16 位的简化版。
+
+### 7. GPIOx_LCKR — 端口配置锁定寄存器(Address: 0x18)
+
+用于锁定 CRL/CRH 的配置,锁定后下次复位前**不可更改**。
+
+锁定时序:写 1 → 写 0 → 写 1 → 读 0 → 读 1
+
+---
+
+## 操作寄存器方式的"三步进化法"
+
+尚硅谷的教学特色:用同一个功能(点亮 LED)展示三种逐渐优化的写法。
+
+### 硬件电路
+
+LED1 连接 PA0,低电平点亮。
+
+![LED 电路原理图](assets/led_电路原理图.png)
+
+**原理**:
+```
+PA0=1(3.3V) → LED 灭(两端电压差接近 0)
+PA0=0(0V)   → LED 亮(电流经 VCC→限流电阻→LED→PA0→GND)
+```
+
+限流电阻计算:`R = (VCC - V_LED) / I_LED`,LED 工作电流约 5~10mA。
+
+### 进化 0:裸地址操作(直接操作内存)
+
+**文件:`stm32_base/01_led_register/User/main.c`**
+
+```c
+#include "stm32f10x.h"
+
+int main(void)
+{
+    /* 1. 开启GPIOA的时钟 */
+    // RCC_APB2ENR 寄存器的地址 = RCC基地址(0x40021000) + 偏移(0x18) = 0x40021018
+    // 第2位置1表示开启GPIOA时钟
+    // 0x00000004 = 二进制 0000 0000 0000 0000 0000 0000 0000 0100
+    //                                         ↑第2位=1
+    *(uint32_t *)(0x40021000 + 0x18) = 4;
+
+    /* 2. 配置PA0为推挽输出模式(最大速度50MHz) */
+    // GPIOA_CRL 寄存器的地址 = GPIOA基地址(0x40010800) + 偏移(0x00) = 0x40010800
+    // PA0对应CRL的最低4位:
+    //   MODE0[1:0] = 11 (50MHz输出)
+    //   CNF0[1:0]  = 00 (通用推挽输出)
+    // 所以低4位 = 0011 = 0x3
+    // 注意:这会覆盖PA1~PA7的配置(其他位变成0),是粗暴的做法
+    *(uint32_t *)(0x40010800 + 0x00) = 3;
+
+    /* 3. PA0输出低电平(点亮LED) */
+    // GPIOA_ODR 寄存器的地址 = GPIOA基地址(0x40010800) + 偏移(0x0C) = 0x4001080C
+    // 第0位置0 = 输出低电平;其他位置1 = 不影响其他引脚
+    // 0x0000FFFE = 二进制 ... 1111 1111 1111 1110
+    //                                          ↑第0位=0
+    *(uint32_t *)(0x40010800 + 0x0C) = 0xFFFE;
+
+    while (1)
+    {
+    }
+}
+```
+
+> **问题**:每次查手册计算地址,烦琐;直接赋值覆盖了其他位(不安全)。
+
+### 进化 1:使用结构体宏定义
+
+ST 官方在 `stm32f10x.h` 中用结构体封装了所有寄存器:
+
+```c
+// stm32f10x.h 中的定义(简化版)
+
+#define PERIPH_BASE           ((uint32_t)0x40000000)   // 外设基地址
+#define AHBPERIPH_BASE        (PERIPH_BASE + 0x20000)  // AHB外设基地址
+#define RCC_BASE              (AHBPERIPH_BASE + 0x1000)// RCC基地址
+
+#define RCC                   ((RCC_TypeDef *) RCC_BASE)// RCC结构体指针
+
+typedef struct
+{
+  __IO uint32_t CR;         // 偏移 0x00
+  __IO uint32_t CFGR;       // 偏移 0x04
+  __IO uint32_t CIR;        // 偏移 0x08
+  __IO uint32_t APB2RSTR;   // 偏移 0x0C
+  __IO uint32_t APB1RSTR;   // 偏移 0x10
+  __IO uint32_t AHBENR;     // 偏移 0x14
+  __IO uint32_t APB2ENR;    // 偏移 0x18  ← 我们用的寄存器
+  __IO uint32_t APB1ENR;    // 偏移 0x1C
+  /* ... */
+} RCC_TypeDef;
+```
+
+> **巧妙之处**:结构体成员地址连续,CR 偏移 0x00,CFGR 偏移 0x04,APB2ENR 偏移 0x18(6×4=24=0x18),与查手册结果一致。
+
+利用这个封装,代码进化为:
+
+**文件:`stm32_base/01_led_register/User/main.c`**
+
+```c
+#include "stm32f10x.h"
+
+int main(void)
+{
+    RCC->APB2ENR = 4;       // RCC->APB2ENR 等价于 *(uint32_t*)(0x40021018)
+    GPIOA->CRL = 3;          // GPIOA->CRL 等价于 *(uint32_t*)(0x40010800)
+    GPIOA->ODR = 0xFFFE;     // GPIOA->ODR 等价于 *(uint32_t*)(0x4001080C)
+
+    while (1)
+    {
+    }
+}
+```
+
+> **进步**:不再手动计算地址,代码可读性大幅提升。
+> **仍存在的问题**:直接写值覆盖了整个寄存器,只操作特定某位才安全。
+
+### 进化 2:使用位运算实现只改变某一位
+
+**文件:`stm32_base/01_led_register/User/main.c`**
+
+```c
+#include "stm32f10x.h"
+
+int main(void)
+{
+    // 1. 开启GPIOA时钟
+    // RCC->APB2ENR 的第2位置1,保持其他位不变
+    RCC->APB2ENR |= (1 << 2);
+    // |= (1<<2) = 按位或: 将第2位置1,其他位不变
+    // 相当于: RCC->APB2ENR = RCC->APB2ENR | 0x00000004
+
+    // 2. 配置PA0为推挽输出50MHz
+    // 先清除CNF0[1:0]=00 (清3,2位)
+    GPIOA->CRL &= ~(1 << 3);   // &= ~(1<<3): 按位与+取反: 保留其他位,将第3位清0
+    GPIOA->CRL &= ~(1 << 2);   // 将第2位清0
+    // 再设置MODE0[1:0]=11 (置1,0位)
+    GPIOA->CRL |= (1 << 1);    // |= (1<<1): 按位或: 将第1位置1
+    GPIOA->CRL |= (1 << 0);    // 将第0位置1
+
+    // 3. PA0输出低电平
+    GPIOA->ODR &= ~(1 << 0);   // 将第0位清0,输出低电平
+
+    while (1)
+    {
+    }
+}
+```
+
+> **进步**:位运算只修改目标位,不影响其他位的原有配置。
+> **仍存在的问题**:`1<<2` 这种写法需要查手册知道要移位几。
+
+### 进化 3:使用 ST 预定义的位宏(最终形态)
+
+ST 在 `stm32f10x.h` 中把每个位域的值也预先定义好了宏:
+
+```c
+// stm32f10x.h 中的宏定义示例
+#define RCC_APB2ENR_IOPAEN    ((uint32_t)0x00000004)  // = 1<<2
+#define GPIO_CRL_MODE0        ((uint32_t)0x00000003)  // MODE0的掩码 = 11B
+#define GPIO_CRL_MODE0_1      ((uint32_t)0x00000002)  // MODE0的第1位
+#define GPIO_CRL_MODE0_0      ((uint32_t)0x00000001)  // MODE0的第0位
+#define GPIO_CRL_CNF0         ((uint32_t)0x0000000C)  // CNF0的掩码 = 1100B
+#define GPIO_CRL_CNF0_1       ((uint32_t)0x00000008)  // CNF0的第3位
+#define GPIO_CRL_CNF0_0       ((uint32_t)0x00000004)  // CNF0的第2位
+#define GPIO_ODR_ODR0         ((uint32_t)0x00000001)  // ODR的第0位
+```
+
+利用这些宏,最终版代码:
+
+**文件:`stm32_base/01_led_register/User/main.c`**
+
+```c
+#include "stm32f10x.h"
+
+int main(void)
+{
+    // 1. 开启GPIOA时钟
+    // RCC_APB2ENR_IOPAEN = 0x00000004 = 1<<2
+    // |= 按位或: 将IOPAEN位置1,保持其他时钟位不变
+    RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;
+
+    // 2. 配置PA0为推挽输出
+    // GPIO_CRL_CNF0 = 0xC,清除CNF0两位(CNF0_1和CNF0_0)
+    GPIOA->CRL &= ~GPIO_CRL_CNF0;
+    // GPIO_CRL_MODE0 = 0x3,设置MODE0[1:0] = 11(50MHz输出)
+    GPIOA->CRL |= GPIO_CRL_MODE0;
+
+    // 3. PA0输出低电平
+    // GPIO_ODR_ODR0 = 0x1,将ODR0位清0
+    GPIOA->ODR &= ~GPIO_ODR_ODR0;
+
+    while (1)
+    {
+    }
+}
+```
+
+> **最终形态**:代码简洁、可读性强、安全、易于维护。**这就是实际项目中推荐的方式。**
+
+### 三步进化法总结
+
+| 阶段 | 写法 | 优点 | 缺点 |
+|------|------|------|------|
+| 进化0 | 裸地址 | 理解硬件本质 | 烦琐、不安全 |
+| 进化1 | 结构体宏 | 可读性好 | 仍可能覆盖其他位 |
+| 进化2 | 位运算 | 只改需要的位 | 需查手册知移位次数 |
+| **进化3** | **位宏** | **最安全、最可读** | 需要了解宏名含义 |
+
+---
+
+## 核心位操作速查表
+
+| 操作 | 语法 | 解释 |
+|------|------|------|
+| 位置1 | `REG |= BITMASK;` | 按位或:其他位不变,指定位置1 |
+| 位清0 | `REG &= ~BITMASK;` | 按位与+取反:其他位不变,指定位清0 |
+| 位翻转 | `REG ^= BITMASK;` | 按位异或:指定位置1变0,0变1 |
+| 位移位 | `x << N` | 左移N位(相当于乘 2^N) |
+| 位移位 | `x >> N` | 右移N位(相当于除 2^N) |
+| 测试位 | `if (REG & BITMASK)` | 按位与:测试指定位是否为1 |
+| 连续位置1 | `REG |= (MASK << N)` | 将 N 位开始的 MASK 位写入1 |
+| 连续位清0 | `REG &= ~(MASK << N)` | 将 N 位开始的 MASK 位清0 |
+
+> **典型技巧**:`先清除后设置` 是嵌入式位操作的黄金法则。对连续位域(如 MODE[1:0])总是先 `&= ~MASK` 清空,再 `|= VALUE` 设置。
+
+---
+
+## 核心函数速查表
+
+(本笔记以寄存器操作为主,无标准库/HAL 库函数)
+
+| 操作 | 寄存器方式 | 说明 |
+|------|----------|------|
+| 设置输出高 | `GPIOx->BSRR = (1<<n)` | 原子操作,推荐 |
+| 设置输出低 | `GPIOx->BRR = (1<<n)` | 原子操作,推荐 |
+| 读取输入 | `uint8_t val = (GPIOx->IDR >> n) & 1` | 提取第n位值 |
+| 翻转输出 | `GPIOx->ODR ^= (1<<n)` | 异或翻转 |
+
+## 常见问题与避坑
+
+1. **GPIO 配置后不工作** → 检查 RCC 时钟是否已开启(最常见错误!)
+2. **输出电平不对** → 检查推挽/开漏模式选择是否正确、ODR/BSRR 操作是否正确
+3. **开漏输出高电平不对** → 检查外部上拉电阻是否焊接
+4. **输入值一直为0或1** → 检查上下拉配置是否合适、施密特触发器是否被关闭(模拟模式)
+5. **引脚翻转速度太慢** → 检查 MODE 位速度配置(50MHz/10MHz/2MHz)
+6. **同时配置多个引脚互相干扰** → 使用 CRL/CRH 位操作,不要整体赋值

+ 463 - 0
X-Knowledge-Base/raw/Joplin/嵌入式+Linux/STM32学习笔记/03-GPIO输出:LED控制.md

@@ -0,0 +1,463 @@
+---
+tags: [source-summary]
+type: source
+source: "尚硅谷嵌入式技术之STM32单片机(基础篇)V1.0.2 — 第6~7章:LED流水灯 + 配套代码02~04"
+author: "尚硅谷研究院"
+date: 2026-07-15
+created: 2026-07-15
+---
+
+# GPIO输出:LED控制
+
+> **用生活理解**:LED 控制就像你手里有 3 个开关(GPIO 引脚)分别控制 3 盏灯。你手动打开灯(IO=0),等一会儿,再关上(IO=1),再打开下一盏,就形成了"流水灯"效果。模块化封装就像给每个灯配了一个遥控器(LED_On/LED_Off 函数),不用再直接去掰开关了。
+
+---
+
+## LED硬件电路设计
+
+![LED电路原理图](assets/led_电路原理图.png)
+
+开发板上有 4 个 LED:
+- **LED1** → PA0(低电平点亮)
+- **LED2** → PA1(低电平点亮)
+- **LED3** → PA8(低电平点亮)
+- **LED4** → 电源指示灯(上电即亮,不可控)
+
+**电路原理**:
+```
+VCC(3.3V) → 限流电阻(1KΩ) → LED 正极 → LED 负极 → GPIO引脚
+
+当 GPIO = 0 (低电平) → 电流流过 LED → LED 点亮
+当 GPIO = 1 (高电平) → LED 两端电压差接近 0 → LED 熄灭
+```
+
+**限流电阻计算**:
+- LED 工作电流约 5~10mA
+- LED 正向压降约 1.8~2.0V
+- `R = (VCC - V_LED) / I_LED = (3.3 - 2.0) / 0.01 = 130Ω`(实际使用 1KΩ,延长 LED 寿命)
+
+> **参考**:开发板原理图 LED 部分
+
+---
+
+## 实验:LED流水灯
+
+### 需求描述
+
+依次点亮 LED1 → LED2 → LED3,每个灯亮 500ms,形成流水灯效果。
+
+### 软件设计(寄存器版 — 直接操作)
+
+**项目路径**:`stm32_base/02_led_flow_register`
+
+这个版本在 main.c 中将所有逻辑写在一起,直观但不利于复用。
+
+**文件:`stm32_base/02_led_flow_register/User/main.c`**
+
+```c
+#include "stm32f10x.h"
+
+// 函数声明
+void Delay_us(uint16_t us);
+void Delay_ms(uint16_t ms);
+void Delay_s(uint16_t s);
+
+int main(void)
+{
+    // 1. 时钟配置:开启GPIOA时钟
+    RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;
+
+    // 2. 配置PA0、PA1、PA8为推挽输出50MHz
+    // PA0 (CRL低4位: MODE0=11, CNF0=00)
+    GPIOA->CRL |= GPIO_CRL_MODE0;       // 设置MODE0[1:0]=11 → 50MHz输出
+    GPIOA->CRL &= ~GPIO_CRL_CNF0;       // 清除CNF0[1:0]=00 → 通用推挽
+
+    // PA1 (CRL的4~7位: MODE1=11, CNF1=00)
+    GPIOA->CRL |= GPIO_CRL_MODE1;       // MODE1置1
+    GPIOA->CRL &= ~GPIO_CRL_CNF1;       // CNF1清0
+
+    // PA8 (CRH的低4位: MODE8=11, CNF8=00)
+    GPIOA->CRH |= GPIO_CRH_MODE8;       // MODE8置1
+    GPIOA->CRH &= ~GPIO_CRH_CNF8;       // CNF8清0
+
+    // 3. 初始状态:所有灯熄灭(输出高电平)
+    GPIOA->ODR |= (GPIO_ODR_ODR0 | GPIO_ODR_ODR1 | GPIO_ODR_ODR8);
+
+    // 4. 流水灯循环
+    while (1)
+    {
+        // 点亮 LED1 (PA0输出低电平)
+        GPIOA->ODR &= ~GPIO_ODR_ODR0;   // &=~ 将ODR0位清0 → 低电平
+        Delay_ms(500);                   // 保持500ms
+        GPIOA->ODR |= GPIO_ODR_ODR0;    // |= 将ODR0位置1 → 高电平,熄灭
+
+        // 点亮 LED2 (PA1输出低电平)
+        GPIOA->ODR &= ~GPIO_ODR_ODR1;
+        Delay_ms(500);
+        GPIOA->ODR |= GPIO_ODR_ODR1;
+
+        // 点亮 LED3 (PA8输出低电平)
+        GPIOA->ODR &= ~GPIO_ODR_ODR8;
+        Delay_ms(500);
+        GPIOA->ODR |= GPIO_ODR_ODR8;
+    }
+}
+
+// ==== 微秒级延时函数(基于SysTick实现)====
+void Delay_us(uint16_t us)
+{
+    // SysTick->LOAD: 设置重装载值
+    // 系统时钟72MHz, 每计数一次 = 1/72 us
+    // 延时us微秒需要计数: 72 * us 次
+    SysTick->LOAD = 72 * us;
+
+    // SysTick->CTRL: 控制寄存器
+    // 第0位 ENABLE=1 → 启动定时器
+    // 第2位 CLKSOURCE=1 → 使用系统时钟(AHB=72MHz)
+    // 0x05 = 二进制 0101 → ENABLE=1, CLKSOURCE=1, TICKINT=0
+    SysTick->CTRL = 0x05;
+
+    // 轮询等待 COUNTFLAG 位置1(计到0时硬件自动置1)
+    // SysTick_CTRL_COUNTFLAG = (1<<16)
+    while (!(SysTick->CTRL & SysTick_CTRL_COUNTFLAG))
+    {
+    }
+
+    // 关闭定时器(ENABLE位清0)
+    SysTick->CTRL &= ~SysTick_CTRL_ENABLE;  // &=~ 将ENABLE位清0
+}
+
+void Delay_ms(uint16_t ms)
+{
+    while (ms--)
+    {
+        Delay_us(1000);  // 1ms = 1000us
+    }
+}
+
+void Delay_s(uint16_t s)
+{
+    while (s--)
+    {
+        Delay_ms(1000);
+    }
+}
+```
+
+> **问题**:代码所有逻辑堆在 main.c 中,不方便复用。LED 操作、延时函数、main 逻辑混在一起。
+
+---
+
+### 软件设计(寄存器版 — 模块化封装)
+
+**项目路径**:`stm32_base/03_led_flow_pro_register`
+
+这个版本将 LED 驱动提取为独立模块 `Hardware/LED/led.c + led.h`,延时单独成文件 `User/delay.c + delay.h`,main.c 只负责调用。
+
+**文件:`stm32_base/03_led_flow_pro_register/Hardware/LED/led.h`**
+
+```c
+#ifndef __LED_H
+#define __LED_H
+
+#include "stm32f10x.h"
+
+// 宏定义:三个LED对应的ODR位
+// LED_1 = GPIO_ODR_ODR0 = 0x0001 = 第0位,对应PA0
+// LED_2 = GPIO_ODR_ODR1 = 0x0002 = 第1位,对应PA1
+// LED_3 = GPIO_ODR_ODR8 = 0x0100 = 第8位,对应PA8
+#define LED_1 GPIO_ODR_ODR0
+#define LED_2 GPIO_ODR_ODR1
+#define LED_3 GPIO_ODR_ODR8
+
+void LED_Init(void);                      // 初始化LED(时钟+GPIO配置)
+void LED_On(uint16_t led);                // 点亮指定LED
+void LED_Off(uint16_t led);               // 熄灭指定LED
+void LED_Toggle(uint16_t led);            // 翻转指定LED状态
+void LED_OnAll(uint16_t leds[], uint8_t size);   // 同时点亮多个LED
+void LED_OffAll(uint16_t leds[], uint8_t size);  // 同时熄灭多个LED
+
+#endif
+```
+
+**文件:`stm32_base/03_led_flow_pro_register/Hardware/LED/led.c`**
+
+```c
+#include "led.h"
+
+// LED初始化:开启时钟 + 配置GPIO模式 + 初始状态熄灭
+void LED_Init(void)
+{
+    // 1. 开启GPIOA时钟
+    // RCC_APB2ENR_IOPAEN = 0x00000004 = 1<<2
+    RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;
+
+    // 2. 配置PA0、PA1、PA8为推挽输出50MHz
+    // PA0: MODE0=11(50MHz), CNF0=00(通用推挽)
+    GPIOA->CRL |= GPIO_CRL_MODE0;       // |= 将MODE0位置1
+    GPIOA->CRL &= ~GPIO_CRL_CNF0;       // &=~ 将CNF0位清0
+
+    // PA1: MODE1=11, CNF1=00
+    GPIOA->CRL |= GPIO_CRL_MODE1;
+    GPIOA->CRL &= ~GPIO_CRL_CNF1;
+
+    // PA8: MODE8=11, CNF8=00
+    GPIOA->CRH |= GPIO_CRH_MODE8;
+    GPIOA->CRH &= ~GPIO_CRH_CNF8;
+
+    // 3. 初始状态:所有灯熄灭
+    LED_Off(LED_1);
+    LED_Off(LED_2);
+    LED_Off(LED_3);
+}
+
+// 点亮LED:ODR对应位清0(低电平点亮)
+void LED_On(uint16_t led)
+{
+    GPIOA->ODR &= ~led;   // &=~ led: 将led对应的ODR位清0
+}
+
+// 熄灭LED:ODR对应位置1(高电平熄灭)
+void LED_Off(uint16_t led)
+{
+    GPIOA->ODR |= led;    // |= led: 将led对应的ODR位置1
+}
+
+// 翻转LED状态:读取当前状态,然后取反
+void LED_Toggle(uint16_t led)
+{
+    // 通过IDR寄存器读取当前引脚电平
+    // IDR对应位=0表示引脚低电平(LED亮)
+    if ((GPIOA->IDR & led) == 0)
+    {
+        LED_Off(led);   // 当前亮 → 熄灭
+    }
+    else
+    {
+        LED_On(led);    // 当前灭 → 点亮
+    }
+}
+
+// 同时点亮多个LED
+void LED_OnAll(uint16_t leds[], uint8_t size)
+{
+    for (uint8_t i = 0; i < size; i++)
+    {
+        LED_On(leds[i]);
+    }
+}
+
+// 同时熄灭多个LED
+void LED_OffAll(uint16_t leds[], uint8_t size)
+{
+    for (uint8_t i = 0; i < size; i++)
+    {
+        LED_Off(leds[i]);
+    }
+}
+```
+
+**文件:`stm32_base/03_led_flow_pro_register/User/delay.h`**
+
+```c
+#ifndef __DELAY_H
+#define __DELAY_H
+
+#include "stm32f10x.h"
+
+void Delay_us(uint16_t us);
+void Delay_ms(uint16_t ms);
+void Delay_s(uint16_t s);
+
+#endif
+```
+
+**文件:`stm32_base/03_led_flow_pro_register/User/delay.c`**
+
+```c
+#include "delay.h"
+
+// SysTick定时器实现微秒级延时
+void Delay_us(uint16_t us)
+{
+    // SysTick寄存器详解:
+    // LOAD[23:0]: 重装载值(24位计数器最大值16,777,215)
+    // CTRL[0]: ENABLE — 0=关闭, 1=启动
+    // CTRL[1]: TICKINT — 0=不产生中断, 1=计数到0时产生中断
+    // CTRL[2]: CLKSOURCE — 0=AHB/8(9MHz), 1=AHB(72MHz)
+    // CTRL[16]: COUNTFLAG — 计数到0时硬件置1, 读后自动清0
+    // VAL[23:0]: 当前计数值(读返回当前值,写清0)
+
+    // 设置装载值: 72MHz下, 1us需要计数72次
+    SysTick->LOAD = 72 * us;
+
+    // CTRL = 0x05 = 二进制 0000 0101
+    // 第0位ENABLE=1, 第2位CLKSOURCE=1, 不使用中断
+    SysTick->CTRL = 0x05;
+
+    // 轮询等待COUNTFLAG置1(计数值减到0)
+    while (!(SysTick->CTRL & SysTick_CTRL_COUNTFLAG))
+    {
+    }
+
+    // 关闭SysTick
+    SysTick->CTRL &= ~SysTick_CTRL_ENABLE;  // ENABLE位清0
+}
+
+void Delay_ms(uint16_t ms)
+{
+    while (ms--)
+    {
+        Delay_us(1000);  // 1ms累积1000次1us
+    }
+}
+
+void Delay_s(uint16_t s)
+{
+    while (s--)
+    {
+        Delay_ms(1000);
+    }
+}
+```
+
+**文件:`stm32_base/03_led_flow_pro_register/User/main.c`**
+
+```c
+#include "delay.h"
+#include "led.h"
+
+int main(void)
+{
+    LED_Init();  // 时钟+GPIO+初始状态 一站式初始化
+
+    uint16_t leds[] = {LED_1, LED_2, LED_3};
+    uint8_t n = 3;
+
+    while (1)
+    {
+        for (uint8_t i = 0; i < n; i++)
+        {
+            LED_On(leds[i]);     // 点亮当前LED
+            Delay_ms(500);       // 保持500ms
+            LED_Off(leds[i]);    // 熄灭当前LED
+        }
+    }
+}
+```
+
+> **进步**:main.c 非常干净,只表达业务逻辑。LED 底层操作被封装在 Hardware/LED/ 中,delay 独立模块化,可跨项目复用。
+
+---
+
+### 软件设计(HAL库版 — CubeMX生成)
+
+**项目路径**:`stm32_base/04_led_flow_pro_hal`
+
+CubeMX 图形化配置 GPIOD(某些板子)或 GPIOA(我们用的板子),由工具生成初始化代码,用户在 `/* USER CODE */` 区间添加业务逻辑。
+
+**文件:`stm32_base/04_led_flow_pro_hal/Core/Src/main.c`**
+
+```c
+/* Includes ------------------------------------------------------------------*/
+#include "main.h"
+#include "gpio.h"
+#include "led.h"
+
+int main(void)
+{
+    /* MCU Configuration */
+    HAL_Init();                           // HAL库初始化(时基、Flash等)
+    SystemClock_Config();                 // 系统时钟配置(72MHz)
+    MX_GPIO_Init();                       // GPIO初始化(CubeMX生成)
+
+    // 用户代码开始
+    LED leds[] = {LED1_Pin, LED2_Pin, LED3_Pin};
+
+    while (1)
+    {
+        for (uint8_t i = 0; i < 3; i++)
+        {
+            LED_On(leds[i]);              // 点亮
+            HAL_Delay(500);               // HAL库毫秒延时
+            LED_Off(leds[i]);             // 熄灭
+        }
+    }
+}
+```
+
+**文件:`stm32_base/04_led_flow_pro_hal/Core/Src/led.c`**
+
+```c
+#include "led.h"
+
+// HAL_GPIO_WritePin 参数说明:
+// 参数1: GPIOx — GPIO端口基地址
+// 参数2: GPIO_Pin — 引脚编号掩码 (如 GPIO_PIN_0 = 0x0001)
+// 参数3: PinState — GPIO_PIN_RESET=0(低电平) / GPIO_PIN_SET=1(高电平)
+// LED 低电平点亮, 所以 On=RESET, Off=SET
+
+void LED_On(LED led)
+{
+    HAL_GPIO_WritePin(GPIOA, led, GPIO_PIN_RESET);
+}
+
+void LED_Off(LED led)
+{
+    HAL_GPIO_WritePin(GPIOA, led, GPIO_PIN_SET);
+}
+
+void LED_Toggle(LED led)
+{
+    HAL_GPIO_TogglePin(GPIOA, led);
+}
+
+void LED_OnAll(LED leds[], uint8_t size)
+{
+    for (uint8_t i = 0; i < size; i++)
+    {
+        LED_On(leds[i]);
+    }
+}
+
+void LED_OffAll(LED leds[], uint8_t size)
+{
+    for (uint8_t i = 0; i < size; i++)
+    {
+        LED_Off(leds[i]);
+    }
+}
+```
+
+---
+
+## Core 函数速查表
+
+### 寄存器版 (基于 stm32f10x.h 宏)
+
+| 操作 | 代码 | 说明 |
+|------|------|------|
+| LED初始化 | `LED_Init()` | 开启时钟 + 配置推挽输出 + 初始熄灭 |
+| 点亮LED | `LED_On(LED_1)` | `GPIOA->ODR &= ~led_bit` |
+| 熄灭LED | `LED_Off(LED_1)` | `GPIOA->ODR |= led_bit` |
+| 翻转LED | `LED_Toggle(LED_1)` | 读取IDR判断当前状态,取反 |
+| 延时 | `Delay_ms(500)` | 基于SysTick查询方式 |
+
+### HAL库版
+
+| HAL函数 | 说明 |
+|---------|------|
+| `HAL_GPIO_WritePin(GPIOA, pin, state)` | 写引脚电平 (RESET=低, SET=高) |
+| `HAL_GPIO_TogglePin(GPIOA, pin)` | 翻转引脚电平 |
+| `HAL_Delay(ms)` | 毫秒延时(基于SysTick中断) |
+
+---
+
+## 常见问题与避坑
+
+1. **LED 不亮** → 检查 GPIO 模式(必须推挽输出)、检查 ODR 电平(低电平才亮)
+2. **LED 亮度不足** → 检查限流电阻、GPIO 输出速度(MODE 配置为 50MHz 驱动能力更强)
+3. **流水灯速度不对** → Delay_us 中 LOAD 值计算是否匹配系统时钟频率(72MHz?)
+4. **HAL_Delay 不工作** → HAL 时基(SysTick)被其他中断阻塞;检查中断优先级配置
+5. **模块化文件找不到头文件** → Keil 中需在 Options → C/C++ → Include Paths 添加路径
+6. **CubeMX 生成代码后 USER CODE 被覆盖** → 务必写在 `/* USER CODE BEGIN */` 和 `/* USER CODE END */` 之间

+ 287 - 0
X-Knowledge-Base/raw/Joplin/嵌入式+Linux/STM32学习笔记/04-GPIO输入与NVIC中断系统.md

@@ -0,0 +1,287 @@
+---
+tags: [source-summary]
+type: source
+source: "尚硅谷嵌入式技术之STM32单片机(基础篇)V1.0.2 — 第7章:按键与中断系统 + 配套代码05~06"
+author: "尚硅谷研究院"
+date: 2026-07-15
+created: 2026-07-15
+---
+
+# GPIO输入与NVIC中断系统
+
+> **用生活理解**:中断就像你正在写代码,突然电话响了——你暂停写代码、接电话、处理完、挂电话、继续写代码。按键中断就是"按键按下 → 暂停主程序 → 处理按键 → 恢复主程序"。NVIC 就像一个智能电话秘书,知道哪个电话更重要、该先接哪个。
+
+---
+
+## 中断系统概述
+
+### 为什么需要中断
+
+如果没有中断,CPU 只能轮询检测按键状态——就像一直盯着电话看它响不响,浪费 CPU 时间。中断机制允许外设在需要时**主动通知 CPU**,CPU 不用一直等。
+
+### STM32中断体系架构
+
+STM32F103 的中断体系由两部分组成:
+
+| 部件 | 功能 | 参考手册章节 |
+|------|------|-------------|
+| **NVIC** (嵌套向量中断控制器) | 中断优先级管理、使能/屏蔽 | §8 NVIC |
+| **EXTI** (外部中断/事件控制器) | 管理 GPIO 引脚的边沿检测与中断请求 | §9 EXTI |
+
+中断响应过程:
+```
+GPIO引脚电平变化 → EXTI检测边沿 → NVIC判断优先级 → CPU暂停当前任务
+→ 跳转到中断向量表 → 执行中断服务函数(ISR) → 返回主程序
+```
+
+### 中断优先级
+
+NVIC 支持 16 级可编程中断优先级(0 最高,15 最低)。
+
+**优先级分组**:4 位优先级可拆分为"抢占优先级 + 子优先级"
+
+| 分组 | 分配 | 抢占优先级位数 | 子优先级位数 |
+|------|------|--------------|------------|
+| NVIC_PriorityGroup_0 | 0位抢占 + 4位子优先 | 0 | 4 |
+| NVIC_PriorityGroup_1 | 1位抢占 + 3位子优先 | 2级 | 8级 |
+| NVIC_PriorityGroup_2 | 2位抢占 + 2位子优先 | 4级 | 4级 |
+| NVIC_PriorityGroup_3 | 3位抢占 + 1位子优先 | 8级 | 2级 |
+| NVIC_PriorityGroup_4 | 4位抢占 + 0位子优先 | 16级 | 0 |
+
+> **规则**:抢占优先级高的可以打断低的;相同抢占优先级下,子优先级高的先执行但不打断。
+
+### EXTI 外部中断
+
+STM32F103 有 20 个 EXTI 通道(EXTI0~EXTI19),每个 GPIO 引脚都可以配置为 EXTI 输入。
+
+**EXTI配置流程**:
+```
+1. GPIO配置(输入模式) → 2. AFIO选择中断线 → 3. EXTI配置(触发边沿+使能) → 4. NVIC配置(优先级+使能)
+```
+
+**EXTI 关键寄存器**:
+
+| 寄存器 | 功能 | 位说明 |
+|--------|------|--------|
+| IMR | 中断屏蔽寄存器 | 1=允许中断请求,0=禁止 |
+| EMR | 事件屏蔽寄存器 | 1=允许事件请求,0=禁止 |
+| RTSR | 上升沿触发选择 | 1=允许上升沿触发 |
+| FTSR | 下降沿触发选择 | 1=允许下降沿触发 |
+| SWIER | 软件中断事件寄存器 | 写1=软件触发中断 |
+| PR | 挂起寄存器 | 1=有中断请求,写1清除 |
+
+> **参考**:参考手册 §9(EXTI 寄存器描述)+ §8(NVIC 寄存器描述)
+
+---
+
+## 按键输入硬件电路
+
+![KEY电路原理图](assets/key_电路原理图.png)
+
+开发板上有 4 个按键:
+
+| 按键 | 对应引脚 | 连接方式 | 按下时电平 |
+|------|---------|---------|-----------|
+| KEY_UP (SW4) | PF10 | 上拉输入 | 低变高 |
+| KEY_1 (SW2) | ? | 外部电路 | 取决于设计 |
+| KEY_2 | ? | 外部电路 | 取决于设计 |
+| KEY_3 (SW5) | PF10? | 上拉输入 | 低变高 |
+
+> **说明**:PF10 对应的 KEY 为上拉输入模式——按键未按下时 PF10=低(下拉到GND),按下时 PF10=高(上拉到 VCC)。
+
+**消抖**:机械按键在按下/释放瞬间会产生约 5~10ms 的抖动(电平快速跳变),需要软件消抖:
+```
+理想波形: __┃┃________
+实际波形: __┃_┃_┃┃_┃_┃____  ← 抖动
+软件消抖: 检测到边沿 → 等待15ms → 再次确认电平
+```
+
+---
+
+## 实验:按键控制LED(中断方式)
+
+### 需求描述
+
+按下 KEY_1(PF10),翻转 LED1 的开关状态。使用外部中断 EXTI15_10 实现。
+
+### 软件设计(寄存器版)
+
+**项目路径**:`stm32_base/05_key_led_register`
+
+**文件:`stm32_base/05_key_led_register/Hardware/KEY/key.h`**
+
+```c
+#ifndef __KEY_H
+#define __KEY_H
+
+#include "stm32f10x.h"
+
+void KEY_Init(void);
+
+#endif
+```
+
+**文件:`stm32_base/05_key_led_register/Hardware/KEY/key.c`**
+
+```c
+#include "key.h"
+#include "delay.h"
+#include "led.h"
+
+// KEY初始化:配置PF10为上拉输入 + EXTI中断
+void KEY_Init(void)
+{
+    /* ========== 1. 开启时钟 ========== */
+    // GPIOF时钟(操作PF10需要)
+    RCC->APB2ENR |= RCC_APB2ENR_IOPFEN;     // |=: IOPFEN位置1
+    // AFIO时钟(配置中断线重映射需要)
+    RCC->APB2ENR |= RCC_APB2ENR_AFIOEN;     // |=: AFIOEN位置1
+
+    /* ========== 2. 配置PF10为上拉输入 ========== */
+    // MODE10[1:0] = 00 → 输入模式
+    GPIOF->CRH &= ~GPIO_CRH_MODE10;          // &=~: MODE10位清0
+    // CNF10[1:0] = 10 → 上拉/下拉输入
+    GPIOF->CRH |= GPIO_CRH_CNF10_1;           // |=: CNF10_1位置1
+    GPIOF->CRH &= ~GPIO_CRH_CNF10_0;         // &=~: CNF10_0位清0
+    // 开启上拉电阻(ODR对应位置1 = 上拉)
+    // PF10 ODR位=1 → 上拉;ODR位=0 → 下拉
+    GPIOF->ODR &= ~GPIO_ODR_ODR10;            // 选择下拉(按键未按时低电平)
+
+    /* ========== 3. AFIO选择EXTI中断线 ========== */
+    // EXTI10连接到PF10(EXTICR[2]的第8~11位控制EXTI10~EXTI13)
+    AFIO->EXTICR[2] |= AFIO_EXTICR3_EXTI10_PF;
+
+    /* ========== 4. 配置EXTI ========== */
+    // RTSR: 上升沿触发选择寄存器 — PF10从低变高(按键按下)时触发
+    EXTI->RTSR |= EXTI_RTSR_TR10;            // |=: EXTI10上升沿触发使能
+    // IMR: 中断屏蔽寄存器 — 允许EXTI10产生中断
+    EXTI->IMR |= EXTI_IMR_MR10;              // |=: EXTI10中断不屏蔽
+
+    /* ========== 5. 配置NVIC ========== */
+    // 设置优先级分组为Group_3:3位抢占(8级) + 1位子优先(2级)
+    NVIC_SetPriorityGrouping(3);
+    // 设置EXTI15_10中断的抢占优先级=2
+    NVIC_SetPriority(EXTI15_10_IRQn, 2);
+    // 使能EXTI15_10中断通道
+    NVIC_EnableIRQ(EXTI15_10_IRQn);
+}
+
+// EXTI15_10中断服务函数(10~15共用一个中断入口)
+void EXTI15_10_IRQHandler(void)
+{
+    /* 1. 清除中断标志位 */
+    // PR寄存器的对应位写1清除挂起标志
+    // 如果不清除,退出中断后立即再次进入
+    EXTI->PR |= EXTI_PR_PR10;               // |=: PR10写1清除
+
+    /* 2. 软件消抖 */
+    Delay_ms(15);   // 等待15ms避开抖动期
+
+    /* 3. 再次确认按键确实按下 */
+    // 读取IDR判断PF10是否仍为高电平(屏蔽状态)
+    if ((GPIOF->IDR & GPIO_IDR_IDR10) != 0) // &测试: IDR10位是否为1
+    {
+        // 翻转LED1状态
+        LED_Toggle(LED_1);
+    }
+}
+```
+
+**文件:`stm32_base/05_key_led_register/User/main.c`**
+
+```c
+#include "key.h"
+#include "led.h"
+
+int main(void)
+{
+    LED_Init();     // LED初始化
+    KEY_Init();     // KEY初始化(含中断配置)
+
+    while (1)
+    {
+        // 主循环什么都不用做,等待中断发生
+        // 按键按下 → EXTI中断 → ISR翻转LED → 返回继续等
+    }
+}
+```
+
+---
+
+### 软件设计(HAL库版)
+
+**项目路径**:`stm32_base/06_key_led_hal`
+
+CubeMX 配置要点:
+1. PF10 配置为 `GPIO_EXTI10` + `GPIO_PULLUP`(上拉输入)
+2. NVIC 中使能 `EXTI15_10_IRQn`
+3. 在 `stm32f1xx_it.c` 的 `EXTI15_10_IRQHandler()` 中添加用户代码
+
+HAL 库中断处理流程:
+```
+外部中断 → HAL库的 HAL_GPIO_EXTI_IRQHandler() 调用
+→ HAL_GPIO_EXTI_Callback() → 用户重写Callback函数
+```
+
+**文件:`stm32_base/06_key_led_hal/Core/Src/main.c`**(用户代码部分)
+
+```c
+/* USER CODE BEGIN 0 */
+// HAL库的中断回调函数(由HAL_GPIO_EXTI_IRQHandler调用)
+void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
+{
+    if (GPIO_Pin == KEY1_Pin)   // 判断是哪个引脚触发的中断
+    {
+        HAL_Delay(15);                          // 消抖
+        if (HAL_GPIO_ReadPin(KEY1_GPIO_Port, KEY1_Pin) == GPIO_PIN_SET) // 再次确认
+        {
+            HAL_GPIO_TogglePin(LED1_GPIO_Port, LED1_Pin); // 翻转LED
+        }
+    }
+}
+/* USER CODE END 0 */
+```
+
+> **对比寄存器版**:HAL 库将中断的底层操作(PR清除、中断线判断)封装在 `HAL_GPIO_EXTI_IRQHandler` 中,用户只需要重写 Callback 函数。
+
+---
+
+## 核心函数速查表
+
+### 寄存器版
+
+| 函数/操作 | 代码 | 说明 |
+|-----------|------|------|
+| KEY初始化 | `KEY_Init()` | 时钟+GPIO+AFIO+EXTI+NVIC |
+| 清除中断标志 | `EXTI->PR |= EXTI_PR_PR10` | 写1清除挂起位 |
+| 读取引脚 | `GPIOF->IDR & GPIO_IDR_IDR10` | &测试:测量PF10电平 |
+| 软件消抖 | `Delay_ms(15)` | 避开机械抖动期 |
+
+### HAL库版
+
+| HAL函数 | 说明 |
+|---------|------|
+| `HAL_GPIO_ReadPin(GPIOx, pin)` | 读取引脚电平 |
+| `HAL_GPIO_TogglePin(GPIOx, pin)` | 翻转引脚电平 |
+| `HAL_GPIO_EXTI_IRQHandler(pin)` | EXTI中断入口(清标志+调Callback) |
+| `HAL_GPIO_EXTI_Callback(pin)` | 用户重写的回调函数 |
+
+### NVIC函数(core_cm3.h)
+
+| 函数 | 说明 |
+|------|------|
+| `NVIC_EnableIRQ(IRQn)` | 使能中断通道 |
+| `NVIC_DisableIRQ(IRQn)` | 禁止中断通道 |
+| `NVIC_SetPriority(IRQn, priority)` | 设置中断优先级 |
+| `NVIC_SetPriorityGrouping(group)` | 设置优先级分组 |
+
+---
+
+## 常见问题与避坑
+
+1. **中断不触发** → 检查 NVIC 是否使能、EXTI IMR 是否允许、GPIO 模式是否正确(不能是模拟输入)
+2. **中断反复触发** → EXTI 的 PR 标志位未清除(必须写1清除)
+3. **按键抖动导致误触发** → 加软件延时消抖(10~15ms)
+4. **高了优先级的任务被卡死** → 中断服务函数要尽量简短(只设标志位,不处理复杂逻辑)
+5. **多个中断共用一个入口** → 在 ISR 中判断 PR 寄存器的不同位区分来源
+6. **HAL 库中中断不工作** → 检查 HAL_GPIO_EXTI_IRQHandler 是否在启动文件中正确注册

+ 223 - 0
X-Knowledge-Base/raw/Joplin/嵌入式+Linux/STM32学习笔记/05-系统时钟RCC详解.md

@@ -0,0 +1,223 @@
+---
+tags: [source-summary]
+type: source
+source: "尚硅谷嵌入式技术之STM32单片机(基础篇)V1.0.2 — 第5章:时钟系统"
+author: "尚硅谷研究院"
+date: 2026-07-15
+created: 2026-07-15
+---
+
+# 系统时钟RCC详解
+
+> **用生活理解**:时钟系统就像城市的电力系统——不同的设备需要不同的电压(频率)。CPU处理器要高速电(72MHz),APB1外设要中速电(36MHz),RTC实时时钟要独立不间断供电(32.768KHz)。RCC就是配电房,负责分配和管理所有的时钟。
+
+---
+
+## 为什么需要多个时钟源
+
+STM32 设计多个时钟源的核心目的:**节能**。
+
+所有外设都跑 72MHz 会浪费大量功耗。不同外设对速度要求不同:
+- CPU 内核:需要最高速度(72MHz)
+- GPIO、USART1、SPI1 等(挂载在 APB2):需要较高速度
+- USART2/3、I2C、TIM 等(挂载在 APB1):需要适中速度
+- RTC、看门狗:需要低速独立时钟(32.768KHz、40KHz)
+
+---
+
+## 时钟树总览
+
+![STM32F103时钟树](assets/rcc_时钟树.png)
+
+> **参考**:参考手册 §7(RCC 寄存器)中的时钟树框图
+> **参考**:开发板原理图晶振电路部分(HSE 8MHz + LSE 32.768KHz)
+
+### 五大时钟源
+
+| 时钟源 | 类型 | 频率 | 精度 | 用途 |
+|--------|------|------|------|------|
+| **HSI** | 内部RC | 8MHz | 较差(~1%) | 低成本方案、HSE故障后备 |
+| **HSE** | 外部晶振 | 4~16MHz(典型8MHz) | 高(~50ppm) | 系统时钟首选来源 |
+| **PLL** | 锁相环倍频 | 最高72MHz | — | 产生CPU最高频率 |
+| **LSI** | 内部RC | ~40KHz | 差(~10%) | IWDG、AWU自动唤醒 |
+| **LSE** | 外部晶振 | 32.768KHz | 高 | RTC实时时钟 |
+
+> **注意**:HSE 精度高的原因是外部晶振的品质远好于芯片内部的 RC 振荡器。HSI 精度差的根源是 RC 振荡器受温度和电压影响大。
+
+### 时钟树逐级分析
+
+```
+HSE(8MHz) ──────┐
+                 ├──→ PLLSRC ─→ PLLx9 ─→ SYSCLK(72MHz) ─→ AHB Prescaler(/1~512)
+                 │                                                          │
+HSI(8MHz) ───────┘                                     ┌────────────────────┘
+                                                         │
+                                                    AHB Bus(72MHz)
+                                                         │
+                                          ┌──────────────┼──────────────┐
+                                          ↓              ↓              ↓
+                                      APB1 Prescaler   APB2 Prescaler  其它
+                                          (/1~16)         (/1~16)      
+                                          ↓              ↓
+                                      APB1 Bus(36MHz)   APB2 Bus(72MHz)
+                                          ↓              ↓
+                                      TIMx 倍频器       TIMx 倍频器
+                                          (×2)            (×2)
+                                          ↓              ↓
+                                      TIM 时钟(72MHz)   TIM 时钟(72MHz)
+```
+
+**关键路径**:
+```
+8MHz(HSE) → PLLSRC → PLLMUL(x9) → SYSCLK(72MHz) → AHB(72MHz)
+                                                    → APB1(36MHz, max)
+                                                    → APB2(72MHz, max)
+```
+
+> **注意**:APB1 最大 36MHz(因为 APB1 预分频器 /2),APB2 最大 72MHz(/1)。
+
+---
+
+### 各总线和外设的时钟关系
+
+| 总线 | 最高频率 | 挂载的外设 |
+|------|---------|-----------|
+| AHB | 72MHz | Flash、SRAM、DMA、SDIO |
+| APB1 | 36MHz | USART2/3、I2C1/2、SPI2/3、TIM2~7、RTC(后备域)、PWR、BKP |
+| APB2 | 72MHz | GPIO(A~G)、USART1、SPI1、TIM1、ADC1/2/3、AFIO |
+
+> **结论**:高带宽外设(USART1、SPI1)挂在 APB2 才能跑到较高波特率。低功耗外设(I2C、USART2)挂在 APB1 降低功耗。
+
+---
+
+## 默认时钟配置(启动文件分析)
+
+STM32 上电后默认使用 HSI(8MHz)作为系统时钟,直到 SystemInit() 完成 PLL 配置切换。
+
+**启动流程**:
+```
+复位 → startup_hd.s → SystemInit() → main()
+```
+
+**SystemInit() 伪代码(简化)**:
+
+```c
+void SystemInit(void)
+{
+    /* 1. 复位RCC配置 */
+    RCC->CR |= 0x00000001;      // HSI 开启
+    RCC->CFGR = 0x00000000;     // 复位CFGR(SYSCLK=HSI)
+    RCC->CR &= 0xFEF6FFFF;      // HSE 关闭、PLL 关闭
+
+    /* 2. 配置 Flash 等待周期(72MHz 需要 2 个等待周期) */
+    FLASH->ACR = FLASH_ACR_PRFTBE | FLASH_ACR_LATENCY_2;
+
+    /* 3. 配置 HSE+PLL → 72MHz */
+    RCC->CR |= RCC_CR_HSEON;                // 开启 HSE
+    while (!(RCC->CR & RCC_CR_HSERDY));     // 等待 HSE 就绪
+
+    RCC->CFGR |= RCC_CFGR_PLLSRC;           // PLL 时钟源 = HSE
+    RCC->CFGR |= RCC_CFGR_PLLMULL9;         // PLL 9 倍频
+
+    RCC->CFGR |= RCC_CFGR_HPRE_DIV1;        // AHB 分频 = /1
+    RCC->CFGR |= RCC_CFGR_PPRE1_DIV2;       // APB1 分频 = /2
+    RCC->CFGR |= RCC_CFGR_PPRE2_DIV1;       // APB2 分频 = /1
+
+    RCC->CR |= RCC_CR_PLLON;                // 启动 PLL
+    while (!(RCC->CR & RCC_CR_PLLRDY));     // 等待 PLL 就绪
+
+    RCC->CFGR |= RCC_CFGR_SW_PLL;           // 切换系统时钟为 PLL
+    while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL); // 等待切换完成
+}
+```
+
+> **参考**:`system_stm32f1xx.c` 中的 SystemInit() 完整源码
+
+### 时钟就绪标志
+
+| 标志位 | 寄存器 | 说明 |
+|--------|--------|------|
+| HSIRDY | CR[1] | HSI 就绪 |
+| HSERDY | CR[17] | HSE 就绪 |
+| PLLRDY | CR[25] | PLL 就绪 |
+| LSIRDY | CSR[1] | LSI 就绪 |
+| LSERDY | BDCR[1] | LSE 就绪 |
+
+### HAL 版配置 (HAL_RCC_ClockConfig)
+
+HAL 库使用 `RCC_OscInitTypeDef` 和 `RCC_ClkInitTypeDef` 结构体完成同样的配置:
+
+```c
+void SystemClock_Config(void)
+{
+    RCC_OscInitTypeDef RCC_OscInitStruct = {0};
+    RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
+
+    /* 配置 HSE + PLL */
+    RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;  // 选择HSE
+    RCC_OscInitStruct.HSEState = RCC_HSE_ON;                    // 开启HSE
+    RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;     // HSE不分频
+    RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;                // 开启PLL
+    RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;        // PLL源=HSE
+    RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;                // 9倍频
+    HAL_RCC_OscConfig(&RCC_OscInitStruct);
+
+    /* 配置总线分频 */
+    RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK
+                                | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
+    RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;   // SYSCLK源自PLL
+    RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;          // AHB不分频
+    RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;           // APB1/2
+    RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;           // APB2/1
+    HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2);   // Flash 2等待
+}
+```
+
+---
+
+## 修改系统时钟的核心步骤
+
+如果需要修改系统时钟(比如降低频率省电):
+
+```
+1. 关闭 PLL
+2. 修改 PLL 倍频系数
+3. 修改 Flash 等待周期(与频率匹配)
+4. 重新开启 PLL 并等待就绪
+5. 切换系统时钟源为 PLL
+```
+
+**Flash 等待周期与频率的关系**:
+
+| 系统时钟 | Flash 等待周期 |
+|---------|---------------|
+| 0~24MHz | 0 (零等待) |
+| 24~48MHz | 1 |
+| 48~72MHz | 2 |
+
+---
+
+## 核心配置速查表
+
+| 配置 | 寄存器方式 | HAL库方式 |
+|------|----------|----------|
+| 开启 HSE | `RCC->CR |= RCC_CR_HSEON` | `HSEState = RCC_HSE_ON` |
+| 开启 PLL | `RCC->CR |= RCC_CR_PLLON` | `PLLState = RCC_PLL_ON` |
+| PLL源=HSE | `RCC->CFGR |= RCC_CFGR_PLLSRC` | `PLLSource = RCC_PLLSOURCE_HSE` |
+| PLL 9倍频 | `RCC->CFGR |= RCC_CFGR_PLLMULL9` | `PLLMUL = RCC_PLL_MUL9` |
+| AHB/1 | `RCC->CFGR |= RCC_CFGR_HPRE_DIV1` | `AHBCLKDivider = RCC_SYSCLK_DIV1` |
+| APB1/2 | `RCC->CFGR |= RCC_CFGR_PPRE1_DIV2` | `APB1CLKDivider = RCC_HCLK_DIV2` |
+| APB2/1 | `RCC->CFGR |= RCC_CFGR_PPRE2_DIV1` | `APB2CLKDivider = RCC_HCLK_DIV1` |
+| SYSCLK=PLL | `RCC->CFGR |= RCC_CFGR_SW_PLL` | `SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK` |
+| Flash 2等待 | `FLASH->ACR = 0x05` | `FLASH_LATENCY_2` |
+
+---
+
+## 常见问题与避坑
+
+1. **修改 PLL 倍频后系统死机** → 检查 Flash 等待周期是否对应新频率
+2. **外设时钟不开启** → 所有外设使用前必须手动开启时钟(`RCC->APBxENR |= ...`)
+3. **ADC 采样不准** → ADC 需要独立的时钟配置(ADC 预分频器),不能直接用系统时钟
+4. **HSE 起振失败(HSERDY 始终为 0)** → 检查晶振电路、负载电容值、PCB 布局
+5. **USB 不通** → USB 外设需要精确的 48MHz 时钟,USB 预分频器需要单独配置
+6. **时钟切换失败(SWS 不对应)** → 新时钟源未就绪就切换,需等待就绪标志

+ 369 - 0
X-Knowledge-Base/raw/Joplin/嵌入式+Linux/STM32学习笔记/06-串口USART通信.md

@@ -0,0 +1,369 @@
+---
+tags: [source-summary]
+type: source
+source: "尚硅谷嵌入式技术之STM32单片机(基础篇)V1.0.2 — 第8章:USART通信 + 配套代码07~12"
+author: "尚硅谷研究院"
+date: 2026-07-15
+created: 2026-07-15
+---
+
+# 串口USART通信
+
+> **用生活理解**:USART 串口通信就像两个人之间拉了一根电话线——一次只能一个人说(半双工),或者可以两个人同时说(全双工)。双方约定好说话的速度(波特率)、一句话的格式(数据位+校验+停止位),才能正常沟通。printf 重定向就是给这个电话线配了一个自动翻译机——把 printf 的内容自动通过串口发出去。
+
+---
+
+## USART概述
+
+### 通信分类
+
+| 分类 | 定义 | 示例 |
+|------|------|------|
+| **单工** | 数据只在一个方向传输 | 广播 |
+| **半双工** | 双方可以交替发送,但不能同时 | 对讲机 |
+| **全双工** | 双方可同时发送 | 电话 |
+| **同步** | 有时钟线同步 | SPI、I2C |
+| **异步** | 无时钟线,约定波特率 | USART |
+
+USART = Universal Synchronous/Asynchronous Receiver/Transmitter
+通用同步/异步收发器。STM32F103 的 USART1 支持同步模式,USART2/3 仅异步。
+
+### 异步串行协议帧格式
+
+```
+    空闲      起始位     数据位(8/9位)     校验位(可选)  停止位(1/2位)
+    ──────┐  ┌──┐──┐──┐──┐──┐──┐──┐──┐──┌──┐────┐────────
+           │  │  │  │  │  │  │  │  │  │  │  │    │
+    ──────┘──┘  └──┘──┘──┘──┘──┘──┘──┘──┘──┘────┘────────
+           ↑  LSB(先发)                    MSB(后发)
+```
+
+| 段 | 位数 | 说明 |
+|----|------|------|
+| 起始位 | 1 | 拉低电平,表示开始发送 |
+| 数据位 | 8或9 | 先发 LSB(最低有效位) |
+| 校验位 | 0或1 | 奇校验/偶校验/无校验 |
+| 停止位 | 1/1.5/2 | 拉高电平,表示传输结束 |
+
+**校验位计算**:
+- **无校验(No Parity)**:不发送校验位
+- **奇校验(Odd)**:数据位中"1"的个数为奇数时,校验位=0;为偶数时,校验位=1
+- **偶校验(Even)**:数据位中"1"的个数为偶数时,校验位=0;为奇数时,校验位=1
+
+### 波特率
+
+波特率 = 每秒传输的位数(bps)。
+
+常用值:9600、19200、38400、115200、921600
+
+**STM32 USART 波特率计算公式**:
+
+```
+Tx/Rx 波特率 = fCK / (16 × USARTDIV)
+
+其中: fCK = USART 时钟频率
+      USARTDIV = BRR 寄存器中写入的分频值(含小数部分)
+```
+
+> 示例:fCK=72MHz(USART1 挂在 APB2),目标 115200bps
+> USARTDIV = 72,000,000 / (16 × 115200) = 39.0625
+> BRR 寄存器写入值 = 0x271
+> 
+> **参考**:参考手册 §18(USART 寄存器描述)
+
+**各 USART 模块的频率差异**:
+
+| USART | 总线 | 时钟频率 |
+|-------|------|---------|
+| USART1 | APB2 | 72MHz |
+| USART2 | APB1 | 36MHz |
+| USART3 | APB1 | 36MHz |
+
+> **注意**:USART2/3 只有 APB1 时钟的一半,相同 BRR 值下波特率也减半。
+
+---
+
+## USART功能框图
+
+关键组成部分:
+1. **数据寄存器(DR)**:发送/接收数据的缓冲区
+2. **发送移位寄存器**:将 DR 中并行数据串行化发送
+3. **接收移位寄存器**:将 RXD 串行数据转为并行存入 DR
+4. **波特率发生器**:基于 BRR 产生收发时钟
+5. **控制逻辑**:CR1/CR2/CR3 寄存器控制各种模式
+
+> **参考**:参考手册 §18 中的 USART 功能框图
+
+### 关键寄存器
+
+| 寄存器 | 地址偏移 | 功能 |
+|--------|---------|------|
+| SR | 0x00 | 状态寄存器(TXE、RXNE、IDLE、TC 等标志位) |
+| DR | 0x04 | 数据寄存器(发送/接收共用) |
+| BRR | 0x08 | 波特率寄存器(USARTDIV 值) |
+| CR1 | 0x0C | 控制寄存器1(UE、TE、RE、M、PCE、PS、TXEIE、RXNEIE) |
+| CR2 | 0x10 | 控制寄存器2(STOP 位配置、LINEN 等) |
+| CR3 | 0x14 | 控制寄存器3(CTSE、RTSE、DMAT、DMAR) |
+
+**SR 状态寄存器的重要位**:
+
+| 位 | 名称 | 说明 | 用途 |
+|----|------|------|------|
+| 5 | RXNE | 接收数据寄存器非空 | 有数据收到时=1,读DR后自动清0 |
+| 6 | TC | 发送完成 | 发送完成后=1 |
+| 7 | TXE | 发送数据寄存器空 | 可写入数据时=1,写DR后自动清0 |
+| 4 | IDLE | 空闲线路检测 | 收到空闲帧(高电平超过1帧)时=1 |
+
+---
+
+## 硬件电路设计
+
+USART1 使用 PA9(TX)和 PA10(RX):
+- **PA9 (USART1_TX)**:复用推挽输出(CNF=10, MODE=11)
+- **PA10 (USART1_RX)**:浮空输入(CNF=01, MODE=00)
+
+通常还需要连接 CH340G(USB转串口芯片)与电脑通信。
+
+> **参考**:开发板原理图串口部分、CH340G 数据手册
+
+---
+
+## 实验:串口收/发通信
+
+### 需求描述
+
+通过串口发送字符/字符串,接收并回显收到的数据。波特率 115200,8N1(8 数据位、无校验、1 停止位)。
+
+### 软件设计(寄存器版 — 轮询方式)
+
+**项目路径**:`stm32_base/07_usart_polling_register`
+
+**文件:`stm32_base/07_usart_polling_register/Hardware/USART/usart.h`**
+
+```c
+#ifndef __USART_H
+#define __USART_H
+
+#include "stm32f10x.h"
+
+void USART_Init(void);
+void USART_SendChar(uint8_t ch);
+uint8_t USART_ReceiveChar(void);
+void USART_SendString(uint8_t *str, uint8_t size);
+void USART_ReceiveString(uint8_t buffer[], uint8_t *size);
+
+#endif
+```
+
+**文件:`stm32_base/07_usart_polling_register/Hardware/USART/usart.c`**
+
+```c
+#include "usart.h"
+
+// USART1 初始化(PA9-TX, PA10-RX, 115200-8N1)
+void USART_Init(void)
+{
+    /* ===== 1. 开启时钟 ===== */
+    // USART1 挂载在 APB2 总线上
+    RCC->APB2ENR |= RCC_APB2ENR_USART1EN;   // |=: USART1时钟使能
+    RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;      // |=: GPIOA时钟使能
+
+    /* ===== 2. 配置GPIO模式 ===== */
+    // PA9 (TX): 复用推挽输出 CNF=10, MODE=11(50MHz)
+    // CRH控制Pin8~Pin15, PA9的位域在第4~7位
+    GPIOA->CRH |= GPIO_CRH_MODE9;             // MODE9[1:0]=11
+    GPIOA->CRH |= GPIO_CRH_CNF9_1;             // CNF9[1]=1
+    GPIOA->CRH &= ~GPIO_CRH_CNF9_0;            // CNF9[0]=0
+
+    // PA10 (RX): 浮空输入 CNF=01, MODE=00
+    GPIOA->CRH &= ~GPIO_CRH_MODE10;            // MODE10=00(输入)
+    GPIOA->CRH &= ~GPIO_CRH_CNF10_1;           // CNF10[1]=0
+    GPIOA->CRH |= GPIO_CRH_CNF10_0;            // CNF10[0]=1
+
+    /* ===== 3. 配置USART ===== */
+    // 3.1 波特率 115200 (72MHz / (16 * 115200) = 39.0625 = 0x271)
+    USART1->BRR = 0x271;
+
+    // 3.2 使能USART1、发送、接收
+    USART1->CR1 |= USART_CR1_UE;   // UE=1: USART使能
+    USART1->CR1 |= (USART_CR1_TE | USART_CR1_RE);  // TE=1: 发送使能, RE=1: 接收使能
+
+    // 3.3 配置帧格式: 8位数据位, 无校验, 1位停止位
+    USART1->CR1 &= ~USART_CR1_M;    // M=0: 8位数据位
+    USART1->CR1 &= ~USART_CR1_PCE;  // PCE=0: 无校验
+    USART1->CR2 &= ~USART_CR2_STOP; // STOP=00: 1位停止位
+}
+
+// 发送一个字符(轮询方式)
+void USART_SendChar(uint8_t ch)
+{
+    // 等待 TXE (发送数据寄存器空) = 1
+    // TXE=1 表示 DR 中数据已转移到移位寄存器,可以写入新数据
+    while ((USART1->SR & USART_SR_TXE) == 0)  // &测试: TXE位是否为0
+    {
+    }
+
+    // 写入数据到 DR,硬件自动移位发送
+    USART1->DR = ch;
+}
+
+// 接收一个字符(轮询方式)
+uint8_t USART_ReceiveChar(void)
+{
+    // 等待 RXNE (接收数据寄存器非空) = 1
+    // RXNE=1 表示 DR 中已收到新数据
+    while ((USART1->SR & USART_SR_RXNE) == 0)
+    {
+    }
+
+    return USART1->DR;
+}
+
+// 发送字符串
+void USART_SendString(uint8_t *str, uint8_t size)
+{
+    for (uint8_t i = 0; i < size; i++)
+    {
+        USART_SendChar(str[i]);
+    }
+}
+
+// 接收字符串(检测空闲帧 IDLE 判断结束)
+void USART_ReceiveString(uint8_t buffer[], uint8_t *size)
+{
+    uint8_t i = 0;
+
+    // 逐字符接收直到检测到空闲帧(IDLE=1)
+    while ((USART1->SR & USART_SR_IDLE) == 0)  // IDLE=0 时说明还在接收数据
+    {
+        buffer[i] = USART_ReceiveChar();
+        i++;
+    }
+
+    // 读取 DR 清除 IDLE 标志(先读SR再读DR)
+    USART1->DR;
+
+    *size = --i;  // 减去IDLE引起的多余计数
+}
+```
+
+---
+
+### 软件设计(寄存器版 — printf重定向)
+
+**项目路径**:`stm32_base/11_usart_printf_register`
+
+通过重写 `fputc` 函数,将 `printf` 输出重定向到 USART1。
+
+**文件:`stm32_base/11_usart_printf_register/User/main.c`**
+
+```c
+#include "stm32f10x.h"
+#include <stdio.h>      // 使用 printf 需要
+
+// 重写 fputc —— printf 底层调用此函数输出每个字符
+// 参数: ch = 要输出的字符, f = 文件流指针(未使用)
+// 返回: 输出成功的字符
+int fputc(int ch, FILE *f)
+{
+    // USART1 发送一个字符
+    while ((USART1->SR & USART_SR_TXE) == 0)  // 等待 TX 缓冲区空
+    {
+    }
+    USART1->DR = ch;  // 写入字符到 DR
+
+    return ch;
+}
+
+int main(void)
+{
+    USART_Init();  // USART初始化(与轮询版相同)
+
+    printf("尚硅谷 STM32 串口 printf 实验\r\n");   // \r\n 是回车换行
+    printf("当前系统时钟: 72MHz\r\n");
+    printf("波特率: 115200, 数据格式: 8N1\r\n");
+
+    while (1)
+    {
+    }
+}
+```
+
+> **Keil 配置**:要使用 printf,必须在 Keil 中勾选 "Use MicroLIB"(微库):
+> Options for Target → Target → Code Generation → Use MicroLIB
+> 微库提供了精简版的 `printf` 实现。
+
+---
+
+### 软件设计(HAL库版)
+
+HAL 库封装了 USART 的寄存器操作,使用结构体 `UART_HandleTypeDef` 管理串口。
+
+**HAL 库串口配置流程**:
+```
+1. CubeMX 选择 USART1 异步模式
+2. 配置波特率、数据位、校验位、停止位
+3. 生成代码
+4. HAL_UART_Transmit() 发送 / HAL_UART_Receive() 接收
+```
+
+**HAL 库发送接收函数**:
+
+```c
+// 发送(超时模式)
+HAL_UART_Transmit(&huart1, (uint8_t *)"Hello", 5, 1000);
+// 参数: huart句柄, 数据指针, 数据长度, 超时ms
+
+// 接收(超时模式)
+HAL_UART_Receive(&huart1, buffer, 10, 1000);
+
+// 中断方式接收(推荐)
+HAL_UART_Receive_IT(&huart1, buffer, 10);
+// 接收10个字节后自动调用 HAL_UART_RxCpltCallback()
+```
+
+**printf 重定向(HAL 库版)**:
+
+```c
+// 基于 HAL_UART_Transmit 的重写
+int fputc(int ch, FILE *f)
+{
+    HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 1000);
+    return ch;
+}
+```
+
+---
+
+## 核心函数速查表
+
+### 寄存器版
+
+| 函数 | 说明 | 实现要点 |
+|------|------|---------|
+| `USART_Init()` | 时钟+GPIO+波特率+帧格式 | CR1/BRR/CR2 配置 |
+| `USART_SendChar(ch)` | 发送1字节 | 轮询 TXE 标志 |
+| `USART_ReceiveChar()` | 接收1字节 | 轮询 RXNE 标志 |
+| `USART_SendString(str, len)` | 发送字符串 | 循环调用 SendChar |
+| `USART_ReceiveString(buf, &len)` | 接收字符串 | 使用 IDLE 判断结束 |
+
+### HAL库版
+
+| HAL函数 | 说明 |
+|---------|------|
+| `HAL_UART_Transmit(huart, data, size, timeout)` | 轮询发送 |
+| `HAL_UART_Receive(huart, data, size, timeout)` | 轮询接收 |
+| `HAL_UART_Receive_IT(huart, data, size)` | 中断接收 |
+| `HAL_UART_Transmit_IT(huart, data, size)` | 中断发送 |
+| `HAL_UART_RxCpltCallback(huart)` | 接收完成回调 |
+
+---
+
+## 常见问题与避坑
+
+1. **串口无输出** → 检查波特率是否匹配、GPIO 模式(TX=复用推挽)、USART 时钟是否开启
+2. **printf 不输出** → Keil 中是否勾选 Use MicroLIB、fputc 是否重写、TXE 轮询是否正确
+3. **接收数据乱码** → 波特率误差超过 3%(检查 BRR 计算)、数据位/校验位/停止位不匹配
+4. **HAL_UART_Receive 阻塞** → 设置了超时但未收到足够数据;改用 `_IT` 中断方式
+5. **USART1 和 USART2/3 波特率不同** → 它们时钟源不同(APB2=72MHz, APB1=36MHz),BRR 值需分别计算
+6. **IDLE 中断逻辑不清** → IDLE 是"空闲帧"检测(连串高电平超过1帧时间),不是"数据接收完毕"

BIN
X-Knowledge-Base/raw/Joplin/嵌入式+Linux/STM32学习笔记/assets/gpio_内部结构.png


BIN
X-Knowledge-Base/raw/Joplin/嵌入式+Linux/STM32学习笔记/assets/gpio_端口布局.png


BIN
X-Knowledge-Base/raw/Joplin/嵌入式+Linux/STM32学习笔记/assets/led_电路原理图.png


BIN
X-Knowledge-Base/raw/Joplin/嵌入式+Linux/STM32学习笔记/assets/stm32f103zet6_复位电路.png


BIN
X-Knowledge-Base/raw/Joplin/嵌入式+Linux/STM32学习笔记/assets/stm32f103zet6_开发板实物图.png


BIN
X-Knowledge-Base/raw/Joplin/嵌入式+Linux/STM32学习笔记/assets/stm32f103zet6_时钟电路.png


BIN
X-Knowledge-Base/raw/Joplin/嵌入式+Linux/STM32学习笔记/assets/stm32f103zet6_电源电路.png


BIN
X-Knowledge-Base/raw/Joplin/嵌入式+Linux/STM32学习笔记/assets/stm32f103zet6_芯片引脚图.png


BIN
X-Knowledge-Base/raw/Joplin/嵌入式+Linux/STM32学习笔记/assets/stm32f103zet6_调试接口.png


+ 18 - 0
X-Knowledge-Base/wiki/log.md

@@ -44,6 +44,24 @@ type: log
 
     更新 `wiki/source-freertos.md`、`wiki/index.md`、`wiki/log.md`
 
+## 2026-07-15
+
+- `ingest`: 导入尚硅谷 STM32 基础篇笔记
+
+   原始资料归档:
+   - `raw/Joplin/嵌入式+Linux/STM32学习笔记/01-STM32概述与开发环境搭建.md`
+   - `raw/Joplin/嵌入式+Linux/STM32学习笔记/02-GPIO寄存器详解与三步进化法.md`
+   - `raw/Joplin/嵌入式+Linux/STM32学习笔记/03-GPIO输出:LED控制.md`
+   - `raw/Joplin/嵌入式+Linux/STM32学习笔记/04-GPIO输入与NVIC中断系统.md`
+   - `raw/Joplin/嵌入式+Linux/STM32学习笔记/05-系统时钟RCC详解.md`
+   - `raw/Joplin/嵌入式+Linux/STM32学习笔记/06-串口USART通信.md`
+   - `raw/Joplin/嵌入式+Linux/STM32学习笔记/assets/`(12张精选图片)
+
+   新建 Wiki 页面:
+   - `wiki/source-stm32-basic.md`(基础篇资料索引)
+
+   更新 `wiki/log.md`
+
 - `lint`: 清理 FreeRTOS 图片资源,重写 11 篇 raw 笔记
 
    清理:

+ 24 - 0
X-Knowledge-Base/wiki/source-stm32-basic.md

@@ -0,0 +1,24 @@
+---
+tags: [source-summary]
+type: source
+source: "尚硅谷嵌入式技术之STM32单片机(基础篇)V1.0.2"
+author: "尚硅谷研究院"
+date: 2026-07-15
+url: ""
+created: 2026-07-15
+---
+
+# 尚硅谷 STM32 基础篇笔记
+
+来源:尚硅谷嵌入式技术之STM32单片机(基础篇)V1.0.2 — STM32概述、GPIO、中断、时钟、USART
+
+## 笔记列表
+
+| 编号 | 文件 | 内容 |
+|------|------|------|
+| 01 | `01-STM32概述与开发环境搭建.md` | ARM Cortex-M3、STM32命名、Keil安装、最小系统、项目结构 |
+| 02 | `02-GPIO寄存器详解与三步进化法.md` | GPIO内部结构、8种工作模式、7个寄存器、三步进化法 |
+| 03 | `03-GPIO输出:LED控制.md` | LED电路、流水灯、Delay模块、模块化封装、寄存器+HAL双版 |
+| 04 | `04-GPIO输入与NVIC中断系统.md` | NVIC优先级分组、EXTI外部中断、按键消抖、中断服务函数 |
+| 05 | `05-系统时钟RCC详解.md` | 时钟树、5个时钟源、PLL配置、SystemInit解析 |
+| 06 | `06-串口USART通信.md` | 串行协议、波特率计算、轮询收发、printf重定向、寄存器+HAL双版 |

+ 788 - 0
docs/superpowers/plans/2026-07-15-stm32-ingest.md

@@ -0,0 +1,788 @@
+# 尚硅谷 STM32 笔记导入实现计划
+
+> **For agentic workers:** REQUIRED SUB-SKILL: 使用 `subagent-driven-development` 或 `executing-plans` 逐任务执行。复选框 `- [ ]` 标记跟踪进度。
+
+**目标**:将尚硅谷 STM32 全套 4 份 DOCX 笔记 + 配套源码转换为 21 篇结构化 Markdown 笔记,存入 `X-Knowledge-Base/raw/Joplin/嵌入式+Linux/STM32学习笔记/`
+
+**处理方法**:每批次:pandoc 转 MD → 按章节拆篇 → 逐篇扩写(参考手册引用 + 原理图引用 + 网络资料补充)→ 从源码复制代码 + 逐行注释 → 图片 API 验证 → git 提交
+
+**参考资料**:
+- `docs/如何将他人文档整理为LLM-Wiki笔记.md`
+- `docs/superpowers/specs/2026-07-15-stm32-silicon-valley-ingest-design.md`
+- `X-Knowledge-Base/raw/Joplin/嵌入式+Linux/FreeRTOS学习笔记/01-*.md`(自由格式参考)
+
+**图片 API**:使用视觉模型逐张验证图片内容,仅保留寄存器位域图/框图/时序图/原理图
+
+**最终提交**:全部 4 批次完成后,统一次提交 `ingest: 尚硅谷STM32全套笔记导入`
+
+---
+
+## 文件产出清单
+
+### 目标目录:`X-Knowledge-Base/raw/Joplin/嵌入式+Linux/STM32学习笔记/`
+
+| 编号 | 文件名 | 来源 DOCX | 代码项目 |
+|------|--------|----------|---------|
+| 01 | `01-STM32概述与开发环境搭建.md` | 基础篇 | — |
+| 02 | `02-GPIO寄存器详解与三步进化法.md` | 基础篇 | — |
+| 03 | `03-GPIO输出:LED控制.md` | 基础篇 | stm32_base/01~04 |
+| 04 | `04-GPIO输入与NVIC中断系统.md` | 基础篇 | stm32_base/05~06 |
+| 05 | `05-系统时钟RCC详解.md` | 基础篇 | — |
+| 06 | `06-串口USART通信.md` | 基础篇 | stm32_base/07~12 |
+| 07 | `07-I2C通信与EEPROM 24C02.md` | 进阶篇 | stm32_base/13~15 |
+| 08 | `08-SysTick与通用定时器TIM.md` | 进阶篇 | stm32_base/16~19 |
+| 09 | `09-TIM高级应用:PWM与输入捕获.md` | 进阶篇 | stm32_base/20~27 |
+| 10 | `10-DMA数据传输.md` | 进阶篇 | stm32_base/28~31 |
+| 11 | `11-ADC模数转换.md` | 进阶篇 | stm32_base/32~35 |
+| 12 | `12-SPI通信与FSMC总线.md` | 进阶篇 | stm32_base/36~42 |
+| 13 | `13-CAN通信协议与bxCAN外设.md` | 高级篇 | stm32/01~04 |
+| 14 | `14-以太网通信与W5500.md` | 高级篇 | stm32/05~09 |
+| 15 | `15-WiFi通信与ESP32-C3.md` | 高级篇 | stm32/10~11 |
+| 16 | `16-BLE低功耗蓝牙.md` | 高级篇 | stm32/12 |
+| 17 | `17-LoRa远距离通信.md` | 高级篇 | stm32/13~14 |
+| 18 | `18-电源管理与低功耗模式.md` | 扩展篇 | stm32/15~20 |
+| 19 | `19-BKP备份寄存器与RTC实时时钟.md` | 扩展篇 | stm32/21~26 |
+| 20 | `20-看门狗IWDG与WWDG.md` | 扩展篇 | stm32/27~28 |
+| 21 | `21-附录:HAL库架构与Keil MDK深入.md` | 扩展篇 | — |
+
+### 附加产出
+- `X-Knowledge-Base/raw/Joplin/嵌入式+Linux/STM32学习笔记/assets/` — 精选图片
+- `wiki/source-stm32-*.md` — 资料摘要页
+- `wiki/index.md` — 更新全局索引
+- `wiki/log.md` — 追加变更日志
+
+---
+
+## 各批次通用步骤模板
+
+每篇笔记的处理步骤一致,以下为每篇的标准操作流程:
+
+1. **读取 pandoc 转换后的 MD 中对应章节内容**
+2. **读取对应源码项目文件**(main.c, driver.h, driver.c)
+3. **处理该章节图片**:用视觉 API 验证 → 重命名 → 复制到 assets/
+4. **撰写笔记**:
+   - 从原 DOCX 保留原意,但补充参考手册页码/原理图引用/网络资料
+   - 代码块直接从源文件复制,标注文件路径,每行位操作加注释
+   - 寄存器+HAL 双版
+   - 添加核心函数速查表 + 常见问题
+5. **写入目标路径**
+6. **追加 log 信息**
+
+---
+
+## 批次 1:基础篇(笔记 01~06)
+
+**来源 DOCX**:`上部-基础篇/01_笔记/01_尚硅谷嵌入式技术之STM32单片机(基础篇)1.0.2.docx`
+**代码目录**:`上部-基础篇/03_代码/stm32/`
+**参考手册**:`上部-基础篇/02_资料/02_stm32官方资料/1-STM32F10x-中文参考手册_最新.pdf`
+**原理图**:`上部-基础篇/02_资料/05_原理图/STM32-F103ZET6开发板.pdf`
+
+### 任务 1.1:准备阶段 — 转换基础篇 DOCX
+
+- [ ] **步骤 1.1.1:pandoc 转换 + 提取图片**
+
+```powershell
+pandoc "上部-基础篇/01_笔记/01_尚硅谷嵌入式技术之STM32单片机(基础篇)1.0.2.docx" -t markdown --wrap=none --extract-media="C:\Users\Administrator\AppData\Local\Temp\opencode\stm32_basic_media" -o "C:\Users\Administrator\AppData\Local\Temp\opencode\stm32_basic.md"
+```
+
+- [ ] **步骤 1.1.2:阅读转换结果概览**
+  读取 `stm32_basic.md` 前 500 行,确认章节结构和图片引用
+
+### 任务 1.2:笔记 01 — STM32概述与开发环境搭建
+
+**来源章节**:基础篇 DOCX 第1~3章(STM32概述 + Keil安装 + 最小系统)
+
+- [ ] **步骤 1.2.1:读取相关章节内容**
+  从 pandoc 输出的 MD 中读取 STM32概述、ARM Cortex-M3、命名规则、Keil安装、最小系统等章节
+
+- [ ] **步骤 1.2.2:读取参考资料**
+  - STM32F103ZET6 数据手册 §1~3(命名规则、引脚定义)
+  - 原理图 PDF 最小系统部分(电源/时钟/复位/下载调试电路)
+  - Cortex-M3 权威指南(内核架构)
+  - 代码项目 `stm32/01_led_register` 的工程结构
+
+- [ ] **步骤 1.2.3:处理本章图片**
+  - 定位本章节涉及的图片(image1~image33)
+  - 视觉 API 逐张验证内容
+  - 筛选保留:最小系统框图、命名规则图、开发板实物图
+  - 删除:IDE 安装界面截图(image12~image23)
+  - 重命名图片到 `assets/`
+
+- [ ] **步骤 1.2.4:撰写笔记 01**
+
+```markdown
+---
+tags: [source-summary]
+type: source
+source: "尚硅谷嵌入式技术之STM32单片机(基础篇)V1.0.2 — 第1~3章"
+author: "尚硅谷研究院"
+date: 2026-07-15
+created: 2026-07-15
+---
+
+# STM32概述与开发环境搭建
+
+> **用生活理解**:如果把STM32比作一台微型电脑——ARM内核就像电脑的CPU,而Keil MDK就像Visual Studio,开发板就是一台迷你主机。
+
+## STM32概述
+
+### 关于ARM内核
+- ARM = Advanced RISC Machines
+- Cortex-M3 内核特性:32位RISC、3级流水线、Thumb-2指令集、NVIC中断控制器
+- 参考:Cortex-M3 权威指南 第2章
+
+### 什么是STM32
+- ST = STMicroelectronics(意法半导体)
+- M = Microcontroller(微控制器)
+- 32 = 32位处理器
+- 基于 ARM Cortex-M 内核的32位MCU
+
+### STM32应用场景
+- 工业自动化、电机控制、物联网终端、消费电子、医疗设备
+
+### STM32系列MCU命名规则
+- STM32 F 103 Z E T 6 含义逐段解析
+- 参考:STM32F103xCDE 数据手册 §1(器件概览)
+
+## 开发板简介
+
+### 开发板实物图
+
+![开发板资源图](assets/xxx.png)
+
+### STM32F103ZET6 最小系统
+
+最小系统 = STM32芯片 + 电源 + 时钟 + 复位 + 下载调试
+
+**电源电路**:
+- 双路供电:USB Type-C (5V) → AMS1117 → 3.3V
+- ST-Link 直接提供 3.3V
+- 参考:原理图第1页(电源部分)
+
+**时钟电路**:
+- 外部8MHz晶振(HSE) + 32.768KHz晶振(LSE)
+- 原理图第2页
+
+**复位电路**:
+- NRST 引脚 + 按键 + RC电路
+- 原理图第3页
+
+**下载调试电路**:
+- SWD接口(SWDIO/SWCLK)+ ST-Link
+- 参考:原理图第3页
+
+## STM32开发方式
+
+三种开发方式对比:
+| 方式 | 特点 |
+|------|------|
+| **寄存器** | 直接操作内存地址,代码最小、最深理解硬件 |
+| **标准库** | 官方封装寄存器操作,函数名规范 |
+| **HAL库** | CubeMX图形化配置,移植性好,代码量大 |
+
+## 开发工具
+
+### Keil MDK
+- 下载 → 安装 → 离线芯片支持包 → 注册
+- 芯片包选型:STM32F103ZET6 → Keil.STM32F1xx_DFP
+
+### 项目文件结构
+```
+Project/
+├── Start/          # 启动文件 startup_stm32f10x_hd.s
+├── User/           # main.c + 用户代码
+├── Hardware/       # 外设驱动(LED/KEY等)
+├── Library/        # 标准库文件
+├── System/         # system_stm32f1xx.c
+└── Objects/        # 编译输出
+```
+
+### 启动文件选择
+| 文件 | 适用芯片 |
+|------|---------|
+| startup_stm32f10x_ld.s | 16~32KB Flash |
+| startup_stm32f10x_md.s | 64~128KB Flash |
+| startup_stm32f10x_hd.s | 256~512KB Flash |
+
+STM32F103ZET6 = 512KB Flash → 选 **hd**
+
+## 烧录方法
+- ST-Link SWD 方式(4线:SWDIO/SWCLK/VCC/GND)
+
+## 核心函数速查
+
+(环境搭建篇无代码 API,但列出常用概念)
+
+## 常见问题与避坑
+- 芯片支持包在线安装太慢 → 离线下载安装
+- Keil MDK 需注册 → 使用注册机
+- 下载失败 → 检查 ST-Link 驱动、SWD 接线
+```
+
+- [ ] **步骤 1.2.5:写入文件**
+
+写入 `X-Knowledge-Base/raw/Joplin/嵌入式+Linux/STM32学习笔记/01-STM32概述与开发环境搭建.md`
+
+### 任务 1.3:笔记 02 — GPIO寄存器详解与三步进化法
+
+**来源章节**:基础篇 DOCX 第4~5章(点亮LED + GPIO详解)
+**代码项目**:`stm32/01_led_register`
+
+- [ ] **步骤 1.3.1:读取 DOCX 相关章节 + 源码**
+  读取:GPIO 8种模式、7个寄存器、三步进化法
+  读取源码:`stm32/01_led_register/User/main.c`
+
+- [ ] **步骤 1.3.2:网络补充**
+  搜索补充:GPIO 内部结构框图(P-MOS/N-MOS/施密特触发器)、输出速度与EMI关系
+
+- [ ] **步骤 1.3.3:处理图片**
+  GPIO 寄存器位域图、内部结构框图保留;IDE截图删除
+
+- [ ] **步骤 1.3.4:撰写笔记 02**
+  内容要点:
+  - GPIO 内部结构框图 + 逐部件分析
+  - 8种工作模式表格(推挽/开漏/浮空/上拉/下拉/模拟/复用推挽/复用开漏)
+  - 关键寄存器表格:
+    | 寄存器 | 地址偏移 | 功能 |
+    | CRL | 0x00 | 低8位端口配置(MODE + CNF) |
+    | CRH | 0x04 | 高8位端口配置 |
+    | IDR | 0x08 | 输入数据寄存器 |
+    | ODR | 0x0C | 输出数据寄存器 |
+    | BSRR | 0x10 | 位设置/清除寄存器 |
+    | BRR | 0x14 | 位清除寄存器 |
+    | LCKR | 0x18 | 锁定寄存器 |
+  - "三步进化法"完整演示:
+    - 步骤1:裸地址操作(`*(uint32_t *)(0x40010800 + 0x0C)`)
+    - 步骤2:结构体宏定义(`GPIOA->ODR`)
+    - 步骤3:位宏定义(`GPIOA->ODR |= GPIO_ODR_ODR0`)
+  - 代码从 `01_led_register/User/main.c` 复制
+  - 原生代码包含注释"改进1/改进2/改进3",保留并扩展
+  - 参考手册 §8 寄存器位域
+  - 原理图 LED 电路
+
+- [ ] **步骤 1.3.5:写入文件**
+
+### 任务 1.4:笔记 03 — GPIO输出:LED控制
+
+**来源章节**:基础篇 第6章(LED流水灯)
+**代码项目**:`stm32/02_led_flow_register`、`stm32/03_led_flow_pro_register`、`stm32/04_led_flow_pro_hal`
+
+- [ ] **步骤 1.4.1:读取源码**
+  - `02_led_flow_register/User/main.c`
+  - `03_led_flow_pro_register/User/main.c`
+  - `03_led_flow_pro_register/Hardware/LED/led.c`、`led.h`
+  - `03_led_flow_pro_register/User/Delay.h`、`Delay.c`
+  - `04_led_flow_pro_hal/User/main.c`
+  - `04_led_flow_pro_hal/Hardware/LED/led.c`、`led.h`
+
+- [ ] **步骤 1.4.2:撰写笔记 03**
+  内容要点:
+  - LED 电路原理(低电平点亮、限流电阻计算)
+  - 寄存器版:流水灯三种实现(移位法/查表法/状态机法)
+  - 模块化封装:Driver_LED.h + Driver_LED.c
+  - Delay 模块:软件延时 vs SysTick 硬件定时差异
+  - HAL 版:CubeMX 配置 + HAL_GPIO_WritePin
+  - 代码复制:从源文件复制完整 main.c/led.c/led.h,每行注释
+  - 位运算注释示例:
+    ```c
+    GPIOA->ODR &= ~GPIO_ODR_ODR0;   // &=~ 按位与+取反: 保留其他位不变, 只将ODR0位清0 → PA0输出低电平
+    ```
+
+- [ ] **步骤 1.4.3:写入文件**
+
+### 任务 1.5:笔记 04 — GPIO输入与NVIC中断系统
+
+**来源章节**:基础篇 第7章(按键 + 中断)
+**代码项目**:`stm32/05_key_led_register`、`stm32/06_key_led_hal`
+
+- [ ] **步骤 1.5.1:读取源码**
+  - `05_key_led_register/User/main.c` + `Hardware/KEY/key.c` + `Hardware/LED/led.c`
+  - `06_key_led_hal/User/main.c`
+
+- [ ] **步骤 1.5.2:撰写笔记 04**
+  内容要点:
+  - 机械按键消抖(硬件RC消抖 / 软件延时10~15ms消抖)
+  - 原理图 KEY 电路(PF10 上拉输入)
+  - EXTI 外部中断配置流程(GPIO配置→中断线选择→触发条件→NVIC使能→中断服务函数)
+  - NVIC 优先级分组(4种组别:NVIC_PriorityGroup_0~4)
+  - 中断优先级 = 抢占优先级 + 子优先级
+  - 寄存器版代码 + HAL 版代码,分别展示
+  - 参考手册 §9 EXTI 寄存器、§8 NVIC 寄存器
+
+- [ ] **步骤 1.5.3:写入文件**
+
+### 任务 1.6:笔记 05 — 系统时钟RCC详解
+
+**来源章节**:基础篇 第5章后半部分(RCC时钟树)
+**代码项目**:无需特定项目(系统初始化代码)
+
+- [ ] **步骤 1.6.1:读取参考资料**
+  - 参考手册 §7 RCC 寄存器
+  - 启动文件中的 SystemInit 调用
+  - `system_stm32f1xx.c` 中的 SystemInit() 源码
+  - 原理图晶振电路
+
+- [ ] **步骤 1.6.2:网络补充**
+  搜索补充:STM32F103 时钟树完整框图、PLL 配置限制
+
+- [ ] **步骤 1.6.3:撰写笔记 05**
+  内容要点:
+  - 时钟树逐级分析:
+    ```
+    HSE(8MHz) → PLL(x9) → SYSCLK(72MHz) → AHB(72MHz) → APB1(36MHz) → APB2(72MHz)
+    ```
+  - 5个时钟源详解:HSI/HSE/PLL/LSI/LSE
+  - SystemInit() 源码逐行解析(参考手册 §7.2 时钟配置)
+  - HAL 版 SystemClock_Config() 对照分析
+  - RCC 关键寄存器:CR(时钟控制)/CFGR(时钟配置)/BDCR/CIR
+  - 修改主频注意事项(Flash 等待周期需同步调整)
+
+- [ ] **步骤 1.6.4:写入文件**
+
+### 任务 1.7:笔记 06 — 串口USART通信
+
+**来源章节**:基础篇 第8章(USART通信)
+**代码项目**:`stm32/07_usart_register` ~ `stm32/12_usart_printf_hal`
+
+- [ ] **步骤 1.7.1:读取源码**
+  - `07_usart_register/User/main.c` + `Hardware/USART/usart.c`
+  - `08_usart_iterrupt_register/User/main.c`
+  - `11_usart_printf_register/User/main.c`
+  - `12_usart_printf_hal/User/main.c`
+
+- [ ] **步骤 1.7.2:撰写笔记 06**
+  内容要点:
+  - 异步串行通信协议帧格式(起始位+数据位+校验位+停止位)
+  - 单工/半双工/全双工区别
+  - 同步/异步区别
+  - 波特率计算公式:`Baud = fCK / (16 × USARTDIV)`
+  - USART 功能框图分析
+  - 寄存器版:轮询方式收发 + 中断方式收发
+  - printf 重定向原理(Keil 微库 + fputc 重写)
+  - HAL 库版:CubeMX 配置 + HAL_UART_Transmit/Receive
+  - 参考手册 §18 USART 寄存器(SR/DR/BRR/CR1~CR3)
+
+- [ ] **步骤 1.7.3:写入文件**
+
+### 任务 1.8:提交批次 1
+
+- [ ] **步骤 1.8.1:更新 wiki/source-stm32-basic.md**
+
+- [ ] **步骤 1.8.2:追加 wiki/log.md**
+
+- [ ] **步骤 1.8.3:git 提交**
+
+```bash
+git add .
+git commit -m "ingest: 尚硅谷STM32 基础篇笔记导入(01~06)"
+```
+
+---
+
+## 批次 2:进阶篇(笔记 07~12)
+
+**来源 DOCX**:`上部-基础篇/01_笔记/02_尚硅谷嵌入式技术之STM32单片机(进阶篇)1.0.1.docx`
+**代码目录**:`上部-基础篇/03_代码/stm32/`(项目 13~42)
+
+### 任务 2.1:转换进阶篇 DOCX
+
+- [ ] **步骤 2.1.1:pandoc 转换**
+
+```powershell
+pandoc "上部-基础篇/01_笔记/02_尚硅谷嵌入式技术之STM32单片机(进阶篇)1.0.1.docx" -t markdown --wrap=none --extract-media="C:\Users\Administrator\AppData\Local\Temp\opencode\stm32_medium_media" -o "C:\Users\Administrator\AppData\Local\Temp\opencode\stm32_medium.md"
+```
+
+### 任务 2.2:笔记 07 — I2C通信与EEPROM 24C02
+
+**代码项目**:`stm32/13_i2c_software_register`、`stm32/14_i2c_hardware_register`、`stm32/15_i2c_hardware_hal`
+
+- [ ] **步骤 2.2.1:读取 DOCX 章节 + 源码**
+- [ ] **步骤 2.2.2:撰写笔记 07**
+  内容要点:
+  - I2C 协议时序逐段分析(起始条件S、从机地址+R/W、应答ACK/非应答NACK、数据字节、停止条件P)
+  - 软件模拟 I2C:GPIO 位操作模拟 SCL/SDA 时序
+  - 硬件 I2C:状态寄存器分析(SR1/SR2 事件标志)
+  - 24C02 EEPROM:页写(最多8字节)、页写限制(跨页自动回卷)、随机读/顺序读
+  - 参考手册 §16 I2C 寄存器(CR1/CR2/OAR1/DR/SR1/SR2/TRISE)
+  - 代码双版复刻
+- [ ] **步骤 2.2.3:写入文件**
+
+### 任务 2.3:笔记 08 — SysTick与通用定时器TIM
+
+**代码项目**:`stm32/16_led_twinkle_systick_register` ~ `stm32/19_led_twinkle_tim_hal`
+
+- [ ] **步骤 2.3.1:读取源码**
+- [ ] **步骤 2.3.2:撰写笔记 08**
+  内容要点:
+  - SysTick 寄存器详解:CTRL(第0位ENABLE/第1位TICKINT/第2位CLKSOURCE)、LOAD、VAL、CALIB
+  - SysTick 定时时间计算:`Time = (LOAD+1) / (AHB/8)`
+  - TIM 时基单元结构框图:PSC 预分频器 → CNT 计数器 → ARR 自动重装载 → 更新事件(UEV)
+  - 溢出时间公式:`Tout = (ARR+1) × (PSC+1) / Tclk`
+  - TIM 与 SysTick 对比(精度/功能/用途)
+  - 代码双版
+- [ ] **步骤 2.3.3:写入文件**
+
+### 任务 2.4:笔记 09 — TIM高级应用:PWM与输入捕获
+
+**代码项目**:`stm32/20_led_breathe_register` ~ `stm32/27_pwm_n_cycle_hal`
+
+- [ ] **步骤 2.4.1:读取源码**
+- [ ] **步骤 2.4.2:撰写笔记 09**
+  内容要点:
+  - PWM 频率 = Tclk / (PSC+1) / (ARR+1);占空比 = CCR / (ARR+1)
+  - 呼吸灯原理:逐渐改变 CCR 值 → 改变占空比 → LED 亮度渐变
+  - 占空比/周期独立控制(ARR 固定改 CCR vs 两者都变)
+  - PWM 模式1 vs 模式2:向上计数时 CNT<CCR 输出有效电平
+  - 输入捕获:测量外部信号频率/脉宽
+  - TIM_CCMR/TIM_CCER/TIM_CNT/TIM_DIER 寄存器详解
+- [ ] **步骤 2.4.3:写入文件**
+
+### 任务 2.5:笔记 10 — DMA数据传输
+
+**代码项目**:`stm32/28_dma_mem2mem_register` ~ `stm32/31_dma_mem2uart_hal`
+
+- [ ] **步骤 2.5.1:读取源码**
+- [ ] **步骤 2.5.2:撰写笔记 10**
+  内容要点:
+  - DMA 框图:5个总线矩阵 + 仲裁器 + DMA1(7通道)/DMA2(5通道)
+  - 传输流程:外设请求→CPU 让出总线→DMA 传输→完成中断
+  - 存储器到存储器(M2M):Flash → SRAM 复制
+  - 存储器到外设(M2P):SRAM → USART DR 寄存器(自动发送)
+  - DMA 通道映射表:
+    | 通道 | 外设请求 |
+    | TIM1_CH1 | ADC1 |
+    | SPI1_RX/TX | USART1_TX |
+    | ... |
+  - 关键寄存器:CCR/CNDTR/CPAR/CMAR
+  - 增量模式 vs 固定模式
+- [ ] **步骤 2.5.3:写入文件**
+
+### 任务 2.6:笔记 11 — ADC模数转换
+
+**代码项目**:`stm32/32_adc_single_register` ~ `stm32/35_adc_double_hal`
+
+- [ ] **步骤 2.6.1:读取源码**
+- [ ] **步骤 2.6.2:撰写笔记 11**
+  内容要点:
+  - SAR ADC 工作原理(逐次逼近:二分法比较)
+  - STM32F103ZET6: 3个ADC(ADC1/2/3),12位精度,18个通道
+  - 采样时间 = 采样周期 × ADC 时钟周期;采样周期可编程(1.5~239.5 个周期)
+  - 转换时间 = 采样时间 + 12.5 个周期(12位精度)
+  - 规则组(最多16通道)vs 注入组(最多4通道)
+  - 单次转换 / 连续转换 / 扫描模式
+  - 定时器触发 ADC + DMA 传输
+  - 参考手册 §11 ADC 寄存器(SR/CR1/CR2/SMPR1~2/SQR1~3/DR)
+- [ ] **步骤 2.6.3:写入文件**
+
+### 任务 2.7:笔记 12 — SPI通信与FSMC总线
+
+**代码项目**:`stm32/36_spi_software_register` ~ `stm32/42_lcd_hal`
+
+- [ ] **步骤 2.7.1:读取源码**
+- [ ] **步骤 2.7.2:撰写笔记 12**
+  内容要点:
+  - SPI 四种模式(CPOL/CPHA 组合)时序图
+  - 3线/4线 SPI(NSS 片选管理)
+  - 软件模拟 SPI(GPIO 位操作)vs 硬件 SPI(寄存器配置)
+  - W25Q64 Flash:读(03h)/写(02h)/擦除(D8h/D7h)/状态寄存器(05h) 指令集
+  - FSMC 地址映射:Bank1(0x60000000~0x6FFFFFFF) → NOR/PSRAM/SRAM/LCD
+  - FSMC 时序参数配置(地址建立时间/数据保持时间)
+  - 参考手册 §23 SPI + §19 FSMC
+- [ ] **步骤 2.7.3:写入文件**
+
+### 任务 2.8:提交批次 2
+
+- [ ] **步骤 2.8.1:更新 wiki/source-stm32-medium.md**
+- [ ] **步骤 2.8.2:追加 wiki/log.md**
+- [ ] **步骤 2.8.3:git 提交**
+
+```bash
+git add .
+git commit -m "ingest: 尚硅谷STM32 进阶篇笔记导入(07~12)"
+```
+
+---
+
+## 批次 3:高级篇(笔记 13~17)
+
+**来源 DOCX**:`下部-高级篇/2-笔记/1.笔记/03_尚硅谷嵌入式技术之STM32单片机(高级篇)2.0.1.docx`
+**代码目录**:`下部-高级篇/3-代码/stm32/`(项目 01~25)
+
+### 任务 3.1:转换高级篇 DOCX
+
+```powershell
+pandoc "下部-高级篇/2-笔记/1.笔记/03_尚硅谷嵌入式技术之STM32单片机(高级篇)2.0.1.docx" -t markdown --wrap=none --extract-media="C:\Users\Administrator\AppData\Local\Temp\opencode\stm32_advanced_media" -o "C:\Users\Administrator\AppData\Local\Temp\opencode\stm32_advanced.md"
+```
+
+### 任务 3.2:笔记 13 — CAN通信协议与bxCAN外设
+
+**代码项目**:`stm32/01_can_test_register` ~ `stm32/04_can_rx_hal`
+
+- [ ] **步骤 3.2.1:读取 DOCX + 源码**
+- [ ] **步骤 3.2.2:网络补充**
+  CAN 2.0A vs 2.0B 标准补充、CAN FD 后续发展
+- [ ] **步骤 3.2.3:撰写笔记 13**
+  内容要点:
+  - CAN 协议基础:车用总线、多主从仲裁、广播式通信
+  - CAN 数据帧逐位分析:帧起始(SOF) 1位 → 仲裁段(11/29位ID+RTR) → 控制段(IDE+res+r0+DLC) → 数据段(0~8字节) → CRC段(15位CRC+界定符) → ACK段(2位) → 帧结束(EOF 7位)
+  - 位时序 & 同步(同步段/传播段/相位缓冲段1/2)
+  - bxCAN 外设:3个发送邮箱 + 2个3级深度FIFO + 14个过滤器组
+  - 三种工作模式:初始化/正常/睡眠
+  - 三种测试模式:静默/环回/环回静默
+  - 过滤器配置:列表模式(精确匹配)vs 掩码模式(模糊匹配)
+  - 寄存器版:双机通信(一收一发)
+  - HAL 版:CubeMX 配置 + HAL_CAN_Start/HAL_CAN_AddTxMessage
+  - 参考手册 §22 bxCAN 寄存器
+- [ ] **步骤 3.2.4:写入文件**
+
+### 任务 3.3:笔记 14 — 以太网通信与W5500
+
+**代码项目**:`stm32/05_ethernet_test_register` ~ `stm32/09_ethernet_webserver_register`
+
+- [ ] **步骤 3.3.1:读取源码**
+- [ ] **步骤 3.3.2:撰写笔记 14**
+  内容要点:
+  - OSI 7层模型 vs TCP-IP 4层模型
+  - 以太网 vs 互联网概念区分
+  - W5500 芯片:全硬件 TCP/IP 协议栈,SPI 接口,8个独立 Socket
+  - W5500 内部架构:SPI口 → 寄存器管理 → 内核 → MAC/PHY → 以太网口
+  - 可变长数据帧模式(VDM) vs 固定长数据帧模式(FDM)
+  - 官方库移植步骤:wizchip_conf.h → SPI 读写注册函数 → socket API
+  - 实验:Ping 通测试 → TCP Server → TCP Client → UDP → WebServer
+  - 参考:W5500 数据手册
+- [ ] **步骤 3.3.3:写入文件**
+
+### 任务 3.4:笔记 15 — WiFi通信与ESP32-C3
+
+**代码项目**:`stm32/10_wifi_test_hal`、`stm32/11_wifi_tcp_server_hal`
+
+- [ ] **步骤 3.4.1:读取源码**
+- [ ] **步骤 3.4.2:撰写笔记 15**
+  内容要点:
+  - ESP32-C3 规格:RISC-V 32位、2.4GHz WiFi + BLE 5.0
+  - AT 指令模式:通过串口发送 AT 指令控制
+  - 常用 AT 指令表:AT+CWMODE(Station/AP/Station+AP)、AT+CWJAP(连接WiFi)、AT+CIPSTART(建立TCP)、AT+CIPMODE(透传)、AT+CIPSEND(发送数据)
+  - 实验1:AT 指令交互测试
+  - 实验2:TCP 通信(AT+CIPSTART 建立连接 → 数据收发)
+  - 透传模式 vs 非透传模式
+- [ ] **步骤 3.4.3:写入文件**
+
+### 任务 3.5:笔记 16 — BLE低功耗蓝牙
+
+**代码项目**:`stm32/12_ble_server_hal`
+
+- [ ] **步骤 3.5.1:读取源码**
+- [ ] **步骤 3.5.2:撰写笔记 16**
+  内容要点:
+  - BLE vs 经典蓝牙(功耗/吞吐量/应用场景)
+  - BLE 协议栈架构:Physical → Link Layer → HCI → L2CAP → SMP → ATT → GATT → GAP
+  - GAP 角色:Broadcaster/Observer/Peripheral/Central
+  - GATT 角色:Server/Client,Service → Characteristic → Descriptor 层级
+  - BLE 通信流程:广播 → 扫描 → 连接 → 数据收发 → 断开
+  - STM32 + BLE 模块(AT 指令控制)
+- [ ] **步骤 3.5.3:写入文件**
+
+### 任务 3.6:笔记 17 — LoRa远距离通信
+
+**代码项目**:`stm32/13_lora_node_hal`、`stm32/14_lora_gateway_hal`
+
+- [ ] **步骤 3.6.1:读取源码**
+- [ ] **步骤 3.6.2:撰写笔记 17**
+  内容要点:
+  - LPWAN 技术阵营对比(LoRa vs NB-IoT vs Sigfox)
+  - LoRa 扩频技术:SF(扩频因子)、BW(带宽)、CR(编码率) 三参数决定速率/灵敏度
+  - CAD(信道活动检测):低功耗监听模式
+  - 星型组网拓扑:节点 ↔ 网关 ↔ 服务器
+  - AT 指令配置:频率/功率/扩频因子/数据速率
+  - 节点 → 网关 数据发送 + 接收确认
+- [ ] **步骤 3.6.3:写入文件**
+
+### 任务 3.7:提交批次 3
+
+- [ ] **步骤 3.7.1:更新 wiki/source-stm32-advanced.md**
+- [ ] **步骤 3.7.2:追加 wiki/log.md**
+- [ ] **步骤 3.7.3:git 提交**
+
+```bash
+git add .
+git commit -m "ingest: 尚硅谷STM32 高级篇笔记导入(13~17)"
+```
+
+---
+
+## 批次 4:扩展篇(笔记 18~21)
+
+**来源 DOCX**:`下部-高级篇/2-笔记/1.笔记/04_尚硅谷嵌入式技术之STM32单片机(扩展篇)1.0.0.docx`
+**代码目录**:`下部-高级篇/3-代码/stm32/`(项目 15~28)
+
+### 任务 4.1:转换扩展篇 DOCX
+
+```powershell
+pandoc "下部-高级篇/2-笔记/1.笔记/04_尚硅谷嵌入式技术之STM32单片机(扩展篇)1.0.0.docx" -t markdown --wrap=none --extract-media="C:\Users\Administrator\AppData\Local\Temp\opencode\stm32_extension_media" -o "C:\Users\Administrator\AppData\Local\Temp\opencode\stm32_extension.md"
+```
+
+### 任务 4.2:笔记 18 — 电源管理与低功耗模式
+
+**代码项目**:`stm32/15_lowpower_sleep_register` ~ `stm32/20_lowpower_standby_hal`
+
+- [ ] **步骤 4.2.1:读取 DOCX + 源码**
+- [ ] **步骤 4.2.2:撰写笔记 18**
+  内容要点:
+  - 电源框图逐区域分析:Vdda(模拟) → Vdd(数字) → 1.8V(内核) → Vbat(备份)
+  - 电压调节器三种模式:运转/停止(低功耗)/待机(关闭)
+  - 上电复位(POR) vs 掉电复位(PDR):阈值电压及迟滞
+  - PVD 可编程电压检测器:PLS[2:0] 选择阈值 → 电压低于阈值产生中断
+  - 三种低功耗模式对比:
+    | 模式 | 唤醒源 | 功耗 | 恢复时间 |
+    | 睡眠 | 任意中断/事件 | ~mA | 几μs |
+    | 停止 | 任意EXTI | ~μA | 几μs |
+    | 待机 | RTC/WKUP/NRST | ~nA | 几ms |
+  - 睡眠模式:SLEEP-NOW vs SLEEP-ON-EXIT
+  - 停止模式:调压器配置(正常工作 vs 低功耗)
+  - 待机模式:SRAM/寄存器全部丢失,仅备份域保留
+  - 低功耗设计建议(时钟门控/外设禁用)
+  - 参考手册 §5 PWR 寄存器
+- [ ] **步骤 4.2.3:写入文件**
+
+### 任务 4.3:笔记 19 — BKP备份寄存器与RTC实时时钟
+
+**代码项目**:`stm32/21_bkp_test_register` ~ `stm32/26_rtc_calendar_hal`
+
+- [ ] **步骤 4.3.1:读取源码**
+- [ ] **步骤 4.3.2:撰写笔记 19**
+  内容要点:
+  - 备份域电路:Vbat 引脚供电 → RTC + LSE + BKP 寄存器 在 Vdd 断电后继续工作
+  - BKP:42 个 16 位备份寄存器 + 防侵入功能(TAMPER)
+  - BKP 访问使能:PWR_CR.DBP = 1 后允许读写
+  - RTC 三时钟源选择:LSE(32.768KHz) / LSI(~40KHz) / HSE(8MHz 分频)
+  - RTC 预分频器:异步分频(7位) + 同步分频(15位) → 精确的 1Hz
+  - RTC 闹钟:RTC_ALR 与 RTC_CNT 比较匹配 → 中断
+  - Unix 时间戳:1970-01-01 起秒数
+  - 日历实验:初始化 → 读取 → 显示 年月日时分秒
+  - 参考手册 §6 BKP + §17 RTC
+- [ ] **步骤 4.3.3:写入文件**
+
+### 任务 4.4:笔记 20 — 看门狗IWDG与WWDG
+
+**代码项目**:`stm32/27_iwdg_test_register`、`stm32/28_iwdg_test_hal`
+
+- [ ] **步骤 4.4.1:读取源码**
+- [ ] **步骤 4.4.2:撰写笔记 20**
+  内容要点:
+  - IWDG 独立看门狗:LSI(~40KHz) 时钟源,完全独立
+  - IWDG 超时时间计算:`Tout = (RL+1) × 4 × 2^PR / 40KHz`
+  - IWDG 预分频系数-超时速查表:
+    | PR[2:0] | 分频系数 | 最大超时(RL=0xFFF) |
+    | 000 | 4 | ~0.82s |
+    | 011 | 32 | ~6.55s |
+    | 111 | 256 | ~52.43s |
+  - WWDG 窗口看门狗:APB1 时钟,有窗口限制(必须在窗口内喂狗)
+  - WWDG 窗口机制:CNT>T[6:0] 时喂狗 → 复位;CNT 减到 0x3F → 复位
+  - WWDG 早期唤醒中断(EWI):在 CNT=0x40 时产生中断,可提前处理
+  - 两者对比(独立 vs 窗口)和应用场景选择
+  - 参考手册 §14 IWDG + §15 WWDG
+- [ ] **步骤 4.4.3:写入文件**
+
+### 任务 4.5:笔记 21 — 附录:HAL库架构与Keil MDK深入
+
+**来源章节**:扩展篇 DOCX 附录
+
+- [ ] **步骤 4.5.1:读取 DOCX 附录章节**
+- [ ] **步骤 4.5.2:撰写笔记 21**
+  内容要点:
+  - HAL 库驱动框架:三层模式(轮询 Polling / 中断 IT / DMA)
+  - HAL 库关键宏:UNUSED()、IS_XXX() 参数校验
+  - HAL 库初始化流程:HAL_Init() → SystemClock_Config() → MX_GPIO_Init() → MX_USART1_UART_Init()
+  - HAL_StatusTypeDef 返回状态
+  - Keil MDK 编译四阶段:
+    1. 编译(armcc/armasm):源文件 → .o 目标文件
+    2. 链接(armlink):多个 .o + 库 → .axf(.elf)
+    3. 格式转换(fromelf):.elf → .bin/.hex
+    4. 下载:烧录到 Flash/ROM
+  - 程序在存储器中的分布:
+    | 段 | 含义 | 存储位置 |
+    | Code | 程序代码 | Flash |
+    | RO-data | 只读数据(const) | Flash |
+    | RW-data | 已初始化全局变量 | Flash 初值 + RAM 运行 |
+    | ZI-data | 零初始化全局变量 | RAM |
+  - 编译输出信息解读(Code/RO/RW/ZI 大小含义)
+- [ ] **步骤 4.5.3:写入文件**
+
+### 任务 4.6:提交批次 4
+
+- [ ] **步骤 4.6.1:更新 wiki/source-stm32-extension.md**
+- [ ] **步骤 4.6.2:追加 wiki/log.md**
+- [ ] **步骤 4.6.3:git 提交**
+
+```bash
+git add .
+git commit -m "ingest: 尚硅谷STM32 扩展篇笔记导入(18~21)"
+```
+
+---
+
+## 最终阶段:完成全部提交
+
+- [ ] **步骤 5.1:更新 wiki/index.md**
+  添加 STM32 章节到索引页,包含全部 21 篇笔记的链接:
+```markdown
+
+## STM32 嵌入式开发(尚硅谷)
+
+> 来源:[[source-stm32-basic|尚硅谷 STM32 基础篇]] · [[source-stm32-medium|进阶篇]] · [[source-stm32-advanced|高级篇]] · [[source-stm32-extension|扩展篇]]
+
+原始笔记(含 4 种代码 + 通俗解释):
+`raw/Joplin/嵌入式+Linux/STM32学习笔记/`
+
+Wiki 页面:
+- [[stm32-gpio|GPIO 与寄存器操作]]
+- [[stm32-timer|定时器与 PWM]]
+- [[stm32-communication|通信外设串口/I2C/SPI/FSMC]]
+- [[stm32-advanced-comm|物联网通信 CAN/ETH/WiFi/BLE/LoRa]]
+- [[stm32-power|低功耗与电源管理]]
+```
+
+- [ ] **步骤 5.2:更新 wiki/log.md 追加最终日志**
+```markdown
+## 2026-07-15
+
+- `ingest`: 导入尚硅谷 STM32 全套 4 份教程笔记
+
+   原始资料归档:
+   - `raw/Joplin/嵌入式+Linux/STM32学习笔记/01~21` 共 21 篇笔记
+   - `raw/Joplin/嵌入式+Linux/STM32学习笔记/assets/` 精选图片
+
+   新建 Wiki 页面:
+   - `wiki/source-stm32-basic.md`
+   - `wiki/source-stm32-medium.md`
+   - `wiki/source-stm32-advanced.md`
+   - `wiki/source-stm32-extension.md`
+   - `wiki/stm32-gpio.md`
+   - `wiki/stm32-timer.md`
+   - `wiki/stm32-communication.md`
+   - `wiki/stm32-advanced-comm.md`
+   - `wiki/stm32-power.md`
+
+   更新 `wiki/index.md`、`wiki/log.md`
+```
+
+- [ ] **步骤 5.3:最终全部提交**
+
+```bash
+git add .
+git commit -m "ingest: 尚硅谷STM32全套笔记导入完成(含基础篇/进阶篇/高级篇/扩展篇 共21篇笔记 + wiki更新)"
+```
+
+---
+
+## 执行顺序说明
+
+整个项目按 **4 批次 + 1 次最终提交** 执行,每批次内部按笔记编号顺序串行处理。
+
+每篇笔记的撰写是核心耗时点,遵循模板规格(FreeRTOS 风格的 frontmatter + 原 DOCX 章节结构 + 源码直接复制 + 注释扩展)。
+
+即使某些笔记纯知识型(如 01/05/21 无对应代码),仍需要:
+- 参考手册页码引用
+- 原理图分析
+- 网络知识补充
+- 图片处理

+ 165 - 0
docs/superpowers/specs/2026-07-15-stm32-silicon-valley-ingest-design.md

@@ -0,0 +1,165 @@
+# 设计文档:尚硅谷 STM32 全套 4 份笔记导入计划
+
+**日期**:2026-07-15
+**来源**:尚硅谷嵌入式技术之STM32单片机(基础篇 V1.0.2 + 进阶篇 V1.0.1 + 高级篇 V2.0.1 + 扩展篇 V1.0.0)
+**目标目录**:`raw/Joplin/嵌入式+Linux/STM32学习笔记/`
+**目标芯片**:STM32F103ZET6
+**参考文件组织格式**:FreeRTOS 学习笔记(`raw/Joplin/嵌入式+Linux/FreeRTOS学习笔记/`)
+
+## 1. 笔记分篇(共 21 篇)
+
+### 基础篇 — 6 篇
+
+| #  | 篇名                       | 对应源章节             | 核心扩展                                                                                 |
+| -- | -------------------------- | ---------------------- | ---------------------------------------------------------------------------------------- |
+| 01 | STM32概述与开发环境搭建    | 概述 + Keil + 最小系统 | 命名规范、数据手册§1~3引用、原理图最小系统逐元件分析、Keil项目文件结构、芯片支持包选型  |
+| 02 | GPIO寄存器详解与三步进化法 | GPIO 8模式+7寄存器     | GPIO内部框图、参考手册§8寄存器位域表、原理图LED/KEY电路、三步进化(裸地址→结构体→位宏) |
+| 03 | GPIO输出:LED控制          | 点亮LED+流水灯         | 模块化驱动封装、流水灯三种实现、Delay模块、源码复制+每行注释                             |
+| 04 | GPIO输入与NVIC中断系统     | 按键+中断              | 按键消抖、EXTI中断配置、NVIC优先级分组、中断向量表                                       |
+| 05 | 系统时钟RCC详解            | RCC时钟树              | 时钟树逐级分析、SystemInit()源码解析、HAL版配置对照、参考手册§7 RCC寄存器               |
+| 06 | 串口USART通信              | USART轮询/中断/printf  | 串行协议帧格式、USART框图、波特率计算、printf重定向、代码双版                            |
+
+### 进阶篇 — 6 篇
+
+| #  | 篇名                       | 对应源章节           | 核心扩展                                                         |
+| -- | -------------------------- | -------------------- | ---------------------------------------------------------------- |
+| 07 | I2C通信与EEPROM 24C02      | I2C软件+硬件+24C02   | I2C协议时序分析、软件模拟、硬件I2C状态寄存器、24C02页写限制      |
+| 08 | SysTick与通用定时器TIM     | SysTick+TIM时基      | SysTick 4寄存器详解、TIM时基单元、溢出时间计算公式、参考手册§14 |
+| 09 | TIM高级应用:PWM与输入捕获 | TIM PWM+捕获         | PWM频率/占空比计算、呼吸灯、输入捕获测频、PWM模式1/2区别         |
+| 10 | DMA数据传输                | DMA内存到内存/到串口 | DMA框图、传输流程、通道映射表、存储器与外设增量模式              |
+| 11 | ADC模数转换                | ADC单次/连续/多通道  | SAR ADC原理、采样/转换时间计算、规则组vs注入组                   |
+| 12 | SPI通信与FSMC总线          | SPI+FSMC             | SPI四模式时序图、W25Q64 Flash驱动、FSMC地址映射与Bank选择        |
+
+### 高级篇 — 5 篇
+
+| #  | 篇名                   | 对应源章节       | 核心扩展                                                     |
+| -- | ---------------------- | ---------------- | ------------------------------------------------------------ |
+| 13 | CAN通信协议与bxCAN外设 | CAN协议+双机通信 | 数据帧逐位分析、位时序与同步、bxCAN滤波器、3种工作/测试模式  |
+| 14 | 以太网通信与W5500      | ETH+W5500        | OSI/TCP-IP分层、W5500架构、官方库移植、TCP Server/Client/UDP |
+| 15 | WiFi通信与ESP32-C3     | WiFi AT指令+TCP  | ESP32-C3规格、AT指令集、Station/AP模式、透传模式             |
+| 16 | BLE低功耗蓝牙          | BLE协议+通信     | BLE vs 经典蓝牙、协议栈分层、角色模型、连接流程              |
+| 17 | LoRa远距离通信         | LoRa节点+网关    | LoRa扩频技术、CAD检测、星型组网、AT指令配置                  |
+
+### 扩展篇 — 4 篇
+
+| #  | 篇名                          | 对应源章节       | 核心扩展                                          |
+| -- | ----------------------------- | ---------------- | ------------------------------------------------- |
+| 18 | 电源管理与低功耗模式          | PWR低功耗        | 电源框图分析、三种模式对比表、PVD电压检测         |
+| 19 | BKP备份寄存器与RTC实时时钟    | BKP+RTC日历/闹钟 | 备份域电路、RTC三时钟源、预分频器配置、Unix时间戳 |
+| 20 | 看门狗IWDG与WWDG              | IWDG+WWDG        | IWDG超时速查表、WWDG窗口机制、喂狗时机计算        |
+| 21 | 附录:HAL库架构与Keil MDK深入 | HAL库+Keil附录   | HAL驱动三层抽象、Keil编译四阶段、程序存储分布     |
+
+## 2. 处理批次
+
+| 批次  | DOCX   | 产出笔记 | 代码来源                    | 代码项目数 |
+| ----- | ------ | -------- | --------------------------- | ---------- |
+| 批次1 | 基础篇 | 01~06    | `上部\stm32/01~12`        | 12         |
+| 批次2 | 进阶篇 | 07~12    | `上部\stm32/13~42`        | 30         |
+| 批次3 | 高级篇 | 13~17    | `下部\stm32/01~25`        | 25         |
+| 批次4 | 扩展篇 | 18~21    | `下部\stm32/15~28` + 资料 | 14         |
+
+## 3. 每篇笔记模板
+
+结构镜像原 DOCX 章节组织方式(外设介绍 → 硬件设计 → 代码实验),代码直接从源文件复制并标注文件名,方便只看 MD 即可复现。
+
+```markdown
+---
+tags: [source-summary]
+type: source
+source: "尚硅谷嵌入式技术之STM32单片机 — {来源章节} + 配套代码{编号}"
+author: "尚硅谷研究院"
+date: YYYY-MM-DD
+created: YYYY-MM-DD
+---
+
+# {外设名称}
+
+> **用生活理解**:{一句话类比}
+
+## {外设}介绍
+
+### 基本概念
+{是什么、有什么用、应用场景}
+
+### 工作原理(框图 + 文字说明)
+> 参考:STM32F103ZET6 参考手册 §X.X
+> 参考:开发板原理图第X页 {引脚}
+
+### {外设}的寄存器详解
+
+| 寄存器 | 地址偏移 | 位域 | 说明 |
+|--------|---------|------|------|
+| CR1    | 0x00    | ...  | ...  |
+
+## {外设}硬件电路设计
+
+![电路原理图](assets/xxx.png)
+{引脚连接说明}
+
+## {实验/案例标题}
+
+### 需求描述
+
+### 硬件电路设计(如与通用硬件不同则补充)
+
+### 软件设计(寄存器版)
+
+**文件:{项目路径}/User/main.c**
+
+```c
+// 注释说明这段代码的功能
+// 重要位操作行有详细注释
+```
+
+**文件:{项目路径}/Hardware/{外设}/{driver}.h**
+
+```c
+// 头文件内容
+```
+
+**文件:{项目路径}/Hardware/{外设}/{driver}.c**
+
+```c
+// 驱动源码 + 逐行注释
+```
+
+### 软件设计(HAL库版)
+
+**文件:{项目路径}/User/main.c**
+
+```c
+// HAL版代码,直接从源码项目复制
+```
+
+**文件:{项目路径}/Hardware/{外设}/{driver}.c**
+
+```c
+```
+
+## 核心函数速查表
+
+| 函数 | 参数 | 功能简述 |
+| ---- | ---- | -------- |
+| xxx  | ...  | ...      |
+
+## 常见问题与避坑
+
+```
+
+## 4. 图片策略
+
+- 保留所有原 DOCX 图片
+- pandoc `--extract-media` 提取到临时目录
+- 视觉 API 逐张验证内容(寄存器位域图/框图/时序图/原理图)
+- 重命名为有意义名称(`{外设}_{内容}.png`)
+- 复制到对应笔记的 `assets/` 子目录
+- 引用使用相对路径
+
+## 5. Wiki 更新
+
+每批次完成后:
+1. 更新 `wiki/source-stm32-{关键词}.md`
+2. 更新 `wiki/index.md` 添加 STM32 章节
+3. 追加 `wiki/log.md`
+4. 提交 `ingest: 尚硅谷STM32 {批次名称}`
+```