news 2026/4/12 16:18:13

图解UART串口通信数据收发过程:新手入门指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
图解UART串口通信数据收发过程:新手入门指南

图解UART串行通信数据收发过程:从“Hello”到波形的完整旅程

你有没有想过,当你在单片机里写上一句UART_SendString("Hello!");的时候,这个“Hello”是怎么变成一串高低电平,在导线上跑出去,又被另一端准确无误地读出来的?

如果你刚接触嵌入式开发,面对TX、RX引脚和波特率设置感到一头雾水,那这篇文章就是为你准备的。我们将剥开UART通信的每一层外壳,用最直观的方式讲清楚:一个字节是如何被拆解成脉冲信号,又是如何跨越物理距离完成“对话”的。


为什么是UART?它凭什么这么“老”还这么“香”?

在USB飞速传输视频、Wi-Fi动辄百兆带宽的时代,为什么我们还在用看起来“古老”的UART?

答案很简单:简单即强大

想象你要给邻居递一张纸条。你可以大张旗鼓搭个对讲系统(SPI),或者搞个加密信道(I2C),但很多时候——
你只需要把门缝塞过去就行。这就是UART的角色。

它不需要共享时钟线,不依赖复杂的协议栈,MCU原生支持,连51单片机都能轻松驾驭。无论是调试打印日志、配置蓝牙模块(HC-05)、读取GPS坐标,还是通过CH340连接电脑,背后都是UART在默默工作。

更重要的是,理解UART,是你读懂所有串行通信的起点。SPI、I2C、CAN……它们都建立在类似的底层逻辑之上。


UART到底是什么?不是接口,而是“翻译官”

很多人把UART当成一种接口,其实它更像一个并串转换器

它的全称是Universal Asynchronous Receiver/Transmitter——通用异步收发器。听名字就知道,它是干两件事的:

  • 发送时:把CPU给的8位并行数据 → 拆成1根线上的串行比特流;
  • 接收时:把导线上的串行脉冲 → 合成CPU能处理的字节。

而所谓的“串口”,只是这个功能暴露出来的物理表现形式。

📌 关键点:UART是异步的。没有共同时钟线,靠双方提前约定好节奏(波特率)来同步采样。

这就像是两个人约好每秒说一个字,即使没有秒表对时,只要心跳差不多稳,就能听懂对方说话。但如果一方快了10%,几句话之后就会“你说东我听成西”。


数据是怎么发出去的?以字符 ‘A’ 为例

让我们亲手拆解一次完整的发送过程。

假设我们要发送字母'A'。它的ASCII码是0x41,二进制为01000001

但注意!UART传输有个规矩:低位先行(LSB First)

所以实际发送顺序是:

D0=1 → D1=0 → D2=0 → D3=0 → D4=0 → D5=0 → D6=1 → D7=0

但这还不是全部。UART并不是直接扔出这8个比特。它会把这些数据包装成一个“数据帧”——就像寄快递要打包一样。

一个标准UART帧长什么样?

我们以最常见的配置8N1(8数据位,无校验,1停止位)为例:

[起始位][D0][D1][D2][D3][D4][D5][D6][D7][停止位] 1bit 1 1 1 1 1 1 1 1 1bit

对应字符 ‘A’ (01000001),整个波形如下:

电平变化: 高 ↓ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ──────┬─────┬───┬───┬───┬───┬───┬───┬───┬───┬──────── │ │ 1 │ 0 │ 0 │ 0 │ 0 │ 0 │ 1 │ 0 │ idle start D0 D1 D2 D3 D4 D5 D6 D7 stop

详细步骤分解:

  1. 空闲态:线路保持高电平(逻辑1),表示“没人说话”;
  2. 起始位:发送方主动拉低电平,持续1个比特时间,相当于喊一声:“我要开始了!”;
  3. 数据位:按 LSB 顺序逐位发送,每一位维持固定时长(由波特率决定);
  4. 停止位:重新拉高电平至少1位时间,标志本次传输结束,并恢复空闲状态。

✅ 小知识:接收端正是通过检测这个“下降沿”来触发内部定时器,开始精确采样后续每一位。


波特率:你们得“同频共振”

既然没有时钟线,那怎么知道每一位该持续多久?

答案是:波特率(Baud Rate),单位是 bps(bits per second)。

比如115200 bps,意味着每秒传 115200 个比特,每个比特的时间宽度就是:

T = 1 / 115200 ≈ 8.68 μs

发送和接收双方必须使用相同的波特率,否则就会出现“错拍”。

举个例子:

  • 如果发送方按 9600 bps 发,接收方却按 115200 bps 收,
  • 那么接收方会在错误的时间点采样,结果很可能把01000001读成XXXXXXX——乱码就此产生。

⚠️ 实践提醒:常见波特率有 9600、19200、38400、57600、115200。优先选择标准值,避免因晶振分频误差导致累积失步。


硬件怎么接?别再TX接TX了!

典型的UART通信需要三根线:

[设备A] [设备B] TX ---------------> RX RX <--------------- TX GND --------------- GND

记住一句话:交叉连接,共地为王

  • TX 接 对方的 RX;
  • RX 接 对方的 TX;
  • GND 必须连在一起,提供共同参考电平。

如果没共地,就像两人打电话却不在同一个频道——你说你的,我听我的。

电平问题不可忽视

不同设备使用的电压可能不同:

类型电平范围应用场景
TTL 3.3V0V / 3.3VSTM32、ESP32等MCU
TTL 5V0V / 5V老款Arduino、51单片机
RS-232±3V ~ ±15V工业设备、老式PC串口

⚠️ 注意:TTL和RS-232不能直连!需要用 MAX232 或 SP3232 这类芯片做电平转换。

而在现代开发中,我们常用USB转串口芯片(如 CH340、CP2102、FT232)将UART信号桥接到电脑USB口,方便调试。


写代码真的只是配几个参数吗?

来看一段STM32 HAL库的经典初始化代码:

UART_HandleTypeDef huart1; void UART_Init(void) { huart1.Instance = USART1; huart1.Init.BaudRate = 115200; huart1.Init.WordLength = UART_WORDLENGTH_8B; huart1.Init.StopBits = UART_STOPBITS_1; huart1.Init.Parity = UART_PARITY_NONE; huart1.Init.Mode = UART_MODE_TX_RX; huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE; if (HAL_UART_Init(&huart1) != HAL_OK) { Error_Handler(); } }

这段代码其实在告诉硬件:“请按以下规则打包和拆包数据”:

参数设置值含义
BaudRate115200每秒传115200个比特
WordLength8B数据位长度为8位
StopBits1停止位用1位
ParityNONE不启用校验
ModeTX_RX同时启用发送和接收

这其实就是我们在前面说的8N1 配置

一旦配置完成,你就可以用一行代码发送字符串:

HAL_UART_Transmit(&huart1, (uint8_t*)"Hello UART!\r\n", 13, HAL_MAX_DELAY);

但要注意:这种轮询方式会阻塞CPU。实际项目中建议开启中断接收或使用DMA,让数据自动搬移,释放主程序资源。


校验位有用吗?什么时候该用?

虽然现在通信环境比以前好很多,但在工业现场或长距离传输中,干扰依然存在。

UART提供了简单的错误检测机制——奇偶校验位

比如启用“偶校验”(Even Parity):
- 数据位中有奇数个1 → 补1使总数为偶;
- 数据位中有偶数个1 → 补0保持为偶。

接收方收到后重新统计1的个数,如果不符,说明传输出错了。

不过要清醒认识到:奇偶校验只能发现单比特错误,无法纠正。对于高可靠性场景,更好的做法是在应用层加CRC校验,甚至采用Modbus RTU这类成熟协议。

但对于调试信息输出这类“丢了也不致命”的场景,8N1 + 高质量线路已经足够可靠。


初学者常踩的坑,你知道几个?

问题现象可能原因解决方案
收到一堆乱码波特率不一致双方确认是否都是115200?
完全没反应TX-RX接反 or 没共地查线!查线!查线!
中文显示异常数据位不足 or 编码不对确保8位数据,且发送UTF-8需多字节处理
快速发送丢数据接收缓冲区溢出改用中断/DMA接收,及时清空DR寄存器
波特率总是不准使用RC振荡器作时钟源改用外部晶振提高精度

💡 调试建议:
- 入门阶段用 XCOM、SSCOM 这类串口助手观察收发;
- 上逻辑分析仪抓波形,看起始位、数据位是否对齐;
- 多设备系统注意电平匹配和负载能力。


工程设计中的深层考量

别以为UART就是“随便接两根线”。真正的产品级设计要考虑更多:

✅ 波特率容差控制

一般要求两端波特率偏差小于 ±2%。若MCU使用内部RC振荡器(±5%误差),高速下容易失步。推荐使用外部晶振或选用自带校准功能的芯片。

✅ 通信距离限制

  • TTL电平:≤1米;
  • RS-232:可达15米;
  • RS-485(差分):可达1200米。

远距离务必选差分信号,抗干扰能力强得多。

✅ 流控机制要不要上?

对于高速大数据流(如图像传输),可启用硬件流控 RTS/CTS,防止接收端来不及处理导致丢包。

✅ 电源隔离保安全

工业环境中强烈建议使用光耦或数字隔离器(如 ADuM1201),实现电气隔离,避免地环路干扰或高压损坏主控。

✅ 协议封装提可靠性

可在UART基础上自定义协议帧,例如:

[Start][Addr][Len][Data...][CRC][End]

加入地址字段支持多机通信,CRC提升检错能力,这才是工程级的做法。


总结:UART教会我们的不只是通信

掌握UART,不只是学会了一个外设配置。

它教会我们:

  • 如何在没有完美同步的情况下达成协作;
  • 如何通过简单的规则构建可靠的通信;
  • 如何从物理层一步步抽象到应用层。

下次当你按下复位键,看到终端弹出 “System Ready” 的那一刻,你会明白:那一串字符的背后,是一次精准的起始位触发、八次电平翻转、一次成功的停止位确认。

而这,正是嵌入式世界的浪漫所在。

如果你正在学习单片机、FPGA或物联网开发,不妨从点亮LED之后的第一站,就加上这一课:亲手用UART打出属于你的第一个“Hello World”

欢迎在评论区分享你的第一次串口调试经历,或者遇到过的奇葩通信问题。我们一起拆解,一起成长。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/8 6:56:43

PETRV2-BEV模型训练:如何提升小目标检测性能

PETRV2-BEV模型训练&#xff1a;如何提升小目标检测性能 在自动驾驶感知系统中&#xff0c;基于视觉的3D目标检测技术近年来取得了显著进展。PETR系列模型通过将相机视角&#xff08;perspective view&#xff09;特征与空间位置编码相结合&#xff0c;在BEV&#xff08;Birds…

作者头像 李华
网站建设 2026/4/10 0:06:36

PyTorch-2.x-Universal-Dev-v1.0保姆级教程:模型训练中断恢复机制

PyTorch-2.x-Universal-Dev-v1.0保姆级教程&#xff1a;模型训练中断恢复机制 1. 引言 在深度学习模型的训练过程中&#xff0c;长时间运行的任务可能因硬件故障、断电、系统崩溃或资源调度等原因意外中断。这种中断不仅浪费计算资源&#xff0c;还可能导致前期训练成果付诸东…

作者头像 李华
网站建设 2026/4/4 22:12:21

NotaGen环境部署:GPU配置与性能优化完整方案

NotaGen环境部署&#xff1a;GPU配置与性能优化完整方案 1. 引言 1.1 项目背景与技术定位 随着生成式人工智能在艺术创作领域的深入发展&#xff0c;基于大语言模型&#xff08;LLM&#xff09;范式的音乐生成技术正逐步走向成熟。NotaGen 是一个专注于古典符号化音乐生成的…

作者头像 李华
网站建设 2026/4/1 18:37:20

解析ModbusRTU在电力监控系统中的稳定性优化

深入实战&#xff1a;如何让ModbusRTU在电力监控系统中“稳如磐石”&#xff1f;你有没有遇到过这样的场景&#xff1f;凌晨两点&#xff0c;配电房的报警灯突然闪烁——数十台智能电表集体失联。运维人员紧急排查&#xff0c;却发现设备供电正常、接线无松动&#xff0c;最后定…

作者头像 李华
网站建设 2026/4/12 0:19:44

VHDL状态机在Xilinx Vivado中的实现详解

用VHDL写状态机&#xff0c;如何在Xilinx Vivado里跑出最优性能&#xff1f;你有没有遇到过这种情况&#xff1a;明明逻辑很简单的一个控制流程&#xff0c;仿真也过了&#xff0c;结果综合出来时序不收敛、资源还爆了&#xff1f;翻来覆去查代码&#xff0c;最后发现——问题出…

作者头像 李华
网站建设 2026/4/8 4:47:03

企业AI测试新方式:快速搭建临时评估环境

企业AI测试新方式&#xff1a;快速搭建临时评估环境 在数字化转型的浪潮中&#xff0c;越来越多的企业开始将语音识别、语音活动检测&#xff08;VAD&#xff09;等AI能力融入客服系统、会议记录、智能助手等核心业务场景。然而&#xff0c;IT部门在推进这类技术落地时常常面临…

作者头像 李华