STM32固件库拆解学习
授人以鱼不如授人以渔。读懂固件库的“骨架”,比背会几个函数重要一万倍。

一、用一张思维导图看懂STM32固件库
在深入每一个模块之前,建议你先用这张思维导图建立全局认知。STM32固件库的完整结构可以归纳为以下五个层次:
text
STM32固件库(标准外设库 v3.5.0)
│
├── 第1层:启动文件(startup_xxx.s)
│ ├── 设置堆栈指针(SP = __initial_sp)
│ ├── 设置程序计数器(PC = Reset_Handler)
│ ├── 初始化中断向量表
│ ├── 调用 SystemInit() → 配置72MHz时钟
│ └── 调用 __main() → 初始化C运行时环境 → 跳转 main()
│
├── 第2层:时钟配置(system_stm32f10x.c)
│ ├── HSE(外部8MHz晶振)
│ ├── PLL(锁相环,×9倍频)
│ ├── SYSCLK(系统时钟 72MHz)
│ ├── AHB总线(HCLK = 72MHz)
│ ├── APB1总线(PCLK1 = 36MHz,低速外设)
│ └── APB2总线(PCLK2 = 72MHz,高速外设)
│
├── 第3层:寄存器映射(stm32f10x.h + core_cm3.h)
│ ├── stm32f10x.h → 片内外设(GPIO、USART、I2C、SPI、TIM…)
│ └── core_cm3.h → 内核外设(NVIC、SysTick、MPU…)
│
├── 第4层:外设驱动库(stm32f10x_xxx.c/.h)
│ ├── 每个外设一对 .c/.h 文件
│ ├── 核心模式:“填结构体 → 调函数”
│ └── 示例:GPIO_InitTypeDef → GPIO_Init()
│
└── 第5层:配置与中断管理(conf.h + it.c)
├── stm32f10x_conf.h → 头文件“总开关”
└── stm32f10x_it.c → 中断服务函数集中存放
二、第一块基石:启动文件(Startup File)
2.1 启动文件在固件库中的位置
在固件库目录中,启动文件位于 Libraries/CMSIS/CM3/DeviceSupport/ST/STM32F10x/startup/ 下。它是芯片复位后执行的第一段代码,用汇编语言编写。
2.2 文件名里的“暗号”:hd、md、ld 是什么意思?
| ld | Low Density | 16KB ~ 32KB | STM32F101C6 |
| md | Medium Density | 64KB ~ 128KB | STM32F103C8 |
| hd | High Density | 256KB ~ 512KB | STM32F103VE、STM32F103ZE |
| xl | XL Density | >512KB | STM32F101ZG |
选错了会怎样? 比如在256KB容量的芯片上用了md的启动文件,中断向量表可能缺少部分外设中断入口(如FSMC或DAC),导致中断无法响应,且编译时通常不会报错,运行时才会莫名其妙死机。
2.3 启动文件的执行流程(示意图)
text
┌─────────────────────────────────────────────────────────────────┐
│ STM32 启动流程全图 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ① 芯片上电复位 │
│ ↓ │
│ ② 硬件自动操作: │
│ ┌─────────────────────────────────────────┐ │
│ │ 从 0x08000000 读取 → 加载到 SP 寄存器 │ │
│ │ 从 0x08000004 读取 → 加载到 PC 寄存器 │ │
│ └─────────────────────────────────────────┘ │
│ ↓ │
│ ③ PC = Reset_Handler 入口地址 │
│ ↓ │
│ ④ Reset_Handler: │
│ ┌─────────────────────────────────────────┐ │
│ │ BL SystemInit ← 配置时钟为72MHz │ │
│ │ BL __main ← 初始化C运行时环境 │ │
│ └─────────────────────────────────────────┘ │
│ ↓ │
│ ⑤ __main 内部: │
│ ┌─────────────────────────────────────────┐ │
│ │ ① 复制 .data 段(Flash → RAM) │


