嵌入式开发必备:深入理解USART通信协议
深入理解USART通信协议
在嵌入式系统开发中,通信是至关重要的一部分。在电赛中,我们往往会用到STM32开发板、CanMV开发板、树莓派等板载计算机,他们之间要进行数据的交换就必须进行通信。而USART(通用同步 / 异步收发传输器)作为一种常见的串行通信接口,广泛应用于各种设备之间的数据传输。本文将详细介绍USART的工作原理、特点,并给出基于STM32单片机的代码实现示例。
什么是USART?
USART:Universal Synchronous Asynchronous Receiver Transmitter,即通用同步异步收发器。USART最初是由Motorola在1970年代设计的,用于解决早期微处理器与外部设备之间的串行通信问题。随着技术发展,USART逐渐成为嵌入式系统中不可或缺的标准接口。
与UART的区别
| 特性 | UART | USART |
|---|---|---|
| 全称 | 通用异步收发器 | 通用同步异步收发器 |
| 通信模式 | 仅支持异步 | 支持同步和异步 |
| 时钟信号 | 无CLK引脚 | 有CLK引脚(可选) |
| 硬件复杂度 | 相对简单 | 相对复杂 |
| 应用场景 | 简单的点对点通信 | 需要时钟同步的场合 |
USART 比 UART 多一个 同步时钟输出功能(对应引脚 CLK),可在通信中提供时钟信号。实际应用中,由于串口通信极少使用同步模式,USART与UART在异步模式下可视为等价的,硬件驱动和配置流程基本一致。
数据帧格式详解
串口通信的核心是数据帧的概念。一个完整的数据帧就像一封包含多个部分的信件,有开头、内容和结尾。
标准数据帧结构
1 | ┌─────────┬───────────────────┬─────────┬─────────┬─────────┐ |
各部分详解
起始位(Start Bit):每个数据帧以逻辑”0”开始,持续1位时间。空闲时线路保持逻辑”1”。接收端通过检测从”1”到”0”的跳变来识别新帧的开始。
数据位(Data Bits):紧跟起始位之后,通常为8位(最常用)或9位。数据以低位优先(LSB First)的方式发送,即 bit0 最先到达线路。
校验位(Parity Bit,可选):用于简单的错误检测。校验位的值由数据位中”1”的个数决定。
停止位(Stop Bits):表示帧的结束,通常为1位、1.5位或2位。停止位为逻辑”1”,用于给接收端提供恢复时间。
校验位的工作原理
校验位是一种简单的检错机制:
- 无校验(None):不发送校验位,数据帧只有起始位+数据位+停止位
- 奇校验(Odd):确保数据位和校验位中”1”的总数为奇数
- 偶校验(Even):确保数据位和校验位中”1”的总数为偶数
例如,发送数据 0x55(二进制
01010101),其中有4个”1”: - 偶校验:校验位 =
0(保持总数为偶数4) - 奇校验:校验位 = 1(使总数变为奇数5)
注意:校验位只能检测奇数个比特错误,如果同时有2个比特出错,校验位可能检测不到。
信号时序与波形
理解串口通信的时序对于调试和问题排查至关重要。
TTL电平信号
在单片机级别(如STM32),USART使用TTL(晶体管-晶体管逻辑)电平:
| 电平状态 | 电压范围 | 逻辑含义 |
|---|---|---|
| 低电平 | 0V ~ 0.4V | 逻辑 “0”(SPACE) |
| 高电平 | 2.4V ~ 3.3V/5V | 逻辑 “1”(MARK) |
发送一个字节的时序示例
以9600波特率、8N1配置(8位数据、无校验、1位停止位)为例,发送数据
0x55:
1 | 空闲状态: ────────────────────────────────────────────── |
波特率与传输时间
波特率(Baud Rate)表示每秒传输的符号数,在串口中也就是每秒传输的位数。常见的标准波特率包括:
| 波特率 | 适用场景 | 每位时间 |
|---|---|---|
| 300 | 远距离、低速设备 | 3.33 ms |
| 1200 | 老式调制解调器 | 833 μs |
| 2400 | 低速串口设备 | 417 μs |
| 9600 | 通用串口(最常用) | 104 μs |
| 19200 | 较快的数据传输 | 52 μs |
| 115200 | 高速通信(USB转串口常用) | 8.68 μs |
| 921600 | 高速模块通信 | 1.08 μs |
| 4608000 | 特殊高速需求 | 0.22 μs |
传输一个字节所需时间 = (数据位 + 起始位 + 停止位 + 校验位) / 波特率
例如 115200 波特率、8N1 格式:传输时间 = 10位 / 115200 ≈ 86.8 μs
USART的工作原理
硬件结构
USART的内部结构可以分为以下几个主要部分:
1 | ┌─────────────────────────────────────┐ |
发送路径详解
流程:CPU(并行数据) → TDR → 发送移位寄存器 → TX引脚(串行位流)
写入数据寄存器 (TDR) CPU或DMA控制器通过内部数据总线,将8位或9位的并行数据写入发送数据寄存器(TDR)。此时数据暂存在TDR中等待发送。
传输至移位寄存器 当发送移位寄存器为空(上一个数据发送完毕)时,TDR中的数据会自动被硬件转移到发送移位寄存器中。一旦数据转移完成,状态寄存器中的 TXE (发送数据寄存器空) 标志置1,提示CPU可以立即写入下一个数据。这种双缓冲机制允许CPU在数据发送的同时准备下一个数据,大大提高了传输效率。
串行移位输出 发送控制器根据配置的波特率产生时钟。在时钟驱动下,发送移位寄存器将数据逐位向TX引脚移动。同时,硬件会自动在数据位前面插入起始位(逻辑0),在数据位后面插入校验位(如果启用)和停止位(逻辑1)。
输出引脚 (TX) 最终,处理好的完整帧(起始位+数据+校验位+停止位)以串行位流的形式,通过TX引脚输出到外部设备。
接收路径详解
流程:RX引脚(串行位流) → 接收移位寄存器 → RDR → CPU(并行数据)
空闲检测与起始位采样 平时,USART的RX引脚保持在高电平状态(空闲状态)。当接收控制器检测到RX从高电平变为低电平时,说明一个新的数据帧即将开始。控制器会立即启动波特率发生器来同步采样时钟。
过采样与起始位验证 为了准确检测起始位并避免噪声干扰,USART通常采用16倍过采样(STM32默认配置)。即在每个比特时间采集16个样本,取中间几个样本进行多数表决。例如,采样序号8、9、10的三个值,取多数作为该位的实际值。
过采样不仅提高了抗干扰能力,还能检测通信错误:
- 如果连续3个采样周期内电平不一致,检测到噪声错误
- 如果在停止位位置采样值为0,检测到帧错误
- 如果奇偶校验不通过,检测到校验错误
数据位接收 完成起始位验证后,接收移位寄存器在同步时钟下,逐位采集RX引脚的电平状态。数据以低位优先的方式接收,即先接收bit0,最后接收bit7。
校验与停止位处理 接收完数据位后,硬件自动进行校验位检查(如果启用了校验)。然后等待停止位的到来,验证停止位是否为预期的逻辑1。
传输至数据寄存器 (RDR) 当一个完整的数据帧(8或9位数据)全部移入接收移位寄存器后,该数据会被并行转移到接收数据寄存器(RDR)中。此时,状态寄存器中的 RXNE (接收数据寄存器非空) 标志置1,同时可能会触发中断或DMA请求通知CPU读取数据。
CPU读取 CPU或DMA控制器通过内部总线读取RDR中的数据。读取完成后,RXNE标志自动清零,USART准备接收下一个字节。
双缓冲机制详解
USART采用双缓冲设计,极大地提升了通信效率:
| 环节 | 缓冲区A | 缓冲区B | 工作方式 |
|---|---|---|---|
| 发送 | TDR(发送数据寄存器) | 发送移位寄存器 | CPU写入TDR,同时移位寄存器发送TDR内容 |
| 接收 | 接收移位寄存器 | RDR(接收数据寄存器) | 移位寄存器接收数据,同时CPU读取RDR |
双缓冲的意义:如果没有双缓冲,CPU必须在等待一个字节发送完成后才能写入下一个字节,这会导致CPU时间浪费。使用双缓冲后,CPU可以连续快速地向TDR写入数据,硬件会自动处理移位发送,CPU只需关注TXE标志即可。
USART的通信模式
异步通信模式(最常用)
异步模式下,发送端和接收端各自使用独立的时钟,通过波特率来约定数据传输的速率。这种模式布线简单,只需TX/RX两根线即可通信。
优点:接线简单,成本低,适合大多数点对点通信场景。
缺点:双方时钟必须足够接近(误差<5%),否则会累积误差导致数据错位。
同步通信模式
同步模式下,USART会通过CLK引脚输出时钟信号,与数据信号同步传输。时钟频率与波特率一致。
同步模式的典型应用: - 连接外部AD/DA转换器 - 与LCD显示屏通信 - 模拟SPI协议(虽然有局限)
重要限制:大多数USART硬件仅支持时钟输出,不支持时钟输入,因此无法实现两个USART设备之间的同步通信。如果需要真正的同步通信,通常使用专用的SPI或I2C接口。
单线半双工模式
某些USART支持单线模式,仅使用一根数据线(TX/RX复用),通过切换方向实现半双工通信。这种模式可以节省IO引脚。
USART与其他通信协议的对比
在嵌入式系统中,常见的通信协议还有SPI和I2C。选择合适的协议需要了解它们的特性:
| 特性 | USART | SPI | I2C |
|---|---|---|---|
| 全称 | 通用同步异步收发器 | 串行外设接口 | 集成电路间总线 |
| 线数 | 2-3根(TX/RX/CLK) | 4根(MOSI/MISO/CLK/CS) | 2根(SDA/SCL) |
| 通信拓扑 | 点对点 | 一主多从 | 多主多从 |
| 最大速度 | 4.5-10 Mbps | 数十 Mbps | 3.4 Mbps(高速模式) |
| 硬件流控 | 支持(RTS/CTS) | 无 | 无 |
| 地址识别 | 无 | 通过CS引脚选择 | 7/10位地址 |
| 从设备数量 | 1个 | 多个(每个需独立CS) | 多个(有限,总线电容限制) |
| 协议复杂度 | 简单 | 中等 | 较复杂 |
| 功耗 | 中等 | 较高(持续时钟) | 较低 |
何时选择USART: - 需要与电脑通信(USB转串口) - 两个设备之间的简单通信 - 需要硬件流控(RTS/CTS) - 传输距离相对较长(可达15米,RS232模式下)
何时选择SPI: - 高速数据传输(显示屏、存储芯片) - 一个主设备连接多个从设备 - 全双工通信需求
何时选择I2C: - 连接多个传感器 - 节省引脚(仅需2根线) - 需要多主机共存
USART的电气特性与电平标准
TTL电平(单片机级别)
大多数单片机(如STM32、51单片机)使用TTL电平:
| 项目 | 说明 |
|---|---|
| 逻辑”0” | 0V ~ 0.4V |
| 逻辑”1” | 2.4V ~ 3.3V(或5V) |
| 驱动能力 | 有限,短距离通信 |
RS232电平(传统串口)
老式电脑的串口使用RS232标准:
| 项目 | 说明 |
|---|---|
| 逻辑”0” | +3V ~ +15V |
| 逻辑”1” | -15V ~ -3V |
| 传输距离 | 最远15米 |
| 抗干扰 | 较强(使用差分信号概念) |
注意:STM32的TTL电平与电脑的RS232电平不兼容,直接连接会损坏单片机!必须使用电平转换芯片(如MAX232)。
RS485电平(工业现场总线)
RS485用于工业环境的长距离通信:
| 项目 | 说明 |
|---|---|
| 信号类型 | 差分信号(A/B两线) |
| 传输距离 | 最远1200米 |
| 传输速率 | 与距离相关(1200m时约100kbps) |
| 拓扑结构 | 总线型,多设备共线 |
| 需要终端电阻 | 通常需要120Ω终端电阻 |
RS485通常需要外接收发器芯片(如MAX485、SP3485),并通过USART发送数据到收发器,再由收发器转换为差分信号。
USART的关键参数配置
波特率设置
波特率的精度取决于系统时钟和分频系数:
1 | 波特率 = f_ck / (16 × USARTDIV) // 16倍过采样模式 |
其中USARTDIV是一个12位的分数寄存器。例如,系统时钟为72MHz,要设置115200波特率:
1 | USARTDIV = 72000000 / (16 × 115200) ≈ 39.0625 |
波特率误差:如果计算出的波特率与目标值有偏差,当偏差过大时会导致通信错误。STM32的技术手册建议误差不超过±2.5%。
数据位长度
| 配置 | 数据位 | 校验位 | 总有效数据 |
|---|---|---|---|
| 8N0 | 8位 | 无 | 8位/帧 |
| 8E1 | 8位 | 偶校验 | 8位/帧 |
| 8O1 | 8位 | 奇校验 | 8位/帧 |
| 9N1 | 9位 | 无 | 9位/帧 |
| 9N2 | 9位 | 无 | 9位/帧 |
9位数据模式常用于实现多机通信:主机发送地址(第九位=1)和数据(第九位=0),从机通过检测第九位来识别地址帧。
停止位长度
| 停止位长度 | 适用场景 |
|---|---|
| 0.5位 | 低速通信,节省时间 |
| 1位 | 最常用 |
| 1.5位 | 仅在数据位=8时有效 |
| 2位 | 高速通信,增强可靠性 |
USART的高级特性
硬件流控制(RTS/CTS)
当发送方和接收方速度不匹配时,可能导致数据丢失。硬件流控制通过额外的两根信号线来解决:
| 信号 | 全称 | 功能 |
|---|---|---|
| RTS | Request To Send | 发送方输出,表示”我准备好接收数据了” |
| CTS | Clear To Send | 接收方输出,表示”你可以发送数据了” |
工作流程: 1. 接收方准备好接收时,将CTS置低 2. 发送方检测到CTS为低,开始发送数据 3. 接收方缓冲区快满时,将CTS置高 4. 发送方检测到CTS为高,暂停发送
多处理器通信
USART支持多处理器模式,通过第9位来区分地址帧和数据帧:
- 所有从机配置为接收模式,检测第9位
- 主机发送地址帧(第9位=1),所有从机接收
- 从机将自己的地址与接收到的地址比较
- 匹配的从机切换到正常接收模式(第9位=0)
- 其他从机保持忽略状态
LIN协议支持(汽车网络)
USART硬件支持LIN(Local Interconnect Network)协议的简化版本,常用于汽车电子中的低速网络。
USART的典型应用场景
调试与日志输出
通过USART连接电脑,使用串口调试助手实时查看程序运行状态,是嵌入式开发最常用的调试手段。
模块通信
| 模块类型 | 通信协议 | 波特率 |
|---|---|---|
| GPS模块 | NMEA 0183 | 9600 |
| ESP8266 WiFi模块 | AT指令 | 115200 |
| 蓝牙模块 | 透传模式 | 9600/115200 |
| 指纹模块 | 自定义协议 | 57600 |
| OLED显示屏 | I2C/SPI | - |
数据采集传输
传感器数据通过USART发送到上位机或数据采集卡,实现环境监测、工业控制等功能。
双机通信
两片STM32之间通过USART实现数据交换,可用于分布式控制系统。
USART的常见问题与解决方案
| 问题现象 | 可能原因 | 解决方案 |
|---|---|---|
| 收到乱码 | 波特率不匹配 | 确认双方波特率一致 |
| 过采样模式不同 | 统一使用16倍或8倍过采样 | |
| 时钟偏差过大 | 检查晶振或PLL配置 | |
| 无数据接收 | TX/RX接反 | 交换TX和RX线 |
| 未使能接收中断 | 检查NVIC和中断回调函数 | |
| 硬件连接问题 | 检查杜邦线连接和电平匹配 | |
| 数据丢包 | 接收处理太慢 | 使用DMA或增加缓冲区 |
| 波特率过高 | 降低波特率或优化处理逻辑 | |
| 通信时好时坏 | 线缆质量差 | 更换屏蔽线或缩短距离 |
| 地线未连接 | 确保共地 | |
| 电磁干扰 | 使用差分信号或增加滤波 |
USART特性总结
灵活的通信模式:支持同步和异步通信,可根据应用需求切换。异步模式最为常用,仅需两根线即可实现全双工通信。
硬件自动化处理:数据帧的组包、拆包、起始位和停止位的添加/移除、校验位的生成与检查,都由硬件自动完成,CPU只需读写数据寄存器。
高效的双缓冲机制:发送和接收各有两个缓冲区(数据寄存器+移位寄存器),允许CPU和硬件并行工作,提高通信效率。
丰富的可配置参数:波特率、数据位长度、停止位数量、校验方式都可以根据需要调整,适应不同的通信需求。
多种传输方式:支持阻塞轮询、中断和DMA三种传输方式,可根据数据量和实时性要求选择合适的方案。
STM32 代码实现
本节以 STM32F4 系列为例,演示使用 HAL 库进行 USART 通信的完整流程。
1. 初始化配置
首先需要在 STM32CubeMX 中配置 USART 参数,或者手动初始化:
1 | /* USART 初始化配置示例(USART1, GPIOA: TX=PA9, RX=PA10) */ |
2. 阻塞式发送与接收
阻塞模式是最简单的通信方式,函数会等待数据发送或接收完成才返回:
1 | /* 阻塞式发送字符串 */ |
3. 中断式发送与接收
中断方式可以让 CPU 在数据发送或接收期间处理其他任务,提高系统效率:
1 | /* 定义全局缓冲区 */ |
4. DMA 传输
DMA(直接内存访问)可以让 USART 在不占用 CPU 的情况下传输数据,非常适合大数据量传输:
1 | /* DMA 配置(需要在 CubeMX 中使能对应 DMA) */ |
5. printf 重定向
将 printf 函数重定向到 USART,方便调试输出:
1 | /* 重定向 printf 到 USART1 */ |
实用技巧与注意事项
1. 硬件接线
串口通信只需要三根线(如果是TTL电平):
| STM32 引脚 | 功能 | 连接设备 |
|---|---|---|
| TX (发送) | 连接对方的 RX | RX |
| RX (接收) | 连接对方的 TX | TX |
| GND | 共地 | GND |
注意:不同设备间通信时电平必须匹配。STM32 通常使用 TTL 电平(0~3.3V),而电脑使用 RS232(±12V) 或 USB 转串口。不匹配的电平可能会损坏设备!
2. 常见问题排查
| 问题现象 | 可能原因 | 解决方案 |
|---|---|---|
| 接收到乱码 | 波特率不匹配 | 确认双方波特率一致 |
| 无数据接收 | TX/RX 接反 | 交换 TX 和 RX 线 |
| 接线松动 | 检查杜邦线连接 | |
| 未使能接收中断 | 检查中断使能和回调函数 | |
| 数据丢包 | 数据处理太慢 | 使用 DMA 或增加缓冲区 |
| 波特率过低 | 提高波特率 |
3. 调试技巧
1 | /* 方法1:使用 LED 指示状态 */ |
4. 通信协议设计建议
在实际项目中,为了保证通信可靠性,建议设计一个简单的通信协议:
1 | /* 简单帧格式示例 */ |
总结
USART 作为嵌入式开发中最常用的通信接口之一,掌握其原理和编程方法是每个嵌入式工程师的必备技能。本文详细介绍了 USART 的工作原理、特点,并提供了基于 STM32 HAL 库的完整代码示例,包括阻塞、中断和 DMA 三种通信方式。在实际开发中,可以根据数据量和实时性要求选择合适的通信方式,同时注意电平匹配和波特率配置,避免常见的通信故障。
