
本文概述
STM32的USART串口是嵌入式开发中最基础也最常用的外设之一,配置流程可以分为五个步骤:使能时钟、配置GPIO复用、设置串口参数(波特率、字长、停止位、校验位)、配置中断(如果需要)、使能外设。波特率由BRR寄存器控制,计算公式为波特率等于外设时钟除以16倍的USARTDIV分频值。实际使用中要注意波特率误差控制在2%以内,不同主频下误差不同,选择合适的晶振频率很重要。除了基本的查询方式收发,还可以用中断和DMA来提高效率。
核心要点速览
USART配置五步法:时钟使能→GPIO复用→参数设置→中断配置→使能外设
波特率公式:波特率 = fCK / (16 × USARTDIV)
BRR寄存器:高12位整数部分,低4位小数部分(OVER8=0时)
波特率误差一般要求在2%以内,最好在1%以内
TX推挽复用输出,RX浮空或上拉输入
收发方式:轮询、中断、DMA三种,各有适用场景
一、面试官考察点
| 考察维度 | 具体内容 | 常见误区 |
|---|---|---|
| 寄存器级理解 | 是否知道BRR寄存器结构,能否讲出波特率的计算过程 | 只会用库函数,不知道底层寄存器怎么回事 |
| 配置流程熟练度 | 配置步骤是否完整,有没有遗漏时钟、GPIO、中断等环节 | 忘记使能时钟或者GPIO配置错了模式 |
| 误差分析能力 | 是否理解波特率误差的来源和影响,知道误差范围要求 | 以为波特率都是精确的,不知道有误差 |
| 实际应用经验 | 是否用过中断、DMA方式,有没有调试串口问题的经验 | 只用过最简单的轮询方式 |
二、回答思路
USART配置完整步骤
使能时钟
第一步是使能GPIO和USART的时钟。不同型号的STM32,USART挂在不同的总线上,比如USART1在APB2上,USART2和USART3在APB1上。对应的GPIO端口时钟也要打开,比如PA9和PA10是USART1的引脚,就要打开GPIOA的时钟。如果用重映射功能,还要打开AFIO时钟。用HAL库的话,调用__HAL_RCC_USART1_CLK_ENABLE()和__HAL_RCC_GPIOA_CLK_ENABLE()就可以了。
配置GPIO引脚
TX引脚配置为复用推挽输出模式,速度选50MHz就行。RX引脚配置为浮空输入或者上拉输入,一般浮空输入就可以,因为串口空闲时是高电平。用标准库的话,GPIO_InitTypeDef里配置Mode和Speed。用HAL库的话,要配置Alternate参数,指定是哪个USART的复用功能。F1系列是直接配复用推挽,F4及以后的系列要单独指定复用功能编号。
设置串口参数
这一步配置波特率、字长、停止位、奇偶校验和流控。波特率是最核心的参数,通过BRR寄存器设置。字长一般选8位,也可以选9位(带奇偶校验的时候其实是8位数据加1位校验位)。停止位可以选1位、0.5位、1.5位或2位,最常用的是1位。奇偶校验可以选无校验、奇校验或偶校验。硬件流控CTS/RTS一般不用,保持关闭就行。
配置中断(可选)
如果要用中断方式收发,就要配置NVIC和USART的中断使能位。常用的中断有发送完成中断、接收缓冲区非空中断。接收中断最常用,收到一个字节就触发中断,在中断服务函数里把数据读出来。要注意配置NVIC的优先级,抢占优先级和子优先级要设置好。如果用HAL库,要先开HAL_NVIC_SetPriority,再HAL_NVIC_EnableIRQ,然后调用__HAL_UART_ENABLE_IT()使能具体的中断位。
使能USART外设
所有参数配置好之后,把USART_CR1寄存器的UE位置1,使能整个串口外设。然后还要分别使能发送和接收,也就是TE位和RE位。这两个位也在CR1寄存器里。使能之后,串口就开始工作了。发送的时候往DR寄存器写数据,接收的时候从DR寄存器读数据。注意USART使能后不能马上配置寄存器,要等它稳定下来,不过一般操作顺序上不会有问题。
波特率计算详解
波特率的计算是面试的高频考点,一定要理解透。STM32的USART使用一个16倍的过采样时钟来采样接收数据,所以分频系数是16倍的关系。
举例计算:以STM32F103为例,系统主频72MHz,USART1挂在APB2上,时钟也是72MHz。要配置波特率为115200:
USARTDIV = 72000000 / (16 × 115200) = 72000000 / 1843200 ≈ 39.0625
整数部分 = 39,小数部分 = 0.0625
小数部分乘以16(因为低4位表示小数):0.0625 × 16 = 1
所以BRR寄存器的值 = (39 << 4) | 1 = 0x271
波特率误差:因为分频值是有限精度的,实际波特率和理想波特率之间会有误差。误差的计算公式是:误差率 = |实际波特率 - 理想波特率| / 理想波特率 × 100%。上例中,USARTDIV刚好是39.0625,是精确值,误差为零。但有些主频和波特率的组合就没这么巧了。比如用8MHz内部RC时钟,配置9600波特率,误差可能会比较大。
三种收发方式对比
| 方式 | 原理 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|---|
| 轮询方式 | 循环检查标志位,等到了就读写 | 简单,容易理解 | 占用CPU,效率低 | 简单测试、数据量很小 |
| 中断方式 | 收到或发完触发中断,在中断里处理 | CPU利用率高,响应及时 | 中断频繁时有开销 | 一般应用,数据量中等 |
| DMA方式 | DMA自动搬运数据,CPU不参与 | 效率最高,CPU零负担 | 配置复杂,需要DMA通道 | 大数据量传输、高速通信 |
常见问题与调试技巧
串口发不出数据或收不到数据的常见原因
时钟没使能:GPIO或USART的RCC时钟忘记打开,这是最常见的低级错误
GPIO配置错了:TX配成输入了,或者RX配成输出了,或者复用功能没配对
波特率不匹配:两边波特率设得不一样,或者时钟频率不对导致波特率误差大
TX和RX接反了:这个真的经常发生,交叉连接才对,自己的TX接对方的RX
没有使能发送或接收:USART使能了,但TE或RE位没置1
中断标志没清:中断服务函数里忘记清标志位,导致一直进中断
电平不匹配:3.3V的单片机接5V的串口设备,或者反过来,需要电平转换
调试串口问题的一般步骤是:先拿示波器量TX引脚有没有波形,有波形说明发送端没问题,问题在接收端或者上位机;没波形就查发送配置。如果有波形但上位机显示乱码,那基本就是波特率不对,量一下实际的bit宽度算出来实际波特率是多少,再调整。如果偶发错误,考虑是不是波特率误差太大或者有干扰。
三、追问环节
追问1:为什么串口波特率误差不能太大?
因为UART是异步通信,发送方和接收方各自用自己的时钟,接收端通过起始位来同步,然后在每个bit的中间位置采样。一帧数据有起始位、8个数据位、停止位,一共10个bit左右。如果波特率有误差,每采一个bit采样点就偏移一点,到最后一个bit的时候偏移量累积起来,如果偏到了bit的边缘甚至下一个bit里,就会采错。一般来说误差要控制在2%以内,最好在1%以内,这样10个bit累积下来偏移不到半个bit,是安全的。
追问2:OVER8模式是什么?什么时候用?
OVER8是8倍过采样模式,默认是16倍过采样。用过采样倍数降低一半,波特率就可以提高一倍,或者说同样的波特率下需要的时钟频率更低。OVER8模式下,BRR寄存器的小数部分只有3位,不是4位了,精度稍微差一点。什么时候用呢?主要是在主频不高但需要很高波特率的时候。比如有些低功耗芯片主频只有几十兆,但要支持1Mbps以上的串口速率,就可以开OVER8模式。一般情况下用默认的OVER16就够了。
追问3:串口接收的时候怎么处理不定长数据?
这是实际开发中经常遇到的问题。常见的处理方式有几种:第一种是用空闲中断,一帧数据发完之后总线空闲了就触发空闲中断,说明一包数据收完了,这种方式效率高而且响应快。第二种是用定时器超时,收到第一个字节后启动定时器,如果超过一定时间没有新数据,就认为一帧结束了。第三种是按协议解析,比如有帧头帧尾或者长度字段,边收边解析,收够了就处理。实际项目中第一种最常用,STM32的USART有专门的IDLE中断位,配置起来也很方便。
追问4:USART和UART有什么区别?
USART是通用同步异步收发器,UART是通用异步收发器。区别就是USART多了同步通信的功能,也就是可以提供时钟信号,实现同步通信。同步模式下,有一个SCLK引脚输出时钟,接收方用这个时钟来采样数据,不需要各自的波特率时钟,精度更高,速率也可以更快。但实际项目中同步模式用得非常少,绝大多数时候我们都是用异步模式,也就是和普通UART一样的用法。所以很多时候大家说USART和UART不怎么区分,但原理上要知道它们的区别。
四、失分表达
常见失分回答
"调用HAL_UART_Init函数就行,参数填进去就好了"——只说库函数调用,不讲原理和配置过程,说明理解不深
"波特率是寄存器直接设的,具体怎么算我没研究过"——波特率计算是基础中的基础,不会说不过去
"串口很简单,就收发两个脚,插上就能用"——说得太轻描淡写,说明没有深入理解和调试经验
五、准备动作
手写一遍波特率计算过程
用72MHz算115200和9600两个常用波特率,把整数小数分别算出来,BRR值也写出来。
用寄存器版写一遍串口初始化
不要只会用库函数,尝试直接操作寄存器来初始化串口,这样才能真正理解每个位的作用。
做一个空闲中断接收的例程
实现一个串口不定长数据接收的程序,用IDLE中断加环形缓冲区,这是实际项目中最常用的方案。
六、核心关键词
USART配置 波特率计算 BRR寄存器 波特率误差 GPIO复用 空闲中断 串口DMA 异步通信

扫码关注





























