3. 寄存器映射与时钟树

在裸机串口驱动开发中,寄存器映射是软件与硬件交互的桥梁,时钟树是外设工作的能量来源。本章将深入剖析STM32F1系列(以F103为例)的GPIO复用功能配置、USART时钟使能路径以及波特率计算公式,帮助读者建立从寄存器位操作到硬件时序的完整认知。

3.1 寄存器映射基础与GPIO复用功能配置

STM32的寄存器被映射到固定的内存地址空间,C语言通过指针或结构体直接访问这些地址。GPIO的复用功能(Alternate Function, AF)配置是串口通信的第一步,需要将USART的TX/RX引脚连接到对应的GPIO端口。

3.1.1 GPIO复用功能配置步骤

  1. 使能GPIO时钟:通过RCC_APB2ENR寄存器使能对应GPIO端口时钟。
  2. 配置引脚模式:设置GPIOx_CRL(低8位)或GPIOx_CRH(高8位)寄存器,将引脚配置为复用推挽输出(TX)和浮空输入(RX)。
  3. 选择复用功能:对于STM32F1,复用功能由GPIOx_AFIO寄存器或直接由外设映射决定(F1的USART1默认映射到PA9/PA10)。
关键寄存器:GPIOx_CRL/CRH
- MODE位:设置引脚速度(10MHz、50MHz等)
- CNF位:设置引脚模式(输入、输出、复用功能、模拟)
- 对于USART TX:CNF=10(复用推挽输出),MODE=11(50MHz)
- 对于USART RX:CNF=01(浮空输入),MODE=00(输入模式)
// 示例:配置USART1的TX(PA9)和RX(PA10)
RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;  // 使能GPIOA时钟

// 配置PA9为复用推挽输出(50MHz)
GPIOA->CRH &= ~(0xF << 4);          // 清除CNF9和MODE9位
GPIOA->CRH |= (0xB << 4);           // CNF=10, MODE=11

// 配置PA10为浮空输入
GPIOA->CRH &= ~(0xF << 8);          // 清除CNF10和MODE10位
GPIOA->CRH |= (0x4 << 8);           // CNF=01, MODE=00
避坑提示:STM32F1的USART1默认映射到PA9(USART1_TX)和PA10(USART1_RX),无需额外配置AFIO重映射。若使用其他USART(如USART2/3),需检查数据手册确认引脚映射,并可能需配置AFIO寄存器。

3.1.2 GPIO复用功能配置流程图

GPIO复用功能配置流程 使能GPIO时钟 配置引脚模式 选择复用功能 详细说明 1. RCC_APB2ENR:使能GPIOA/B/C等端口时钟 2. GPIOx_CRL/CRH:设置MODE和CNF位 - TX:CNF=10(复用推挽输出),MODE=11(50MHz) - RX:CNF=01(浮空输入),MODE=00(输入模式) 3. 对于F1,USART1默认映射PA9/PA10,无需额外配置

3.2 USART时钟使能:APB1与APB2总线

STM32的时钟树通过RCC(Reset and Clock Control)模块管理。USART外设挂载在不同的APB总线上,需要正确使能对应的时钟位。USART1挂载在APB2总线(最高72MHz),USART2/3挂载在APB1总线(最高36MHz)。

3.2.1 时钟使能寄存器对比

外设 挂载总线 时钟使能寄存器 使能位 最大时钟频率
USART1 APB2 RCC_APB2ENR 位14 (USART1EN) 72 MHz
USART2 APB1 RCC_APB1ENR 位17 (USART2EN) 36 MHz
USART3 APB1 RCC_APB1ENR 位18 (USART3EN) 36 MHz
// 使能USART1时钟(APB2总线)
RCC->APB2ENR |= RCC_APB2ENR_USART1EN;

// 使能USART2时钟(APB1总线)
RCC->APB1ENR |= RCC_APB1ENR_USART2EN;
时钟配置陷阱:APB1总线的最大频率为36MHz,若系统时钟(HCLK)为72MHz,则APB1预分频器必须设置为2分频。USART2/3的波特率计算需使用36MHz作为输入时钟,而非72MHz。务必检查RCC_CFGR寄存器的PPRE1位。

3.2.2 USART时钟树结构图

USART时钟树结构 HCLK (72MHz) APB2 Prescaler (/1 或 /2) APB1 Prescaler (/1 或 /2) USART1 (72MHz) APB2时钟 USART2 (36MHz) APB1时钟 注意:APB1最大频率36MHz,若HCLK=72MHz,则APB1预分频器必须设为/2

3.3 波特率计算公式与USART_BRR寄存器详解

波特率(Baud Rate)决定了串口通信的速率。STM32的USART波特率通过USART_BRR寄存器配置,其值由系统时钟和过采样模式决定。

3.3.1 波特率计算公式

USART的波特率计算公式如下:

波特率公式:
BaudRate = f_CK / (16 * USARTDIV)
其中:
- f_CK:USART输入时钟频率(APB1或APB2时钟)
- USARTDIV:USART_BRR寄存器的值(定点数,整数部分+小数部分)
- 16:过采样率(默认模式,也可配置为8倍过采样)

USARTDIV的计算公式:

USARTDIV = f_CK / (16 * BaudRate)

例如:f_CK = 72MHz, BaudRate = 115200
USARTDIV = 72000000 / (16 * 115200) = 39.0625

3.3.2 USART_BRR寄存器结构

位域 名称 描述
15:4 DIV_Mantissa USARTDIV的整数部分(12位)
3:0 DIV_Fraction USARTDIV的小数部分(4位,精度1/16)

USART_BRR寄存器的值计算:

USARTDIV = 39.0625
DIV_Mantissa = 39 (0x27)
DIV_Fraction = 0.0625 * 16 = 1 (0x1)
USART_BRR = (39 << 4) | 1 = 0x271
小数部分计算技巧:小数部分 = round(小数 * 16)。例如0.0625 * 16 = 1.0,取整为1。若计算结果为0.5,则四舍五入。误差过大会导致通信失败,建议使用整数运算避免浮点。

3.3.3 波特率配置代码示例

// 计算并设置USART1波特率为115200(f_CK=72MHz)
uint32_t f_ck = 72000000;  // USART1时钟频率
uint32_t baud = 115200;    // 目标波特率

// 计算USARTDIV = f_ck / (16 * baud)
uint32_t usartdiv = (f_ck + (8 * baud)) / (16 * baud);  // 四舍五入

// 提取整数和小数部分
uint16_t mantissa = usartdiv / 16;
uint16_t fraction = usartdiv % 16;

// 写入USART_BRR寄存器
USART1->BRR = (mantissa << 4) | fraction;

3.3.4 波特率误差分析表

目标波特率 f_CK=72MHz USARTDIV 实际波特率 误差
9600 72MHz 468.75 9600 0%
115200 72MHz 39.0625 115200 0%
250000 72MHz 18.0 250000 0%
921600 72MHz 4.8828 921600 0%
误差警告:当f_CK不是16*BaudRate的整数倍时,小数部分舍入会产生误差。误差超过2%可能导致通信不稳定。建议使用整数运算计算USART_BRR,并验证实际波特率误差。

3.3.5 波特率计算流程图

波特率计算与USART_BRR配置流程 获取f_CK时钟频率 计算USARTDIV 提取整数/小数 写入USART_BRR 公式:USARTDIV = f_CK / (16 * BaudRate) BRR = (Mantissa << 4) | Fraction,其中Fraction = round(小数部分 * 16)

3.4 本章小结

  • GPIO复用功能配置:通过GPIOx_CRL/CRH寄存器设置引脚模式,TX为复用推挽输出,RX为浮空输入。
  • 时钟使能:USART1使用APB2时钟(RCC_APB2ENR),USART2/3使用APB1时钟(RCC_APB1ENR),注意APB1最大频率限制。
  • 波特率计算:使用USARTDIV = f_CK / (16 * BaudRate)计算,通过USART_BRR寄存器的整数和小数部分配置。
  • 误差控制:使用整数运算四舍五入,确保误差在2%以内。