2.1 MCU、地址空间与外设
1. 简介
微控制器(Microcontroller Unit, MCU)是将中央处理器核心、易失性与非易失性存储器,以及丰富的外设控制硬件集成在单一芯片上的计算系统。在现代嵌入式系统领域,意法半导体(STMicroelectronics)推出的 STM32 系列微控制器基于 Arm Cortex-M 架构,凭借丰富的产品梯度与外设生态,被广泛应用于工业自动化、电机驱动、智能仪表、车载电子以及物联网终端设备中。
与通用计算机依赖南桥、北桥或复杂的 PCIe 总线挂载外部扩展设备不同,MCU 内部通过 AHB(Advanced High-performance Bus)与 APB(Advanced Peripheral Bus)等多级片上总线网络,将所有功能部件连接在一起。处理器的 4GB(32 位)地址空间被划分为若干固定功能的逻辑区间,Flash 闪存、片上 SRAM、各类外设控制寄存器乃至 Cortex-M 内核专属的系统控制块,均以内存映射的方式呈现。程序对硬件外设的控制,本质上转化为在统一编址空间内对特定物理地址的读写访问。
STM32 系列在硬件资源与开发支持上具备一系列成熟特性:
- 丰富的外设集成:涵盖模数转换器(ADC)、数模转换器(DAC)、通用与高级定时器(支持脉宽调制 PWM 与正交编码器输入)、串行外设接口(SPI)、集成电路间总线(I2C)、通用异步收发器(UART/USART)、控制器局域网(CAN)以及通用输入输出(GPIO)等。
- 灵活的电源管理:提供运行、睡眠、停机(Stop)与待机(Standby)等多种低功耗工作模式,配合时钟门控技术,能够根据负载动态关闭闲置总线与外设,满足电池供电设备严苛的功耗预算。
- 存储与总线架构:内置高速 Flash 与静态 SRAM,支持零等待周期的指令预取与缓存机制;部分中高端型号还提供灵活的外部存储控制器(FSMC/FMC),用于扩展外部 SRAM、NOR/NAND Flash 或驱动液晶显示屏。
- 完善的开发生态:官方提供图形化引脚与时钟配置工具 STM32CubeMX、基于 Eclipse/Clang 的集成开发环境 STM32CubeIDE,以及底层寄存器封装库与硬件抽象层(HAL/LL 库),同时拥有庞大的开源社区与第三方工具链支持。
2. STM32 选型
进入具体的硬件与底层软件开发之前,芯片选型是系统设计的首要环节。面对庞杂的产品型号,设计者需要综合权衡计算性能、片上存储容量、外设通道配比、封装物理尺寸以及量产成本。
STM32 产品家族按照处理器内核架构与目标应用场景划分了清晰的产品线。不同系列在主频性能、功耗表现以及特定硬件加速单元(如单精度/双精度硬件浮点单元 FPU、DSP 数字信号处理指令集)上各有侧重。
2.1 STM32 分类
| CPU 位数 | 内核 | 系列 | 描述 |
|---|---|---|---|
| 32 | Cortex-M0 | STM32-F0 | 入门级 |
| STM32-L0 | 低功耗 | ||
| Cortex-M3 | STM32-F1 | 基础型,主频 72MHz | |
| STM32-F2 | 高性能 | ||
| STM32-L1 | 低功耗 | ||
| Cortex-M4 | STM32-F3 | 混合信号 | |
| STM32-F4 | 高性能,主频 180MHz | ||
| STM32-L4 | 低功耗 | ||
| Cortex-M7 | STM32-F7 | 高性能 | |
| 8 | STM8 | ||
| STM8s | 标准系列 | ||
| STM8AF | 标准车载 | ||
| STM8AL | 低功耗车载 | ||
| STM8L | 低功耗 |
2.2 STM32 命名方法

注:摘自《STM32 选型手册》
3. 开发导引
3.1 分配原理图 IO
在硬件电路设计的初期阶段,面对数十乃至上百个芯片引脚,预先梳理各引脚的电气角色与功能约束是绘制原理图的前提。芯片的管脚资源并非全部可用作普通输入输出,合理的分类规划有助于避免后期硬件布线时出现功能互斥或电气冲突。
一般而言,引脚在硬件设计中可按功能划分为以下几大类别:
| 引脚分类 | 引脚说明 |
|---|---|
| 电源与参考电压 | 包括数字核心供电(VDD/VSS)、后备电池域(VBAT)、模拟供电与模拟参考地(VDDA/VSSA),以及高精度 ADC 参考源(VREF+/VREF-)等 |
| 晶振时钟 IO | 外部高速晶振输入输出(OSC_IN/OSC_OUT)及低速 RTC 实时时钟晶振(OSC32_IN/OSC32_OUT) |
| 调试与烧录 IO | 串行调试接口 SWD(SWDIO、SWCLK)与联合测试工作组接口 JTAG(JTMS、JTCK、JTDI、JTDO、NJRST) |
| 引导模式 IO | 硬件启动选择引脚 BOOT0、BOOT1,用于在复位释放时采样确定芯片是从 Flash、系统存储器(内置 Bootloader)还是片上 SRAM 启动 |
| 外部复位 IO | 异步双向复位引脚 NRST,低电平有效,芯片内部集成弱上拉电阻与滤波电路 |
| 通用与复用 GPIO | 包含通用数字输入输出,以及分配给片上外设总线(如 I2C、SPI、CAN、USB、USART、FSMC 等)的复用引脚 |
3.2 关于引脚
在查阅具体芯片数据手册(Datasheet)中的 Pinouts and pin descriptions 章节时,可以找到每一款封装对应的物理管脚排布图与功能对照表:

数据手册中的引脚说明表格包含了引脚的电气特性与内部多路复用(Multiplexing)信息,各字段的含义如下:
| 属性名称 | 详细说明 |
|---|---|
| 引脚序号(Pins) | 对应具体物理封装(如 LQFP48、LQFP64、LQFP100 等)下的芯片管脚物理编号,设计 PCB 封装时必须与此精确对应 |
| 引脚名称(Pin name) | 引脚的标准命名,通常反映其上电复位完成后的默认硬件连接身份 |
| 引脚类型(Type) | 标明引脚的电气传输方向。其中 S 代表电源或接地(Power Supply);I 代表只读专用输入;I/O 则代表可配置为输入或输出的双向引脚 |
| I/O 结构(I/O Level) | 标明引脚的耐压与模拟电路特性。FT(Five-Volt Tolerant)表示在 3.3V 供电下引脚输入具备容忍 5V 电平的能力;TTa 则表示模拟专用引脚,直接接入片上 ADC/DAC 模拟开关,不可直接承受高于 VDDA 的电压;带有内部弱上拉的复位引脚或启动引脚亦有特定结构标记 |
| 主功能(Main function) | 芯片完成硬件复位并进入执行状态时引脚默认启用的初始功能 |
| 复用功能(Alternate function) | 引脚内部通过多路选择器挂接的外设硬件信号(例如定时器输入捕获通道、USART 收发线、SPI 时钟线等)。通过配置端口控制寄存器,引脚可以脱离通用 GPIO 模式,交由特定片内外设直接接管 |
| 重映射(Remap) | 为解决多个片内外设争夺同一组物理引脚的问题,STM32 提供了外设重映射机制。在配置 AFIO 重映射寄存器后,特定外设的硬件信号可重新定向至备用引脚,提升了 PCB 布线与外设搭配的灵活性 |
4. 习题
对照本页 2.2 小节的命名方法图,写出下面四个型号的家族、系列、引脚数、Flash 容量、封装与温度范围:
STM32F103C8T6STM32F103CBT6STM32F407VGT6STM32L051K8U6
然后回答:
(1) 前两个型号只差一个字符,Flash 容量差多少?这个差别会影响链接脚本 MEMORY 里的哪一个参数?
(2) STM32F103C8T6 的引脚数是 48,但 Blue Pill 板上引出的排针并不是 48 根。说明「引脚数」与「可用 GPIO 数」为什么不是一回事,至少举出三个不能当普通 GPIO 用的引脚。
(3) 命名图里「特定功能」一栏写的是三位数字,103 与 051 分别对应什么定位?如果一个项目需要硬件浮点运算,这两个系列能不能选?
写一个主机端程序 part_decode.c,从命令行接收若干 STM32 型号,逐行输出解码结果:
$ gcc -std=c17 -Wall -Wextra part_decode.c -o part_decode
$ ./part_decode STM32F103C8T6 STM32F103CBT6 STM32F407VGT6 STM32L051K8U6
STM32F103C8T6: 系列 103, 48 引脚, 64 KB Flash, LQFP, -40~+85
STM32F103CBT6: 系列 103, 48 引脚, 128 KB Flash, LQFP, -40~+85
STM32F407VGT6: 系列 407, 100 引脚, 1024 KB Flash, LQFP, -40~+85
STM32L051K8U6: 系列 051, 32 引脚, 64 KB Flash, UFQFPN, -40~+852
3
4
5
6
要求:
(1) 用一个函数 int decode(const char *part, char *out, size_t n) 完成解析,型号长度不是 13 或前缀不是 STM32 时返回 0,主函数打印 无法解析: 型号 并继续处理下一个参数。
(2) 引脚数、Flash 容量、封装、温度的编码各写成一张静态表或一个 switch,不要在解析函数里堆一长串 if。
(3) 自行补两个型号验证:STM32F103RCT6(64 引脚、256 KB)与 STM32F103C8T7(温度范围不同),贴出运行结果。
按 3.1 小节的分类整理一份引脚清单,写程序检查冲突。清单如下:
static const struct pin_use g_uses[] = {
{"VDD", "VDD", "电源"}, {"VSS", "VSS", "电源"},
{"OSC_IN", "PD0", "晶振"}, {"OSC_OUT", "PD1", "晶振"},
{"SWDIO", "PA13", "下载"}, {"SWCLK", "PA14", "下载"},
{"BOOT0", "BOOT0", "BOOT"}, {"BOOT1", "PB2", "BOOT"},
{"NRST", "NRST", "复位"},
{"LED", "PC13", "GPIO"}, {"KEY", "PA0", "GPIO"},
{"USART1_TX", "PA9", "GPIO"}, {"USART1_RX", "PA10", "GPIO"},
{"USB_DM", "PA11", "GPIO"}, {"USB_DP", "PA12", "GPIO"},
{"CAN_RX", "PA11", "GPIO"}, {"CAN_TX", "PA12", "GPIO"},
};2
3
4
5
6
7
8
9
10
11
写 pin_plan.c,统计每个类别用了几个引脚,再两两比较引脚名,把重复的引脚打印出来。期望输出:
电源 2
晶振 2
下载 2
BOOT 2
复位 1
GPIO 8
合计 17
冲突: PA11 (USB_DM, CAN_RX)
冲突: PA12 (USB_DP, CAN_TX)2
3
4
5
6
7
8
9
(1) 这两个冲突对应硬件上的什么约束?查阅 RM0008 第 23 章,说明 USB 与 CAN 能否同时工作,以及计划里为什么要把 CAN 改到重映射引脚。
(2) 给程序加一条检查:属于「下载」类别的引脚如果同时出现在 GPIO 类别里,输出 警告: 引脚 被复用。把 PA13 再加一条 {"LED2", "PA13", "GPIO"} 验证这条检查。
(3) 冲突检查为什么只能按引脚名比较,不能按类别比较?举一个清单里不冲突但同类的例子。
第 2.1 节的正文还没有展开存储器映射。用 RM0008 第 3 章的存储器映射表与各外设章的基地址,写一个查询工具 memmap.c:从标准输入逐行读一个十六进制地址,输出它落在哪个区域、哪个外设,以及相对外设基地址的偏移。
要求至少覆盖:别名区、Flash、系统存储器、选项字节、SRAM、外设区、Cortex-M3 内核外设区;外设区里至少覆盖 TIM2、TIM3、TIM4、SPI2、USART2、I2C1、PWR、AFIO、GPIOA、GPIOB、GPIOC、ADC1、SPI1、USART1、RCC、FLASH。
用下面九个地址验证,输出必须一致:
$ printf '08000000\n20000000\n4001080C\n40021018\n40013800\n40022000\nE000E010\n1FFFF000\n40021800\n' | ./memmap
0x08000000 Flash
0x20000000 SRAM
0x4001080C 外设 APB2 GPIOA 偏移 0x00C
0x40021018 外设 AHB RCC 偏移 0x018
0x40013800 外设 APB2 USART1 偏移 0x000
0x40022000 外设 AHB FLASH 偏移 0x000
0xE000E010 内核外设 NVIC/SCB/SysTick
0x1FFFF000 系统存储器
0x40021800 外设 未知外设2
3
4
5
6
7
8
9
10
(1) 0x40021800 落在外设区里但不在你列出的任何外设内。查 RM0008 第 3 章的映射表,说明它位于哪两个外设之间、为什么是保留地址,以及往这里写会触发哪一类故障(第 2.10 节会讲)。
(2) 把 GPIOC 的基地址写成 0x40011100(比真正的 0x40011000 多加了 0x100)。分别查询真正的 GPIOC_ODR 地址 0x4001100C 和错误的 0x4001110C,写出工具的输出。说明基地址抄错一个数字时,工具报出的「偏移 0x00C」为什么反而是错的,这类错误编译期为什么发现不了、只能靠什么发现。
(3) 0xE000E010 是 SysTick 的 CTRL 寄存器,它在手册里由 PM0056 而非 RM0008 描述。查 PM0056 给出这个寄存器的三个位名,说明查询工具为什么要把内核外设区单独列一类。