STM32中USART和UART的区别是什么?

一、开篇:从历史说起

在嵌入式通信领域,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 选择指南

  1. 简单通信 → 选择UART(如果可用)

  2. 需要硬件流控制 → 选择USART

  3. 高速同步通信 → 必须选择USART

  4. LIN总线应用 → 必须选择USART

  5. 智能卡模式 → 必须选择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线或更多

核心要点

  1. 所有USART都可以作为UART使用

  2. 不是所有UART都能作为USART使用

  3. 在STM32中,硬件上通常设计为USART,但某些型号可能限制功能

  4. 选择哪个取决于具体应用需求

理解这些差异,可以帮助你在项目中选择最合适的通信接口,充分利用STM32的外设资源。记住,在大多数情况下,你可以将USART当作UART使用,但反过来不行!

相关推荐
一路往蓝-Anbo2 小时前
C语言从句柄到对象 (三) —— 抛弃 Malloc:静态对象池与索引句柄的终极形态
c语言·开发语言·数据结构·stm32·单片机·算法
wdfk_prog2 小时前
[Linux]学习笔记系列 -- [fs]mbcache
linux·笔记·学习
心前阳光2 小时前
Unity通过ScriptableObject学习访问者模式
学习·unity·访问者模式
Freshman小白2 小时前
《现代电力电子技术及应用》2025网课答案
学习·答案·网课答案
集芯微电科技有限公司3 小时前
PC1001超高频率(50HMZ)单通单低侧GaN FET驱动器支持正负相位配置
数据结构·人工智能·单片机·嵌入式硬件·神经网络·生成对抗网络·fpga开发
QT 小鲜肉3 小时前
【Linux命令大全】001.文件管理之slocate命令(实操篇)
linux·运维·服务器·数据库·笔记
一路往蓝-Anbo3 小时前
C语言从句柄到对象 (二) —— 极致的封装:不透明指针与 SDK 级设计
c语言·开发语言·数据结构·stm32·单片机·嵌入式硬件
上天_去_做颗惺星 EVE_BLUE3 小时前
C++学习:学生成绩管理系统
c语言·开发语言·数据结构·c++·学习
dlz08363 小时前
点亮LED灯
单片机·嵌入式硬件