一、开篇:从历史说起
在嵌入式通信领域,UART(Universal Asynchronous Receiver/Transmitter)和USART(Universal Synchronous/Asynchronous Receiver/Transmitter)这两个术语经常被混淆。特别是在STM32的文档和外设命名中,我们经常看到这两种不同的通信接口。它们之间到底有什么区别?今天我们就来彻底解密!
二、基本概念澄清
2.1 UART:异步通信的奠基者
UART 是一种纯粹的异步串行通信协议。它的特点包括:
-
只支持异步通信模式
-
使用起始位、停止位和可选的奇偶校验位进行帧同步
-
通信双方需要事先约定相同的波特率
-
不需要时钟信号线(只有TX和RX两根线)
2.2 USART:同步+异步的全能选手
USART 是在UART基础上发展起来的,关键区别在于:
-
支持同步和异步两种通信模式
-
在同步模式下需要额外的时钟信号线(CK引脚)
-
通常支持更多的通信协议
三、技术细节对比
3.1 同步模式:USART的独家功能
cs
// STM32 USART同步模式配置示例
void USART_SyncMode_Config(void)
{
USART_InitTypeDef USART_InitStructure;
// 配置为同步模式
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_InitStructure.USART_BaudRate = 9600;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
// 关键配置:同步模式
USART_InitStructure.USART_Clock = USART_Clock_Enable;
USART_InitStructure.USART_CPOL = USART_CPOL_Low; // 时钟极性
USART_InitStructure.USART_CPHA = USART_CPHA_1Edge; // 时钟相位
USART_InitStructure.USART_LastBit = USART_LastBit_Disable;
USART_Init(USART1, &USART_InitStructure);
}
3.2 硬件引脚差异
// UART接口(基本配置)
UART_TX ------------ UART_RX
UART_RX ------------ UART_TX
GND ------------ GND
// USART接口(同步模式)
USART_TX ------------ USART_RX
USART_RX ------------ USART_TX
USART_CK ------------ USART_CK // 同步时钟线
GND ------------ GND
四、STM32中的实际实现
4.1 硬件架构差异
在STM32中,USART和UART实际上是同一类型的外设,但在功能上有所区分:
STM32F1系列:
// 外设名称映射(以STM32F103为例)
USART1: 全功能USART,支持同步模式
USART2: 全功能USART,支持同步模式
USART3: 全功能USART,支持同步模式
UART4: 仅异步模式(缺少CK引脚)
UART5: 仅异步模式(缺少CK引脚)
STM32F4系列:
// 在F4系列中,几乎所有串口都是USART
USART1: 全功能,带CK引脚
USART2: 全功能,带CK引脚
USART3: 全功能,带CK引脚
UART4: 实际上是USART4,但部分型号可能限制功能
UART5: 同UART4
USART6: 全功能,带CK引脚
4.2 寄存器级差异
我们可以通过检查控制寄存器来判断外设能力:
cs
// 检查USART同步功能
uint32_t Check_USART_Sync_Capability(USART_TypeDef* USARTx)
{
// USART_CR2寄存器中的CLKEN位指示同步模式支持
if(USARTx->CR2 & USART_CR2_CLKEN)
{
return 1; // 支持同步模式
}
return 0; // 不支持同步模式
}
// USART特有寄存器
typedef struct
{
__IO uint32_t SR; // 状态寄存器
__IO uint32_t DR; // 数据寄存器
__IO uint32_t BRR; // 波特率寄存器
__IO uint32_t CR1; // 控制寄存器1
__IO uint32_t CR2; // 控制寄存器2 // UART可能缺少某些位
__IO uint32_t CR3; // 控制寄存器3 // UART可能缺少某些位
__IO uint32_t GTPR; // 保护时间和预分频寄存器(某些USART特有)
} USART_TypeDef;
五、同步时钟:USART的核心优势
5.1 时钟信号的作用
在同步模式下,USART通过CK引脚提供时钟信号:
-
精确同步:每个数据位都在时钟边沿被采样
-
更高速度:可以达到比异步模式更高的波特率
-
降低误差:无需精确匹配波特率
5.2 时钟极性和相位配置
cs
// 时钟配置组合示例
typedef enum
{
// 模式0:CK空闲低电平,在第一个边沿采样
USART_Sync_Mode0 = (USART_CPOL_Low | USART_CPHA_1Edge),
// 模式1:CK空闲低电平,在第二个边沿采样
USART_Sync_Mode1 = (USART_CPOL_Low | USART_CPHA_2Edge),
// 模式2:CK空闲高电平,在第一个边沿采样
USART_Sync_Mode2 = (USART_CPOL_High | USART_CPHA_1Edge),
// 模式3:CK空闲高电平,在第二个边沿采样
USART_Sync_Mode3 = (USART_CPOL_High | USART_CPHA_2Edge)
} USART_Sync_Mode;
六、实际应用场景
6.1 何时选择UART?
cs
// UART适用场景:
// 1. 简单的点对点通信
// 2. 与PC串口通信(RS-232)
// 3. 与蓝牙模块、GPS模块通信
// 4. 调试信息输出(printf重定向)
void UART_Debug_Init(void)
{
// 简单的调试串口初始化
UART_InitTypeDef UART_InitStructure;
UART_InitStructure.UART_BaudRate = 115200;
UART_InitStructure.UART_WordLength = UART_WordLength_8b;
UART_InitStructure.UART_StopBits = UART_StopBits_1;
UART_InitStructure.UART_Parity = UART_Parity_No;
UART_InitStructure.UART_Mode = UART_Mode_Rx | UART_Mode_Tx;
UART_InitStructure.UART_HardwareFlowControl = UART_HardwareFlowControl_None;
UART_Init(UART4, &UART_InitStructure);
UART_Cmd(UART4, ENABLE);
}
6.2 何时选择USART同步模式?
七、性能对比分析
cs
// USART同步模式适用场景:
// 1. 高速数据传输(SPI替代方案)
// 2. 需要精确时序的应用
// 3. 与某些需要时钟的外设通信
// 4. 多主设备通信场景
void USART_Sync_SPI_Like_Init(void)
{
// 将USART配置为类似SPI的主设备
USART_InitTypeDef USART_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
// 配置CK引脚为输出
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8; // USART1_CK
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
// USART同步主模式配置
USART_InitStructure.USART_BaudRate = 2000000; // 2 Mbps
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
// 同步模式特有配置
USART_InitStructure.USART_Clock = USART_Clock_Enable;
USART_InitStructure.USART_CPOL = USART_CPOL_Low;
USART_InitStructure.USART_CPHA = USART_CPHA_1Edge;
USART_InitStructure.USART_LastBit = USART_LastBit_Disable;
USART_Init(USART1, &USART_InitStructure);
USART_Cmd(USART1, ENABLE);
}
7.1 波特率范围
| 型号 | UART最大波特率 | USART异步最大波特率 | USART同步最大波特率 |
|---|---|---|---|
| STM32F103 | 4.5 Mbps | 4.5 Mbps | 最高可达系统时钟/8 |
| STM32F407 | 10.5 Mbps | 10.5 Mbps | 最高可达42 Mbps |
7.2 时钟精度要求
cs
// 异步模式下的波特率误差计算
float Calculate_BaudRate_Error(uint32_t desired_baud, uint32_t actual_baud)
{
// UART对时钟精度要求较高,通常需要<2%的误差
float error = ((float)actual_baud - desired_baud) / desired_baud * 100.0;
return error;
}
// 同步模式下,时钟由主机提供,从机无需精确匹配波特率
// 这是同步模式的一大优势
八、编程模型差异
8.1 中断处理差异
cs
// USART有更丰富的中断源
void USART_IRQHandler(void)
{
// USART特有中断
if(USART_GetITStatus(USART1, USART_IT_CTS) != RESET) // CTS变化中断
{
// 硬件流控制处理
USART_ClearITPendingBit(USART1, USART_IT_CTS);
}
// USART同步模式相关中断
if(USART_GetITStatus(USART1, USART_IT_LBD) != RESET) // LIN断开检测
{
// LIN总线处理
USART_ClearITPendingBit(USART1, USART_IT_LBD);
}
// UART/USART共有中断
if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)
{
uint8_t data = USART_ReceiveData(USART1);
// 数据处理
}
}
8.2 DMA支持
USART通常有更完善的DMA支持:
cs
void USART_DMA_Config(void)
{
// USART支持发送和接收DMA
USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE);
USART_DMACmd(USART1, USART_DMAReq_Rx, ENABLE);
// 某些UART可能缺少接收DMA支持
}
九、现代STM32中的发展趋势
9.1 HAL库的统一接口
在STM32Cube HAL库中,UART和USART使用相同的接口:
cs
// HAL库中不再区分UART和USART
UART_HandleTypeDef huart;
// 初始化配置类似
huart.Instance = USART1; // 即使是UART也使用USART_TypeDef
huart.Init.BaudRate = 115200;
huart.Init.WordLength = UART_WORDLENGTH_8B;
huart.Init.StopBits = UART_STOPBITS_1;
huart.Init.Parity = UART_PARITY_NONE;
huart.Init.Mode = UART_MODE_TX_RX;
huart.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart.Init.OverSampling = UART_OVERSAMPLING_16;
// 同步模式配置(如果支持)
huart.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
// 对于同步模式需要额外配置
9.2 LL库的底层区别
在LL(Low Layer)库中,差异更加明显:
cs
// 检查外设类型
if(IS_UART_INSTANCE(USART1))
{
// UART特有操作
LL_UART_Enable(USART1);
}
else if(IS_USART_INSTANCE(USART1))
{
// USART特有操作
if(LL_USART_IsEnabledSyncMode(USART1))
{
// 同步模式操作
LL_USART_EnableClock(USART1);
}
}
十、实战建议
10.1 选择指南
-
简单通信 → 选择UART(如果可用)
-
需要硬件流控制 → 选择USART
-
高速同步通信 → 必须选择USART
-
LIN总线应用 → 必须选择USART
-
智能卡模式 → 必须选择USART
10.2 兼容性设计
cs
// 设计兼容UART和USART的代码
#ifdef USE_FULL_USART
#define SERIAL_TYPE USART_TypeDef
#define SERIAL_INIT USART_Init
#define SERIAL_CMD USART_Cmd
#else
#define SERIAL_TYPE UART_TypeDef
#define SERIAL_INIT UART_Init
#define SERIAL_CMD UART_Cmd
#endif
void Serial_Init(SERIAL_TYPE* Serialx, uint32_t baudrate)
{
// 通用初始化代码
// 具体实现根据SERIAL_TYPE调整
}
十一、总结
UART和USART在STM32中的区别可以概括为:
| 特性 | UART | USART |
|---|---|---|
| 通信模式 | 仅异步 | 同步+异步 |
| 时钟引脚 | 无 | 有(CK) |
| 最大波特率 | 受系统时钟限制 | 同步模式下更高 |
| 额外功能 | 基本功能 | 硬件流控制、LIN、智能卡等 |
| 引脚数 | 2线(TX+RX) | 3线或更多 |
核心要点:
-
所有USART都可以作为UART使用
-
不是所有UART都能作为USART使用
-
在STM32中,硬件上通常设计为USART,但某些型号可能限制功能
-
选择哪个取决于具体应用需求
理解这些差异,可以帮助你在项目中选择最合适的通信接口,充分利用STM32的外设资源。记住,在大多数情况下,你可以将USART当作UART使用,但反过来不行!