1. USART通讯基础概念解析
USART(Universal Synchronous/Asynchronous Receiver/Transmitter)是一种通用的同步/异步串行通信接口,在嵌入式系统中广泛应用。与单纯的UART(异步模式)相比,USART增加了同步通信能力,使其应用场景更加广泛。
1.1 USART与UART的核心区别
USART和UART的主要差异体现在时钟信号的配置上:
-
UART:纯异步通信,仅依靠TX(发送)和RX(接收)两条信号线传输数据,没有独立的时钟线。通信双方需要预先约定相同的波特率(Baud Rate)来同步数据采样。
-
USART:支持同步和异步两种模式。同步模式下,除了TX/RX外,还提供SCLK(同步时钟)信号线,由主机提供时钟信号,从设备根据时钟边沿采样数据,无需预先约定波特率。
实际应用中,大多数STM32等现代MCU的USART外设默认工作在异步(UART)模式,同步模式多用于特定协议(如智能卡、LIN总线等)场景。
1.2 串行通信帧格式详解
无论是USART还是UART,数据都是以帧为单位传输的。一个完整的数据帧包含以下部分:

- 起始位(Start Bit):固定为1位低电平,标志一帧数据的开始。
- 数据位(Data Bits):有效数据长度,通常为5-9位(常用8位)。
- 校验位(Parity Bit,可选):
- 奇校验(Odd):数据位+校验位中"1"的总数为奇数
- 偶校验(Even):数据位+校验位中"1"的总数为偶数
- 停止位(Stop Bit):1位、1.5位或2位高电平,标志一帧数据结束。
- 空闲帧(Idle Frame):连续高电平,表示当前无数据传输。
1.3 波特率与比特率的关系
- 波特率(Baud Rate):每秒传输的码元(符号)数量,决定每个位的持续时间。
- 比特率(Bit Rate):每秒传输的二进制位数。
在二进制通信中(每个码元代表1bit),波特率等于比特率。例如115200波特率即每秒传输115200位数据。计算实际数据传输速率时,需考虑帧格式开销:
code复制有效数据速率 = (数据位长度 / 总帧长度) × 波特率
例如:8N1格式(8数据位+无校验+1停止位)
有效速率 = (8/10) × 115200 = 92160 bps
2. USART硬件连接与电平标准
2.1 基础连接方式
USART/UART最基本的连接方式是三线制:
- TX(发送端) → 对端RX
- RX(接收端) ← 对端TX
- GND(共地)
注意:这种直连方式仅适用于短距离(通常<1米)和相同电平标准的设备间通信。
2.2 常见电平标准对比
| 标准 | 逻辑0 | 逻辑1 | 传输距离 | 特点 |
|---|---|---|---|---|
| TTL | 0V | 3.3V/5V | <0.5m | 直接连接MCU IO |
| RS232 | +3V~+15V | -3V~-15V | 15m | 抗干扰强,需电平转换 |
| RS422 | A-B < -0.2V | A-B > +0.2V | 1200m | 差分信号,全双工 |
| RS485 | A-B < -0.2V | A-B > +0.2V | 1200m | 差分信号,半双工 |
2.3 USB转TTL模块的应用
开发板上常见的USB转TTL芯片(如CH340、CP2102)实现了:
- USB协议 ↔ 串行数据转换
- USB电平(差分) ↔ TTL电平转换
- 在主机端虚拟出COM端口
接线示例:
code复制MCU TX → 模块RX
MCU RX ← 模块TX
MCU GND ↔ 模块GND
注意:不要连接模块的VCC到MCU除非确认电压匹配,多数开发板已内置3.3V稳压。
3. STM32 USART编程实战
3.1 硬件初始化配置
使用STM32CubeMX配置USART1异步模式:
c复制huart1.Instance = USART1;
huart1.Init.BaudRate = 115200;
huart1.Init.WordLength = UART_WORDLENGTH_8B;
huart1.Init.StopBits = UART_STOPBITS_1;
huart1.Init.Parity = UART_PARITY_NONE;
huart1.Init.Mode = UART_MODE_TX_RX;
huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart1.Init.OverSampling = UART_OVERSAMPLING_16;
HAL_UART_Init(&huart1);
关键参数解析:
- OverSampling:过采样率(16x或8x),影响抗噪能力和最高波特率
- HwFlowCtl:硬件流控(RTS/CTS),高速通信时建议启用
- WordLength:包含校验位时的实际数据位长度
3.2 轮询模式通信
基础收发示例:
c复制// 发送字符串
HAL_UART_Transmit(&huart1, (uint8_t*)"Hello", 5, 100);
// 接收固定长度数据
uint8_t rx_data[10];
if(HAL_UART_Receive(&huart1, rx_data, 10, 1000) == HAL_OK) {
// 处理接收数据
}
轮询模式的缺点:阻塞式等待,效率低,适合简单应用或调试。
3.3 中断模式优化
中断接收实现步骤:
- 启用USART全局中断(NVIC)
- 启动中断接收
- 实现中断回调函数
c复制// 启动中断接收
HAL_UART_Receive_IT(&huart1, rx_buf, BUF_SIZE);
// 接收完成回调
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) {
if(huart == &huart1) {
// 处理数据
// 重新启动接收
HAL_UART_Receive_IT(&huart1, rx_buf, BUF_SIZE);
}
}
3.4 DMA+空闲中断高效方案
针对变长数据的高效处理方案:
c复制// 初始化DMA接收
HAL_UART_Receive_DMA(&huart1, dma_buffer, DMA_BUF_SIZE);
__HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE);
// 空闲中断处理
void USART1_IRQHandler(void) {
if(__HAL_UART_GET_FLAG(&huart1, UART_FLAG_IDLE)) {
__HAL_UART_CLEAR_IDLEFLAG(&huart1);
HAL_UART_DMAStop(&huart1);
// 计算接收长度
uint16_t len = DMA_BUF_SIZE - __HAL_DMA_GET_COUNTER(&hdma_usart1_rx);
// 处理数据
process_data(dma_buffer, len);
// 重启DMA接收
HAL_UART_Receive_DMA(&huart1, dma_buffer, DMA_BUF_SIZE);
}
HAL_UART_IRQHandler(&huart1);
}
4. 高级应用技巧
4.1 printf重定向实现
在MDK-ARM中实现printf到串口:
c复制#include <stdio.h>
int fputc(int ch, FILE *f) {
HAL_UART_Transmit(&huart1, (uint8_t*)&ch, 1, HAL_MAX_DELAY);
return ch;
}
需在工程选项中勾选"Use MicroLIB"。
4.2 环形缓冲区实现
高效数据缓冲方案:
c复制typedef struct {
uint8_t buffer[256];
volatile uint16_t head;
volatile uint16_t tail;
} RingBuffer;
void rb_push(RingBuffer *rb, uint8_t data) {
rb->buffer[rb->head++] = data;
if(rb->head >= sizeof(rb->buffer)) rb->head = 0;
}
uint8_t rb_pop(RingBuffer *rb) {
uint8_t data = rb->buffer[rb->tail++];
if(rb->tail >= sizeof(rb->buffer)) rb->tail = 0;
return data;
}
bool rb_is_empty(RingBuffer *rb) {
return rb->head == rb->tail;
}
4.3 硬件流控配置
RTS/CTS流控配置示例:
c复制huart1.Init.HwFlowCtl = UART_HWCONTROL_RTS_CTS;
huart1.Init.OverSampling = UART_OVERSAMPLING_8; // 流控时建议8x过采样
// GPIO配置
GPIO_InitStruct.Pin = GPIO_PIN_11|GPIO_PIN_12; // CTS/RTS引脚
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF7_USART1;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
5. 工业通信标准:RS232/422/485
5.1 RS232详解
- 电平:±3V~±15V(负逻辑)
- 距离:典型15米(115200bps时)
- 特点:
- 全双工点对点通信
- 需要电平转换芯片(如MAX232)
- 支持硬件流控(RTS/CTS)
5.2 RS422与RS485对比
| 特性 | RS422 | RS485 |
|---|---|---|
| 工作模式 | 全双工 | 半双工 |
| 差分线对 | 两对(TX/RX) | 一对(DATA) |
| 节点能力 | 1发10收 | 32单位负载 |
| 终端电阻 | 100Ω | 120Ω |
| 典型应用 | 工业仪表 | MODBUS总线 |
5.3 RS485总线设计要点
- 终端电阻:在总线两端并联120Ω电阻,消除信号反射
- 偏置电阻:空闲时通过4.7kΩ上拉(A)和下拉(B)电阻确保确定状态
- 收发控制:使用单独的GPIO控制收发器方向(DE/RE)
c复制void rs485_send(uint8_t *data, uint16_t len) { HAL_GPIO_WritePin(DE_GPIO_Port, DE_Pin, GPIO_PIN_SET); // 使能发送 HAL_UART_Transmit(&huart1, data, len, 100); while(__HAL_UART_GET_FLAG(&huart1, UART_FLAG_TC) == RESET); // 等待发送完成 HAL_GPIO_WritePin(DE_GPIO_Port, DE_Pin, GPIO_PIN_RESET); // 切回接收 }
6. ESP32-S3 UART应用实例
6.1 初始化配置
c复制uart_config_t uart_config = {
.baud_rate = 115200,
.data_bits = UART_DATA_8_BITS,
.parity = UART_PARITY_DISABLE,
.stop_bits = UART_STOP_BITS_1,
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
.source_clk = UART_SCLK_DEFAULT,
};
uart_driver_install(UART_NUM_1, 1024*2, 1024*2, 10, &uart_queue, 0);
uart_param_config(UART_NUM_1, &uart_config);
uart_set_pin(UART_NUM_1, TXD_PIN, RXD_PIN, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
6.2 中断处理模式
c复制// 配置模式检测中断(如AT指令识别)
uart_enable_pattern_det_baud_intr(UART_NUM_1, '+', 3, 9, 0, 0);
// 任务处理事件
xTaskCreate(uart_event_task, "uart_event", 2048, NULL, 12, NULL);
void uart_event_task(void *pvParameters) {
uart_event_t event;
while(1) {
if(xQueueReceive(uart_queue, (void*)&event, portMAX_DELAY)) {
switch(event.type) {
case UART_PATTERN_DET:
// 处理模式匹配
break;
case UART_DATA:
// 处理普通数据
break;
}
}
}
}
7. 常见问题与调试技巧
7.1 通信失败排查步骤
-
检查物理连接
- 确认TX-RX交叉连接
- 检查地线连接
- 测量信号线电压
-
验证配置参数
- 两端波特率一致(误差<3%)
- 数据帧格式匹配(数据位/停止位/校验)
- 流控设置一致
-
信号质量分析
- 使用逻辑分析仪捕获波形
- 检查信号上升/下降时间
- 观察噪声和振铃现象
7.2 抗干扰设计建议
-
硬件措施
- 增加线路滤波电容(10-100nF)
- 使用双绞线(差分信号)
- 添加TVS二极管防护
-
软件措施
- 实现数据校验(CRC/Checksum)
- 增加超时重传机制
- 采用数据包应答协议
7.3 性能优化技巧
-
DMA使用要点
- 设置合理的DMA缓冲区大小(通常为2的幂次)
- 使用双缓冲技术减少处理延迟
- 定期检查DMA指针位置防止溢出
-
低功耗设计
- 空闲时关闭UART时钟
- 使用硬件唤醒功能
- 动态调整波特率降低功耗
通过以上全面的USART/UART技术解析和实战示例,开发者可以快速掌握串行通信的核心技术要点,并能在实际项目中灵活应用各种高级功能。不同MCU平台的实现虽有差异,但核心原理相通,理解底层机制有助于快速移植和调试。