STM32 UART串口通信协议与3种底层驱动实现(寄存器/标准库/HAL库)

STM32 UART串口通信协议与3种底层驱动实现(寄存器/标准库/HAL库)

串口通信是STM32与上位机(电脑、手机、串口调试助手等)交互的核心方式,其稳定性依赖标准化的帧结构、校验规则与配置参数。本文将从串口通信核心规范入手,详细讲解STM32下UART串口的3种核心底层驱动实现方式(直接操作寄存器、标准外设库、HAL库),并对比不同方案的核心差异。

一、串口通信核心规范

串口数据收发的稳定性完全依赖统一的通信规范,包含帧结构、校验方式、配置参数等核心要素。

1.1 串口数据包结构

完整的数据帧需包含固定格式,保障传输完整性与可校验性:
包头 + 命令 + 数据 + 校验 + 包尾

1.2 数据校验方式

数据传输过程中易受干扰,需通过校验机制验证数据完整性,工程中常用以下3种方式:

  • CR校验
  • 异或校验
  • 和校验(工程最常用)

1.3 串口配置核心参数

串口通信的基础参数需上下位机保持一致,核心配置如下:

  • 波特率:默认115200(可根据需求灵活调整)
  • 数据位:8位
  • 停止位:1位
  • 校验位:无校验
  • 通信模式:异步通信
  • 采样方式:16倍过采样

1.4 数据接收与校验逻辑

以接收缓冲区buf为例,典型的帧校验逻辑如下(工程常用):

  • 帧头判定:buf[0] == 0x55
  • 帧尾判定:buf[4] == 0xff
  • 校验逻辑:buf[1] + buf[2] == buf[3]
  • 异常处理:校验失败时需返回错误信息,避免脏数据被处理

二、STM32 UART 3种核心底层驱动实现

以下3种方式均为直接操作UART外设的硬件底层驱动方案,相互独立、同级并列,适用于不同开发场景。

2.1 直接操作寄存器(最底层)

跳过所有库封装,直接读写UART硬件寄存器,适合深入理解串口底层工作原理。

核心寄存器说明

UART的核心操作依赖状态寄存器(SR)和数据寄存器(DR):

  • SR(状态寄存器):位7(TXE)表示发送数据寄存器空;位5(RXNE)表示接收数据寄存器非空。
  • DR(数据寄存器) :串口收发数据的载体,写DR完成数据发送,读DR获取接收数据。
    (注:完整寄存器说明需参考对应STM32型号的数据手册)
代码实现(单字节收发+回显)
c 复制代码
// 单字节发送函数
void SendBit(uint8_t Bit)
{
    // 等待发送寄存器为空
	while(!(USART1->SR & (1<<7))){}
    // 写入数据到发送寄存器
	USART1->DR = Bit;
}

// 单字节接收函数
uint8_t ReciveBit(void)
{
	uint8_t Bit;
    // 等待接收寄存器非空
	while(!(USART1->SR & (1<<5))){}
    // 读取接收寄存器数据
	Bit = USART1->DR;
	return Bit;
}

// 主循环实现数据回显
while (1)
{
	uint8_t ch = ReciveBit();
	SendBit(ch);
}

2.2 标准外设库实现(STM32F1示例)

ST早期官方推出的标准外设库,封装了寄存器操作,兼顾底层可读性与开发效率(注:该库已停止官方维护)。

关键实现步骤
  1. 开启UART和对应GPIO的时钟;
  2. 配置TX引脚为复用推挽输出,RX引脚为浮空输入;
  3. 初始化UART通信参数(波特率、数据位、停止位等);
  4. 使能UART外设。
代码实现
c 复制代码
#include "stm32f10x.h"

// UART初始化函数
void UART_Init() {
    // 开启USART1和GPIOA时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE);
    
    GPIO_InitTypeDef GPIO_InitStruct;
    // 配置TX引脚(PA9)为复用推挽输出
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStruct);
    
    // 配置RX引脚(PA10)为浮空输入
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_Init(GPIOA, &GPIO_InitStruct);
    
    // 初始化UART参数
    USART_InitTypeDef USART_InitStruct;
    USART_InitStruct.USART_BaudRate = 9600;
    USART_InitStruct.USART_WordLength = USART_WordLength_8b;
    USART_InitStruct.USART_StopBits = USART_StopBits_1;
    USART_InitStruct.USART_Parity = USART_Parity_No;
    USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    USART_InitStruct.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;
    USART_Init(USART1, &USART_InitStruct);
    
    // 使能USART1
    USART_Cmd(USART1, ENABLE);
}

// 单字符发送函数
void UART_SendChar(USART_TypeDef* USARTx, char ch) {
    // 等待发送寄存器为空
    while (USART_GetFlagStatus(USARTx, USART_FLAG_TXE) == RESET);
    // 发送字符
    USART_SendData(USARTx, ch);
}

int main() {
    UART_Init();
    // 循环发送字符'H'
    while (1) {
        UART_SendChar(USART1, 'H');
    }
}

2.3 HAL库实现(CubeMX生成)

ST当前主推的开发方案,高度封装,配合CubeMX图形化配置工具可快速完成开发,适配新芯片。

前期配置(CubeMX)
  1. 选择对应STM32型号,开启USART1;
  2. 配置UART模式为"Asynchronous"(异步);
  3. 设置波特率、数据位、停止位等核心参数;
  4. 生成工程代码(本文以MDK-ARM为例)。
    (注:配置界面参考"串口cube配置"截图)
代码实现(循环发送字符串)
c 复制代码
#include "main.h"
#include "usart.h"
#include "gpio.h"

int main(void) {
    // 初始化HAL库
    HAL_Init();
    // 初始化GPIO
    MX_GPIO_Init();
    // 初始化USART1
    MX_USART1_UART_Init();

    uint8_t send_buf[] = "Hello, UART!\r\n";

    while (1) {
        // 发送字符串,超时时间100ms
        HAL_UART_Transmit(&huart1, send_buf, sizeof(send_buf)-1, 100); 
        // 延时1秒
        HAL_Delay(1000);
    }
}

三、标准库与HAL库核心差异对比

对比维度 标准外设库 HAL库
代码风格 接近寄存器操作,底层逻辑清晰 高度封装,代码简洁易移植
学习成本 适合学习底层原理 适合快速开发,上手快
官方支持 停止维护 主推方案,新芯片专属支持
开发效率 中等(需手动配置更多参数) 高(CubeMX一键生成)

四、总结

STM32 UART串口的3种底层驱动实现方式各有适用场景:

  • 直接操作寄存器:适合深入理解串口硬件原理,或对代码体积、执行效率有极致要求的场景;
  • 标准外设库:适合学习STM32外设驱动逻辑,兼容老项目维护;
  • HAL库:适合新项目开发、快速迭代,尤其是使用STM32新款芯片的场景。

无论选择哪种方式,串口通信的核心始终是统一的帧结构、校验规则和配置参数,这是保障通信稳定性的基础。

相关推荐
周洲083010 小时前
STM32 ADC 采集实战|电压采集、分压计算、数据滤波
stm32·单片机·嵌入式硬件
SKH.11 小时前
单片机(2)
单片机
DaTou大头12 小时前
STM32第三篇
单片机·嵌入式·电路基础
H_oRIZoN_13 小时前
Linux入门DAY40(51 单片机入门:GPIO、中断、定时器、PWM、蜂鸣器完整梳理)
单片机·嵌入式硬件
LCG元13 小时前
STM32F103 复位来源诊断实战:RCC_CSR 标志位判优、BKP 复位计数持久化与六种复位源注入实测
stm32·单片机·嵌入式硬件
国产HT1621B15 小时前
显示省不了电,休眠才见真章:1621 低功耗实操
驱动开发·单片机·嵌入式硬件·led驱动·lcd驱动
国科安芯15 小时前
低轨卫星姿轨控系统中高可靠嵌入式控制单元的设计与验证
单片机·mcu·低轨卫星·星间链路·卫星姿轨控
zhangzhangkeji17 小时前
stm32 5-2 : 中断,代码篇,对射式红外计数器,旋转编码器。 本 M3中等密度的中断向量列表
stm32
老当益壮梁奶奶18 小时前
ARM 汇编学习笔记(二)启动代码、指令、函数调用与 C 混合编程
c语言·arm开发·单片机·嵌入式硬件·51单片机
天空'之城19 小时前
单片机基础核心知识点汇总(三十八)
单片机·嵌入式硬件