这一章在干嘛?

复习 STM32 嵌入式开发必备的 C 语言(位操作、宏定义、结构体、指针)+ 寄存器本质 + STM32F407 系统架构 + 存储器与寄存器映射。读完后面对 HAL 库「为什么这样封装」会有恍然大悟的感觉。

5.1 C 语言基础知识复习

5.2 寄存器基础知识

5.3 STM32F407 系统架构

5.1 C 语言基础知识复习

5.1.1 位操作

嵌入式天天和 bit 打交道:清零 &= ~BIT、置位 |= BIT、取反 ^= BIT、读取 (x & BIT) ? 1 : 0

5.1.2 define 宏定义

#define PI 3.14 文本替换;带参数 #define MAX(a,b) ((a)>(b)?(a):(b)) 注意整体加括号避免运算符优先级坑。

5.1.3 ifdef 条件编译

头文件防重包含 #ifndef __STM32_H\n#define __STM32_H ... #endif;区分调试与发布 #ifdef DEBUG ... #endif

5.1.4 extern 外部声明

extern uint8_t g_flag; 告诉编译器「这变量在别的文件里定义」,不要分配空间。多文件工程必备。

5.1.5 typedef 类型别名

typedef unsigned int uint32_t; 让代码可移植、易读。C99/C11 的 <stdint.h> 已经替我们做好:uint8_t/uint16_t/uint32_t/uint64_t/int8_t/.../int64_t

5.1.6 结构体

把相关变量打包:struct GPIO_TypeDef { uint32_t MODER; uint32_t OTYPER; ... };。访问用 .(普通变量)或 ->(指针变量)。

5.1.7 指针

STM32 大量用「外设寄存器结构体指针」:#define GPIOA ((GPIO_TypeDef *)0x40020000),然后 GPIOA->BSRR = 0x01; 就是点亮 PA0。指针就是地址,地址就是数字,没什么神秘的。

C 语言建议: 把这 7 节内容当字典,不懂就翻,3 天后自然就熟了。

5.2 寄存器基础知识

寄存器 = 特殊功能的内存单元。本质:

(*(unsigned int *)(0x40010C0C)) = 0xFFFF;     // 把 GPIOB->ODR 设为 0xFFFF

但可读性差,所以改用结构体:

GPIOB->ODR = 0xFFFF;                          // 实质等价上一行

寄存器按 32 位组织,每位或几位代表一个开关/参数。命名约定:xxxx_CR1/CR2/CR3 配置寄存器、xxxx_SR 状态寄存器、xxxx_DR 数据寄存器、xxxx_BRR 波特率寄存器。

5.3 STM32F407 系统架构

5.3.1 Cortex M4 内核 & 芯片

Cortex-M4 由 ARM 设计,包含 NVIC(嵌套向量中断控制器)、SysTick、MPU、FPU、DSP 指令等。ST 在此基础上集成自家外设(USART/SPI/…)。

5.3.2 STM32 系统架构

F407 有 8 条主控总线:I-Code、D-Code、S-Bus、DMA、FSMC、AHB、APB1、APB2。

  • I-Code:取指令,CPU → Flash
  • D-Code:读常量,CPU → Flash
  • S-Bus:CPU 访问外设寄存器
  • DMA 总线:DMA 搬运数据不经过 CPU

原书图 5.3.2.1:STM32 系统架构框图原书图 5.3.2.1:STM32 系统架构框图

5.3.3 存储器映射

整个 4 GB 地址空间划分:

地址范围用途
0x0000_0000~0x1FFF_FFFFCode 区(Flash 映射)
0x2000_0000~0x3FFF_FFFFSRAM(192 KB)
0x4000_0000~0x5FFF_FFFF外设寄存器
0x6000_0000~0x7FFF_FFFFFSMC 扩展(外部 SRAM/NOR)
0x8000_0000~0x9FFF_FFFFFSMC 扩展(NAND)
0xA000_0000~0xDFFF_FFFFFSMC 扩展(其它)
0xE000_0000~0xFFFF_FFFFCortex-M4 内核(NVIC/SysTick)

原书图 5.3.3.1:STM32 存储器映射图原书图 5.3.3.1:STM32 存储器映射图

记住常用段: RAM 起始 0x20000000;外设起始 0x40000000;Flash 起始 0x08000000(启动后映射到 0x00000000)。

5.3.4 寄存器映射

寄存器描述解读:手册里每个寄存器都有「位定义表」,例如 USART_BRR 寄存器:

名称读写功能
[3:0]DIV_FractionRW小数部分
[15:4]DIV_MantissaRW整数部分

寄存器映射举例:把 USART1 的 BRR 地址算出:

外设基地址USART 基地址偏移总地址
0x400000000x400110000x080x40011008

寄存器地址计算:外设基址 + 偏移;外设基址 = 总线基址 + 总线相对偏移;总线基址 = 总线基址基址 + N×总线间距。

原书图 5.3.4.1:寄存器描述解读示例原书图 5.3.4.1:寄存器描述解读示例

stm32f407xx.h 寄存器映射说明:ST 已经把整个 F407 的寄存器映射成结构体,我们直接 USART1->BRR = 0x0683; 即可,不用自己算地址。