当前位置: 首页 > news >正文

UART 串口协议详解与 STM32 实战实现

在嵌入式开发领域,UART(通用串行异步收发器)是设备间数据交互的核心协议之一,尤其在 STM32 开发中,其通过 USART 外设(通用同步异步收发器)实现异步通信,广泛应用于调试日志输出、传感器数据接收、模块指令交互等场景。本文整合 UART 核心协议概念与 STM32 实战代码,从原理到落地,系统梳理关键知识点,兼顾复习与工程应用。

一、UART 核心概念:从定义到特性

UART 的名称蕴含 “通用、串行、异步、收发器” 四大核心属性,也是理解其工作逻辑的基础,同时需结合 STM32 的硬件实现关联认知。

1. 核心属性解析

  • 通用:不依赖特定场景,STM32 中通过 USART1/2/3 等多外设支持,覆盖工控、电力、消费电子等领域(如 STM32F103 的 USART1 可用于调试,USART2 连接蓝牙模块)。
  • 串行:处理器与外设仅通过 1 根数据线传输数据,按 “低位优先” 逐 bit 发送;对比并行通信(多根数据线,一次传多字节),STM32 中 UART 因抗干扰强、传输距离远(优于并行),更适合板间短距通信。
特性串行通信(UART)并行通信
数据线数量1 根8/16/32 根
速度较慢(如 115200bps)较快
抗干扰强(单线路串扰少)弱(多线路干扰多)
传输距离较远较近
  • 异步:无需时钟线同步,依赖 “波特率” 和 “数据帧协议” 实现双方对齐(STM32 中通过配置 USART 参数约定,区别于 SPI 的同步时钟模式)。
  • 收发器:硬件单元负责数据发送 / 接收,角色随流向变化(STM32 作为 CPU 时,给外设发数据则 STM32 是发送器,接收外设数据则是接收器)。

2. 电气特性与 STM32 硬件

  • 电平类型:STM32 引脚输出 TTL 电平(高≈3.3V,低≈0V),外部串口线常用 EIA 电平(高 - 3~-15V,低 3~15V),需通过电平转换芯片(如 MAX232)兼容。
  • 硬件连接:STM32 UART 通信至少需 3 根线 ——TX(发送,如 USART1 的 PA9)、RX(接收,如 USART1 的 PA10)、GND(共地,保证电平参考一致),且需 “交叉连接”(STM32 的 TX 接外设的 RX,STM32 的 RX 接外设的 TX)。
  • 工作方式:STM32 UART 默认支持全双工(数据可同时双向传输,如调试时 PC 发指令、STM32 回传数据),也可配置为半双工或单工(极少用)。

二、UART 协议核心:数据帧与关键参数(附 STM32 配置映射)

UART 通过 “数据帧” 规范数据传输格式,STM32 的 USART 外设需配置与帧结构匹配的参数,双方参数一致才能正常通信。

1. 数据帧结构

标准数据帧格式为:{空闲位 + 起始位 + 数据位 +(校验位)+ 停止位},各字段定义与 STM32 配置对应关系如下:

字段位数电平 / 作用STM32 配置参数(USART_InitTypeDef)
空闲位1bit高电平(无数据时的默认状态)硬件自动生成,无需配置
起始位1bit低电平(标志传输开始)硬件自动生成,无需配置
数据位5/6/7/8bit高低电平表示有效数据USART_WordLength_8b(常用,对应 1 字节数据)
校验位0/1bit检测传输错误USART_Parity_No(无校验)/Even(偶)/Odd(奇)
停止位1/2bit高电平(标志传输结束)USART_StopBits_1(常用)

2. 关键协议参数

  • 波特率:每秒传输的 bit 数(单位 bps),STM32 常用 115200bps(调试首选,速度快)和 9600bps(稳定性高,适合弱信号场景),配置通过USART_InitStruct.USART_BaudRate设置,由库函数自动计算 BRR 寄存器值(基于 STM32 的 APB 时钟,如 F103 的 APB2 时钟为 72MHz)。
  • 校验位逻辑:STM32 硬件自动计算校验位,无需软件干预。例如传输0x95(二进制10010101,含 4 个 1):
    • 奇校验:硬件自动添加 1bit 高电平(4+1=5,奇数);
    • 偶校验:硬件自动添加 1bit 低电平(4+0=4,偶数)。

三、STM32 UART 实战代码:从初始化到收发

以 STM32F103 固件库为例,实现 USART1 的初始化、查询式收发、中断式接收,覆盖主流应用场景。

1. 基础初始化(GPIO+USART)

需先使能时钟,再配置 GPIO 引脚模式和 USART 参数:

#include "stm32f10x.h"// USART1初始化:115200bps,8位数据,无校验,1位停止位,全双工
void USART1_Init(void) {// 1. 使能时钟(GPIOA和USART1均挂载APB2总线)RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE);// 2. 配置GPIO引脚GPIO_InitTypeDef GPIO_InitStruct;// TX引脚:PA9(复用推挽输出,需将USART1_TX功能映射到引脚)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);// 3. 配置USART参数USART_InitTypeDef USART_InitStruct;USART_InitStruct.USART_BaudRate = 115200; // 波特率115200bpsUSART_InitStruct.USART_WordLength = USART_WordLength_8b; // 8位数据位USART_InitStruct.USART_StopBits = USART_StopBits_1; // 1位停止位USART_InitStruct.USART_Parity = USART_Parity_No; // 无校验USART_InitStruct.USART_Mode = USART_Mode_Tx | USART_Mode_Rx; // 收发双模式USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None; // 无硬件流控USART_Init(USART1, &USART_InitStruct);// 4. 使能USART1外设USART_Cmd(USART1, ENABLE);
}

2. 查询式收发(适合简单场景)

通过查询 USART 状态寄存器(SR)的TXE(发送空)和RXNE(接收非空)标志位,实现阻塞式收发:

// 发送1字节数据(查询TXE标志,确保发送寄存器空)
void USART1_SendByte(uint8_t data) {while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET); // 等待发送空USART_SendData(USART1, data); // 写入数据寄存器,硬件自动发送
}// 发送字符串(逐字节调用SendByte)
void USART1_SendString(char* str) {while (*str != '\0') {USART1_SendByte(*(str++));}
}// 接收1字节数据(查询RXNE标志,阻塞等待数据)
uint8_t USART1_ReceiveByte(void) {while (USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == RESET); // 等待接收非空return USART_ReceiveData(USART1); // 读取数据寄存器
}

3. 中断式接收(适合非阻塞 / 大数据场景)

查询式接收会阻塞主程序,中断式接收可在数据到来时触发中断,提升程序效率,需配置 NVIC(嵌套向量中断控制器):

#include "misc.h" // 包含NVIC相关定义uint8_t g_rx_data; // 全局变量存储接收数据// NVIC初始化:配置USART1中断优先级
void USART1_NVIC_Init(void) {NVIC_InitTypeDef NVIC_InitStruct;NVIC_InitStruct.NVIC_IRQChannel = USART1_IRQn; // USART1中断通道NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1; // 抢占优先级(需根据系统调整)NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1; // 子优先级NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE; // 使能中断通道NVIC_Init(&NVIC_InitStruct);// 使能USART1接收中断(RXNE触发)USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
}// USART1中断服务函数:处理接收中断
void USART1_IRQHandler(void) {// 判断是否为接收中断(RXNE标志置位)if (USART_GetITStatus(USART1, USART_IT_RXNE) == SET) {g_rx_data = USART_ReceiveData(USART1); // 读取接收数据USART_ClearITPendingBit(USART1, USART_IT_RXNE); // 清除中断标志(可选,读取DR后自动清除)}
}

4. 主函数调用示例

int main(void) {USART1_Init(); // 初始化USART1USART1_NVIC_Init(); // 初始化中断(若用中断接收)USART1_SendString("STM32 UART Test Start!\r\n"); // 发送测试字符串while (1) {// 方式1:查询式接收并回发// uint8_t recv = USART1_ReceiveByte();// USART1_SendByte(recv);// 方式2:中断接收后处理(此处仅示例,可在中断中直接处理)// if (g_rx_data != 0) { ... }}
}

四、调试技巧与常见问题解决

  1. 通信失败:优先检查双方波特率、数据位 / 校验位 / 停止位是否一致(STM32 配置需与外设参数完全匹配);
  2. 接收乱码:波特率计算错误(确认 STM32 的 APB 时钟频率,如 F103 需确保 APB2 为 72MHz,库函数才会正确计算 BRR 寄存器);
  3. 引脚无输出:GPIO 模式配置错误(TX 需为GPIO_Mode_AF_PP,而非普通推挽输出,否则无法映射 USART 功能);
  4. 中断不触发:NVIC 优先级配置错误(抢占优先级需低于系统其他高优先级中断)或未使能 USART 中断(USART_ITConfig未调用);
  5. 数据丢失:查询式接收阻塞主程序导致漏接,建议改用中断式或 DMA 方式(STM32 USART 支持 DMA,适合大数据量传输)。

五、相关结构体和库函数详解

typedef struct{uint32_t USART_BaudRate; //波特率,例如:115200 uint16_t USART_WordLength; //字长uint16_t USART_StopBits; //停止位uint16_t USART_Parity; //校验位uint16_t USART_Mode; //USART模式uint16_t USART_HardwareFlowControl; //硬件流控制
} USART_InitTypeDef;USART_BaudRate: 波特率,如 9600、115200	USART_WordLength:	数据位长度:USART_WordLength_8b(8位)、USART_WordLength_9b(9位)	USART_StopBits:		停止位:USART_StopBits_1(1位)、USART_StopBits_2(2位)	USART_Parity:校验:USART_Parity_No(无)、USART_Parity_Even(偶)USART_Parity_Odd(奇)USART_Mode:模式:USART_Mode_Rx(接收)、USART_Mode_Tx(发送),可组合USART_Mode_Rx|USART_Mode_TxUSART_HardwareFlowControl:硬件流控:None、RTS、CTS、RTS_CTS	USART_HardwareFlowControl_None硬件流控制常用的有RTS/CTSQ流控制和DTR/DSR(数据终端就绪/数据设置就绪)流控制。RTS(RequireToSend,发送请求)为输出信号,用于指示本设备准备好可接收数据,低电平有效,低电平说明本设备可以接收数据。CTS(ClearToSend,发送允许)为输入信号,用于判断是否可以向对方发送数据,低电平有效,低电平说明本设备可以向对方发送数据。
-----------------------------------------------------------------------------------------
USART 寄存器结构,USART_TypeDeff,在文件“stm32f10x_map.h”中定义如下: 
typedef struct { vu16 SR; u16 RESERVED1;vu16 DR; u16 RESERVED2;vu16 BRR; u16 RESERVED3; vu16 CR1; u16 RESERVED4; vu16 CR2; u16 RESERVED5;vu16 CR3;u16 RESERVED6; vu16 GTPR;u16 RESERVED7; 
} USART_TypeDef; 
寄存器 	描述 
SR 		USART 状态寄存器 
DR 		USART 数据寄存器 
BRR 	USART 波特率寄存器 
CR1 	USART 控制寄存器 1 
CR2 	USART 控制寄存器 2 
CR3 	USART 控制寄存器 3 
GTPR 	USART 保护时间和预分频寄存器 
----------------------------------------------------------------------------------------
void USART_Init(USART_TypeDef* USARTx, USART_InitTypeDef* USART_InitStruct)功能: 根据 USART_InitStruct 中指定的参数初始化外设 USARTx 寄存器 参数 1 USARTx:x 可以是 1,2 或者 3,来选择 USART 外设 参数 2 USART_InitStruct:指向结构 USART_InitTypeDef 的指针,包含了外设 USART 的配置信息。
----------------------------------------------------------------------------------------
void USART_Cmd(USART_TypeDef* USARTx, FunctionalState NewState) 功能 使能或者失能 USART 外设 参数 1 USARTx:x 可以是 1,2 或者 3,来选择 USART 外设 参数 2 NewState: 外设 USARTx 的新状态  这个参数可以取:ENABLE 或者 DISABLE 
----------------------------------------------------------------------------------------
void USART_SendData(USART_TypeDef* USARTx, u8 Data) 功能 通过外设 USARTx 发送单个数据 参数 1 USARTx:x 可以是 1,2 或者 3,来选择 USART 外设 参数 2 Data: 待发送的数据 
----------------------------------------------------------------------------------------
u8 USART_ReceiveData(USART_TypeDef* USARTx) 功能 返回 USARTx 最近接收到的数据 参数 USARTx:x 可以是 1,2 或者 3,来选择 USART 外设  返回值 接收到的字 
----------------------------------------------------------------------------------------
FlagStatus USART_GetFlagStatus(USART_TypeDef* USARTx, u16 USART_FLAG) 功能 检查指定的 USART 标志位设置与否 参数 1 USARTx:x 可以是 1,2 或者 3,来选择 USART 外设 参数 2 USART_FLAG:待检查的 USART 标志位 USART_FLAG :USART_FLAG_CTS CTS 标志位 USART_FLAG_LBD LIN 中断检测标志位 USART_FLAG_TXE 发送数据寄存器空标志位 √ USART_FLAG_TC 发送完成标志位 √ USART_FLAG_RXNE 接收数据寄存器非空标志位 USART_FLAG_IDLE 空闲总线标志位 检测一包数据接收完成USART_FLAG_ORE 溢出错误标志位 USART_FLAG_NE 噪声错误标志位 USART_FLAG_FE 帧错误标志位 USART_FLAG_PE 奇偶错误标志位 返回值 USART_FLAG 的新状态(SET 或者 RESET)------------------------------------------USART_IT_IDLE中断,是串口收到一帧数据后,发生的中断。也可以叫做一包数据USART_IT_IDLE和USART_IT_RXNE区别当接收到1个字节,会产生USART_IT_RXNE中断当接收到一帧数据,就会产生USART_IT_IDLE中断清中断方法USART_IT_RXNE USART_ClearITPendingBit(USART1, USART_IT_RXNE); 或者USART1->DRUSART_IT_IDLE 先读SR寄存器 USART1->SR ,再读DR寄存器USART1->DR。
----------------------------------------------------------------------------------------
void USART_ITConfig(USART_TypeDef* USARTx, u16 USART_IT, FunctionalState NewState) 功能 使能或者失能指定的 USART 中断 参数 1 USARTx:x 可以是 1,2 或者 3,来选择 USART 外设 参数 2 USART_IT:待使能或者失能的 USART 中断源 参数 3 NewState:USARTx 中断的新状态 可以取:ENABLE 或者 DISABLE USART_IT  USART_IT_PE 	奇偶错误中断 USART_IT_TXE 	发送中断 发送寄存器 DR 为空USART_IT_TC 	传输完成中断 数据帧(含停止位)发送完USART_IT_RXNE 	接收中断 当DR寄存器从外设接收了一个字符,触发一次RXNE中断USART_IT_IDLE 	空闲总线中断 检测一包数据接收完成USART_IT_LBD 	LIN 中断检测中断 LIN 协议相关(极少用)USART_IT_CTS 	CTS 中断 硬件流控制信号变化USART_IT_ERR 	错误中断帧错误 / 溢出 / 噪声等
----------------------------------------------------------------------------------------
ITStatus USART_GetITStatus(USART_TypeDef* USARTx, u16 USART_IT) 功能 检查指定的 USART 中断发生与否 参数 1 USARTx:x 可以是 1,2 或者 3,来选择 USART 外设 参数 2 USART_IT:待检查的 USART 中断源 返回值 USART_IT 的新状态 (SET 或者 RESET)
----------------------------------------------------------------------------------------
void USART_ClearITPendingBit(USART_TypeDef* USARTx, u16 USART_IT)功能 清除 USARTx 的中断待处理位 参数 1 USARTx:x 可以是 1,2 或者 3,来选择 USART 外设 参数 2 USART_IT:待检查的 USART 中断源 
----------------------------------------------------------------------------------------

时序图示例:

六、总结

UART 协议与 STM32 的结合,核心是 “协议参数一致性” 与 “硬件配置匹配”:

  1. 理解 UART 的串行异步特性、数据帧结构,是 STM32 配置的基础;
  2. STM32 代码实现需围绕 “时钟使能→GPIO 配置→USART 参数设置→收发逻辑(查询 / 中断)” 展开;
  3. 调试时需紧扣 “参数匹配” 和 “硬件连接”,优先排查波特率、引脚模式、中断配置等关键节点。

作者​​:趙小贞

​​声明​​:本文基于个人学习经验总结,如有错误欢迎指正!

​​版权​​:转载请注明出处,禁止商业用途。

AI声明:本文代码注释借助AI详细补全,整体框架和内容优化借助CSDN文章AI助手润色!

               整体内容原创,用于复习总结以及分享经验,欢迎大家指点!

http://www.dtcms.com/a/523652.html

相关文章:

  • 【CMakeLists.txt】QtSvg 头文件包含配置详解
  • 调用Zlib库接口压缩、解压缩(C++源码)
  • flume的log4j日志无输出排查
  • 一个域名可以做两个网站吗天津人事考试网
  • whisper 模型处理音频办法与启示
  • linux rt任务调度器
  • 金融智能体技术解读:十大应用场景与AI Agent架构设计思路
  • 永磁同步电机(PMSM)在MATLAB中的高级调参策略与实践
  • 李宏毅机器学习笔记31
  • 【timecode】两种不同的时间码格式:“`00:00:00`” 和 “`00:00:00:00`”
  • 个人网站 不用备案深圳建设网站和公众号
  • npm 安装 canvas 报错 node-gyp ERR! 的解决方法(Windows 系统)
  • 编辑器汇总:Neovim、Helix、Vim、LazyVim、Kakoune、nb、Lite XL
  • 如何开发一个自己的包并发布到npm
  • 商城型网站的概念企业信息平台登录
  • Docker MySQL 单主从及分表函数
  • UE5 蓝图-11:本汽车蓝图的事件图表,汽车拆分事件,染色事件(绿蓝黄青)。
  • CDC 实时数据同步与小时级统计方案(Flink 1.13.5 + MySQL 8.0)
  • Redis之String 类型入门与实战,由基础语法快速掌握再到缓存加速/验证码防刷/计数统计场景应用
  • 【Qt | .pro文件】Qt项目文件详解:pro文件与pri文件
  • SpringAI2-Spring AI-聊天模型:ChatClient,流式编程,ChatModel
  • [MySQL] 事务和视图
  • 建设网站的特色wordpress域名网站搬家
  • 记录画图笔记
  • 【江苏政务服务网-注册_登录安全分析报告】
  • redisson介绍
  • 20251020二分总结
  • Android 基于清单文件mate-data数据共享
  • Android中Window和LayoutParams的常用属性及常用方法介绍
  • MySQL的安装与卸载