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新款芯片的场景。

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

相关推荐
项目題供诗4 小时前
STM32-TIM输入捕获(十四)
stm32·单片机·嵌入式硬件
cpsss06814 小时前
Freertos的Systick_Handler重定义
单片机·嵌入式硬件
国产电子元器件6 小时前
电流传感器的输出可以直接接示波器吗?
stm32·单片机·嵌入式硬件
m0_747124538 小时前
单片机 VSCode 开发环境搭建
vscode·单片机·嵌入式硬件
嵌入式小站8 小时前
STM32 零基础可移植教程 21:1602A 并口 4 位模式,先显示 Hello
stm32·单片机·嵌入式硬件
夜月yeyue8 小时前
KCP 与 UDP 可靠传输
linux·网络·单片机·网络协议·udp·php
WIZnet9 小时前
W55RP20-EVB-MKR MicroPython 实战(14):MQTT 协议与 OneNET 平台对接
单片机·网络协议·wiznet
三佛科技-187366133979 小时前
AIP8P005B(SOP14)中微爱芯8位MCU用辉芒微FT60E112A SOP14替代
单片机·嵌入式硬件
西城微科方案开发9 小时前
LED汽车打气泵PCBA方案
单片机·嵌入式硬件
羊羊一洋9 小时前
GCC __attribute__ 完全指南:从入门到实战
c语言·stm32