
串口调试是个老话题但“为什么发了一堆数据对端收到的却是残缺的”“明明波特率没问题为什么偶发丢字节”“FIFO到底要不要开开多大合适”这些问题几乎每个做过单片机、工控机、上位机通信的工程师都踩过。这次我们直接聊串口 FIFO 缓存把它的原理、配置、软件实现和丢数据排查一次讲透。先给结论串口丢数据绝大多数不是波特率不对而是 CPU 没来得及把数据从串口硬件里取走导致后续数据把前一个数据覆盖了。FIFO 的本质是给硬件加一排“缓冲区”让 CPU 可以晚一点去取同时降低中断频率。但 FIFO 不是万能药开太大或太小都会出问题真正稳定的接收方案通常是“硬件 FIFO 软件环形缓冲区 中断/DMA”三层配合。这篇文章会覆盖以下内容串口硬件 FIFO 的工作原理与触发阈值、上位机 USB 转串口芯片的 FIFO 配置、MCU 侧软件环形缓冲区软件 FIFO的完整实现、中断 DMA 的接收方案对比、以及一套从“现象”到“根因”的丢数据排查流程。如果你手上正好有项目在调串口或者正准备把裸机接收改成 DMA 环形缓冲区这篇文章可以直接当参考。1. 串口丢数据的真实场景与根本原因1.1 最常见的四种丢数据场景先还原几个真实场景看你能不能对号入座。场景一高波特率批量传输。设备以 921600 波特率向上位机连续发送数据每帧 512 字节上位机用 VB、C# 或 Python 的串口控件接收结果发现数据零星丢失尤其是程序界面卡顿或者主线程在做其它操作时丢掉的数据更多。场景二低波特率但数据密集。115200 波特率看似不快但如果你在接收中断回调里做了大量处理比如解析协议、写 Flash、打印日志、甚至调用了 sleep中断被长时间占用波特率再低也能丢数据。因为串口硬件寄存器一次只能存一个字节或一小段数据你处理慢了后面的数据就把它覆盖了。场景三多任务系统抢占。RTOS 或 Linux 环境下任务调度导致串口接收任务不能及时被调度如果驱动层没有足够大的缓冲数据到应用层时已经丢了一部分。场景四USB 转串口加主机端缓冲。CH340、FTDI、CP2102 这类芯片本身就带 USB 端缓冲但 Windows/Linux 驱动层、应用层串口 API 也各自有缓冲区。某个环节缓冲太小或者应用层不及时读取就会出现设备端看起来发送了数据、上位机却少收的情况。1.2 丢数据的直接原因把场景抽象一下丢数据的直接原因其实就是以下几条接收覆盖Overrun。UART 硬件接收寄存器只有一个或几个字节深度单片机或芯片还没有取走前一个字节下一个字节已经到达新数据覆盖旧数据。FIFO 溢出Overflow。即使硬件有 16 字节或 64 字节 FIFO如果 CPU 长时间不来读FIFO 满了之后后续进来的数据照样无处存放直接丢弃。缓冲未及时取走Software Buffer Full。应用层环形缓冲区已经满了但主循环还没空处理驱动层无法再写入新的数据只能丢弃。时钟误差与数据位失真。收发双方波特率存在偏差尤其在 1 Mbps 以上时一帧 10 bit 的数据误差逐渐累积采样点偏离数据位错误。这种情况更常见于 USB 转串口芯片与目标板之间。流控缺失。硬件流控 RTS/CTS 没有接或没有配置接收端处理不过来时无法通知对端暂停对端继续发送数据自然丢失。1.3 丢数据前的典型症状丢数据并不是毫无征兆通常可以通过以下现象提前判断数据每隔一段时间就缺一段尤其在对方发送大文件或连续流数据时。数据偶尔出现“半个帧”或“错位帧”原因可能是接收缓冲区里残留了不完整的数据。协议层校验失败率上升CRC 或校验和错误持续出现。接收线程长时间得不到调度时丢失概率明显增加。如果你遇到上述情况先把“是不是波特率不对”放在一边优先检查接收链路中每一级缓冲区是否足够。2. 串口 FIFO 是什么硬件 FIFO 与软件 FIFO2.1 硬件 FIFO串口芯片里的缓冲队列硬件 FIFO 是串口控制器内部的一小块 RAM以队列方式工作数据按先进先出顺序存放。经典 PC 串口时代NS16550 UART 引入了 16 字节收发 FIFO这是串口硬件缓冲的重要里程碑。后来的 MCU 串口比如 STM32、NXP S32K、GD32、ESP32 等在 USART 硬件内部大多也带 16 字节或更深的收发 FIFO具体容量以芯片参考手册为准。硬件 FIFO 的工作逻辑可以这样理解没有 FIFO 时每收到一个字节硬件就向 CPU 发一次中断CPU 响应中断、读走数据有 FIFO 后硬件会把接收到的多个字节先放进 FIFO当 FIFO 中的数据量达到设定的触发阈值时才发一次中断CPU 一次性读走一批数据。所以硬件 FIFO 的核心价值有两个降低中断频率给 CPU 留出更多时间处理其它任务。在 CPU 响应延迟期间暂存数据减少因 ISR 响应不及时导致的单个字节丢失。2.2 软件 FIFO用户区的环形缓冲区硬件 FIFO 的容量终究有限16 字节或 64 字节对于连续大数据流来说远远不够。软件 FIFO 是在内存中开辟的一块环形缓冲区也叫 Ring Buffer通过“写入索引 读取索引”来模拟先进先出。它的作用是把“接收动作”和“数据处理动作”解耦。中断服务程序只负责把数据从硬件 FIFO 搬进软件 FIFO主循环或应用线程再择机从软件 FIFO 取走数据做协议解析。这样即使应用层忙于界面刷新、文件写入、网络转发数据也能暂存在软件 FIFO 里不会马上丢。2.3 为什么 FIFO 能减少丢包用一句话说明丢包的本质是“产出速度大于消费速度”而 FIFO 是在生产者和消费者之间加了一个蓄水池当消费速度暂时跟不上时先把多余的数据放到缓冲区。但这要求缓冲区容量必须大于“生产者突发写入量”与“消费者暂未消费量”的差值。如果缓冲区容量设置得太小消费者还没处理完缓冲区就满了后面的数据还是会被丢弃。这正是很多工程师开了 FIFO 后依然丢数据的原因不是 FIFO 没用而是 FIFO 深度不够或触发策略没调好。3. 硬件 FIFO 怎么配置从外置芯片到 MCU3.1 上位机侧 USB 转串口芯片的 FIFO 配置CH340、FTDI、CP2102 这类 USB 转串口芯片不一定直接暴露硬件 FIFO 深度但驱动往往提供缓冲区大小或缓冲策略的选项。以 FTDI 驱动为例Windows 设备管理器中打开对应 COM 口的属性高级设置里通常可以看到“接收缓冲区”“传输缓冲区”大小的选项可调整范围常见为 1 KB 到 32 KB。这个缓冲区的本质是驱动层软件缓冲不完全是芯片硬件 FIFO但它直接影响 USB 接收数据的稳定性和延迟。CH340 驱动在 Windows 下的界面相对简单但部分新版驱动也提供了缓冲区调整选项。不同驱动版本界面差异较大建议检查并加大接收缓冲区尤其在上位机程序里使用异步读取或事件驱动读取时。3.2 MCU 侧串口 FIFO 与中断阈值以 STM32 系列为例早期型号如 F1 系列的 USART 没有显式的 FIFO 概念数据寄存器一次只能放一个字节因此接收一般靠“单字节中断 软件缓冲”。而 STM32H7、G0、L4 等较新系列的部分串口实例内部集成了收发 FIFO可以通过寄存器配置 FIFO 使能、触发阈值、DMA 模式等。如果 MCU 硬件不带 FIFO也不必担心我们完全可以用“中断 软件环形缓冲区”实现等效甚至更灵活的缓冲方案。触发阈值的设置是硬件 FIFO 调优的关键。阈值太低比如设成 1 字节那 FIFO 和普通无 FIFO 模式几乎没区别中断频率依然很高阈值太高比如把 16 字节 FIFO 阈值设成 14 字节虽然中断频率低了但如果 CPU 响应稍慢FIFO 连续溢出数据丢失的风险反而加大。因此阈值一般选中等偏低的水平比如一半深度。3.3 触发阈值与 CPU 负载的取舍一个典型取舍场景阈值 4/16中断频率较高但几乎不会出现过冲CPU 负载偏高。阈值 8/16中断频率适中适合大多数中低波特率应用。阈值 12/16 或 14/16中断频率低但对 CPU 响应时间要求高适合波特率低、数据量小的场景。如果你用的是 DMA 接收中断阈值对 CPU 负载的影响就会降低很多因为数据由 DMA 搬运CPU 只需在空闲中断或半传输中断时处理。这也是“DMA FIFO”组合方案受欢迎的原因。4. 软件 FIFO 实战写一个环形缓冲区4.1 数据结构设计环形缓冲区实现方案有很多最简单的做法是用数组、读索引、写索引、剩余计数。下面给出一个适用于 STM32 等单片机的 C 语言实现模板。这个模板适用于裸机环境和 RTOS关键代码路径要关中断保护防止读写索引竞争。#define RX_RING_SIZE 512 // 必须是2的幂方便掩码取模 typedef struct { uint8_t buffer[RX_RING_SIZE]; volatile uint16_t head; // 写索引ISR里更新 volatile uint16_t tail; // 读索引主循环里更新 volatile uint16_t count; // 当前缓冲区内数据字节数 } ring_buffer_t; static ring_buffer_t rx_ring;注意这里RX_RING_SIZE是 512正好是 2 的幂。这样可以用 (RX_RING_SIZE - 1)代替% RX_RING_SIZE效率会高一些。4.2 初始化、写入与读取代码void ring_init(ring_buffer_t *ring) { ring-head 0; ring-tail 0; ring-count 0; } int ring_write(ring_buffer_t *ring, uint8_t data) { if (ring-count RX_RING_SIZE) { return -1; // 缓冲区已满 } ring-buffer[ring-head] data; ring-head (ring-head 1) (RX_RING_SIZE - 1); ring-count; return 0; } int ring_read(ring_buffer_t *ring, uint8_t *data) { if (ring-count 0) { return -1; // 缓冲区为空 } *data ring-buffer[ring-tail]; ring-tail (ring-tail 1) (RX_RING_SIZE - 1); ring-count--; return 0; }以上写法在单生产者单消费者场景下只要写入全部在中断里、读取全部在主循环/线程里可以做到无锁运行。如果要在多线程环境使用需要加临界区保护。4.3 中断处理函数里怎么用以 USART1 接收中断为例void USART1_IRQHandler(void) { // 检查接收数据寄存器非空标志 if (USART1-ISR USART_ISR_RXNE) { uint8_t data (uint8_t)(USART1-RDR 0xFF); // 直接写入软件环形缓冲区 if (ring_write(rx_ring, data) ! 0) { // 软件缓冲区满了做溢出计数 overflow_count; } } }这段代码只做两件事从硬件里读出数据写入软件 FIFO。不要在中断里做协议解析、日志输出、Flash 写入。中断里处理得越快丢数据的概率越低。如果 MCU 的串口硬件自带 FIFO 且触发了多字节中断可以通过循环把 FIFO 里的所有数据全部搬到软件 FIFOvoid USART1_IRQHandler(void) { while ((USART1-ISR USART_ISR_RXNE) (rx_ring.count RX_RING_SIZE)) { uint8_t data (uint8_t)(USART1-RDR 0xFF); ring_write(rx_ring, data); } // 如果退出循环是因为缓冲满了记录溢出 if (USART1-ISR USART_ISR_RXNE) { overflow_count; } }4.4 怎么知道一次写入多少个数据热搜词里提到“STM32 单片机 FIFO 怎么知道一次写入多少个数据”这个问题的答案分两层第一层是串口协议约定。比如规定一帧格式为“帧头 长度字段 数据 校验”。接收端并不依赖 FIFO 自动告诉你数据量而是根据协议里的长度字段从软件 FIFO 中读取指定数量的字节组成完整帧。第二层是动态查询。在中断里每次成功写入一个字节count加 1应用层读取时count减 1。因此应用层随时可以通过读取rx_ring.count得知当前软件 FIFO 中积压了多少数据而不是“一次写入多少个”。如果使用 DMA 接收还可以配置 DMA 计数器通过__HAL_DMA_GET_COUNTER或类似寄存器计算出本次接收的数据长度。5. 中断 DMA FIFO 的组合方案5.1 简单中断接收的优缺点简单中断接收也就是每收一个字节进入一次中断是入门与中小数据量项目最常用的方案。优点实现简单逻辑清晰。不需要额外外设和内存。对波特率和数据量不大场景足够用。缺点高波特率大数据量时CPU 中断频繁容易丢数据。中断函数如果写得不够精简会直接影响系统实时性。以 115200 波特率为例约每 86.8 微秒收一个字节这期间如果中断被更高优先级任务抢占超过几十微秒就可能出现接收覆盖。因此在 921600 或更高波特率环境下单纯靠中断接收确实吃力。5.2 DMA 空闲中断接收不定长数据DMA 是串口接收防丢包更有效的方案。它的思路是DMA 控制器把 UART 接收寄存器的数据自动搬到内存缓冲区整个过程不需要 CPU 逐字节参与。CPU 只在缓冲区半满、满或串口空闲时被通知一次。接收不定长数据时常见的组合是DMA 接收开启到一块固定大小的缓冲区。打开串口空闲中断IDLE LINE Interrupt或基于空号超时检测。当串口出现一段时间空闲时触发空闲中断CPU 在中断里根据 DMA 剩余计数器算出本次实际收到的数据长度把这段数据搬走或交给协议层。5.3 DMA 接收的环形缓冲实现为了进一步降低中断次数可以使用 DMA 的循环模式让 DMA 自动把数据循环写入一块缓冲区再用半传输中断和传输完成中断通知应用层处理。#define DMA_RX_BUF_SIZE 1024 static uint8_t dma_rx_buf[DMA_RX_BUF_SIZE]; void HAL_UART_RxHalfCpltCallback(UART_HandleTypeDef *huart) { if (huart-Instance USART1) { process_dma_data(dma_rx_buf, DMA_RX_BUF_SIZE / 2); } } void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) { if (huart-Instance USART1) { process_dma_data(dma_rx_buf DMA_RX_BUF_SIZE / 2, DMA_RX_BUF_SIZE / 2); } }这种方案把缓冲区从硬件 FIFO 扩展到内存里的 DMA 缓冲区效果上就是把“软件 FIFO”换成了“内存 FIFO”。CPU 不需要在每次数据到达时响应而是分批次处理极大减少了中断负载。5.4 什么时候用 DMA什么时候用普通中断通常可以参考以下选择数据量小于几十字节每秒且接收不连续普通中断就够。数据量中等但比较集中突发建议开启硬件 FIFO 普通中断 软件环形缓冲区。高波特率、大数据量、连续传输务必上 DMA 空闲中断或 DMA 循环模式。多路串口同时接收DMA 方案能明显降低 CPU 占用。从工程实践来看DMA 空闲中断接收是主流 MCU 平台处理串口不定长数据的最稳定方案尤其适用于 921600 波特率以上、每帧几百上千字节的场景。6. 串口 FIFO 与数据流控的关系6.1 软件流控与硬件流控FIFO 只能缓冲不能无限接收。当 FIFO 装满接收端依然没有能力继续消费时真正的保底手段是流控。硬件流控RTS/CTS 信号线接收端在缓冲区快满时拉低 RTS通知对端暂停发送接收端恢复空闲后拉高 RTS对端继续发送。软件流控XON/XOFF 字符通过串口线传输控制字符让对端暂停或恢复发送。在 RS232、RS485 长线传输或蓝牙串口、USB 转串口场景硬件流控受限于连接线是否物理支持不是每一路都能用。但只要你手上有 RTS/CTS 线且对端硬件支持优先开启硬件流控能大幅降低高速传输时的丢包率。6.2 FIFO 深度与流控的配合从系统级来看FIFO 深度和流控策略必须一起设计。假设上位机通过 USB 转串口以 1 Mbps 发送数据给 MCUMCU 的硬件 FIFO 深度为 16 字节DMA 缓冲区为 1 KB。MCU 主循环每 10 ms 处理一次数据1 Mbps 下 10 ms 会积累约 1250 字节1 KB 缓冲区还不够。此时如果不开 DMA仅靠 16 字节硬件 FIFO 软件环形缓冲区软件缓冲区至少要设计到 2 KB 以上否则很容易丢数据。如果加了 RTS/CTS 硬件流控MCU 在软件缓冲区剩余空间小于某个阈值时拉低 RTS对端暂停发送这样缓冲区容量可以适当缩小。6.3 RS485 半双工的特殊性RS485 是半双工发送和接收共用同一对总线。如果接收端 FIFO 即将溢出它没法像 RS232 那样直接通过 RTS/CTS 通知对端暂停。很多时候要靠主站轮询协议的间隔控制或者严格限制一包的长度避免从站数据积压。这也是为什么某些 RS485 主从协议会规定“最大单帧长度”和“响应超时时间”本质就是在没有流控的情况下用协议节奏规避 FIFO 溢出风险。7. 串口 FIFO 相关的常见问题与排查方法下面的表格把串口 FIFO、丢数据、串口调试中最常见的问题汇总起来你可以直接对照排查。问题现象可能原因排查方式解决方案偶尔丢一个字节整体数据基本正常接收中断响应不及时或硬件 FIFO 溢出查看串口错误标志位 ORE/OVERUN观察丢包是否集中在主循环繁忙时开启硬件 FIFO 并调节触发阈值增加软件环形缓冲区把中断里的耗时操作移出FIFO 开了之后丢数据反而更严重触发阈值设置过高CPU 响应不及时导致 FIFO 溢出降低触发阈值观察中断频率将阈值改为一半深度配合 DMA 接收高波特率大数据量连续丢多字节软件缓冲区太小或者根本没有软件缓冲检查环形缓冲区是否溢出增加计数变量加大软件环形缓冲区改用 DMA 接收串口调试助手显示乱码或收到数据为 0x00波特率误差过大、收发双方时钟不匹配用示波器/逻辑分析仪看波形检查波特率寄存器配置校准时钟降低波特率确认转换芯片速率限制数据错位但每帧长度不变接收缓冲区残留旧数据解析起始位置错乱打印接收缓冲区内容检查帧同步逻辑接收协议加帧头和长度校验解析前先搜索帧头上位机收到数据慢、延迟高USB 转串口驱动缓冲过大或应用层读取不及时调整驱动缓冲区大小改用异步读取提高读取频率使用事件驱动或独立接收线程RS485 接收时偶发丢包半双工切换时序不合理或者一包数据过长抓取总线波形观察收发切换是否在帧结束后完成调整方向引脚切换延时减少单帧长度使用 DMA 后数据时好时坏缓冲区边界处理错误半满/全满回调重叠检查 DMA 模式是否循环模式回调里是否搬走数据使用双缓冲 DMA 或循环 DMA注意处理半满和全满时序7.1 怎么用错误标志辅助定位大部分带串口 FIFO 的 MCU都有对应的错误标志或状态寄存器及时读取这些标志是定位丢数据原因的关键。以 STM32 为例OREOverrun Error表示出现过载错误也就是数据寄存器中的数据还没被读走新的数据已经到达。FE是帧错误PE是奇偶校验错误NE是噪声错误。如果在异常发生前发现ORE被置位那么问题大概率出在中断延迟而不是波形质量。调试时可以这样做在串口中断里读取状态寄存器记录错误类型和发生次数。在软件环形缓冲区溢出时把overflow_count暴露到一个调试变量里。通过调试器或额外的调试串口定时读取这些计数判断丢包发生在哪个环节。7.2 用串口调试助手验证 FIFO 配置效果验证 FIFO 是否存在丢包最直接的方式是使用串口调试助手先确认 COM 口号避免与系统其它虚拟串口冲突。将波特率、数据位、停止位、校验位配置固定。选择循环发送固定报文或者用脚本连续发送大文件观察接收端统计的丢包率。逐级调整 FIFO 阈值和软件缓冲区大小记录每种配置下的接收完整度。加上流控后再次发送对比结果。注意串口调试助手本身也可能成为瓶颈如果发送端发送过快或者调试助手处理事件回调不及时它自身的数据显示窗口都可能无法展示全部数据。建议用文本文件保存完整接收记录后再统计而不是依赖显示窗口肉眼判断。7.3 排查为什么“开了 FIFO 反而丢数据”有工程师反馈芯片开启 FIFO 后丢数据比不开还多这种反常现象通常有两个原因。第一开启 FIFO 后中断次数变少CPU 响应门槛变高但 FIFO 深度有限如果中断被延迟的时间超过了 FIFO 填满的时间溢出概率反而上升。这是触发阈值和响应延迟之间没有匹配好。第二FIFO 开启后软件初始化顺序有误比如先开启 FIFO 再配置 DMA或者第一次切换 FIFO 模式后没有清除已产生的错误标志导致以后的数据进入异常路径。遇到这种情况先关闭 FIFO 恢复原来的中断模式验证数据是否正常再分步调试开启 FIFO 和调整阈值逐步定位是配置问题还是硬件响应问题。8. 串口 FIFO 设计与工程化最佳实践8.1 先定协议再定缓冲区串口工程中缓冲区不是盲目的越大越好。缓冲区大小应该按最坏情况计算最大积压数据量 最大未响应时间 × 波特率 / 10举例波特率 1152001 个字节加起始位停止位共 10 bit如果最坏情况下 CPU 在 100 ms 内没有处理串口数据那么最大积压数据量 0.1 s × 11520 字节/s ≈ 1152 字节因此软件环形缓冲区至少要设计成 2048 字节才能保证在 100 ms 延迟下不丢包。如果考虑突发帧还要再留余量。8.2 协议层加上帧头和长度字段FIFO 和缓冲区解决的是“数据不要丢”但只有“定长帧”或“帧头 长度 校验”的协议设计才能解决“数据错位、缺帧、半帧”的问题。建议所有串口应用至少在帧尾加一个校验字节哪怕是简单的累加和或 CRC8也能过滤掉大量由错误字节引起的解析问题。8.3 多级缓冲的统一设计在工程上可以把缓冲设计成三层第一层硬件 FIFOMCU 外设自带。第二层DMA 缓冲区DMA 把数据批量搬到内存。第三层软件环形缓冲区供协议解析和应用层使用。三层缓冲的存在意义不同不能互相替代。硬件 FIFO 解决中断抖动DMA 解决逐字节中断的负载软件环形缓冲区解决协议处理与应用逻辑的解耦。每一层的容量都要单独评估同时也要考虑层与层之间的衔接速度避免数据在某一层滞留过久。8.4 批量数据与分包策略上位机或设备一次发送几百上千字节时接收端如果一帧一帧地处理FIFO 和软件缓冲都容易积压。比较好的实践是模块内部用 DMA 循环接收应用层按协议帧超时或帧头匹配将数据包切分出来每收到一个完整帧就立即交给上层处理而不是等缓冲区满。8.5 不同平台的注意事项串口 FIFO 的配置在不同平台有不同入口STM32、GD32在 USART_InitTypeDef 或 HAL_UART_Init 中配置 FifoEnable、FifoThreshold 等字段需查阅具体芯片参考手册。NXP、瑞萨、英飞凌等厂商不同系列串口外设命名和 FIFO 配置方法差异很大建议直接读参考手册的 UART 章节。Linux 用户层串口终端设置里的低延时标志和 tty 缓冲区参数可以通过stty、setserial调整影响驱动层缓冲行为。Windows 用户层可以通过设备管理器调整 COM 口的接收/传输缓冲区不同 USB 转串口驱动的界面和有效范围不同直接影响上位机丢包率。8.6 关于安全和合规的提醒串口数据往往涉及设备控制、生产参数、用户信息调试时必须确保所有数据来源合法已获得设备或系统所有者的授权。不要利用串口抓包、调试接口去读取未经授权的设备数据也不要将测试中获取的生产数据、协议细节随意发布到公开平台。涉及工业控制、医疗设备、自动驾驶等关键系统时所有串口调试和改动都应在隔离、备份和回滚方案准备好之后再进行。9. 总结与下一步串口 FIFO 缓存不是复杂的概念但它确实是串口稳定通信的重要一环。硬件 FIFO 负责降低 CPU 中断压力软件 FIFO 负责接管数据并解耦应用处理DMA 则在高波特率大数据量场景下把 CPU 从逐字节中断中解放出来。丢数据的核心原因在于各缓冲层级容量和响应速度不匹配排查时逐个环节检查不要一开始就怀疑波特率。比较推荐的实践路径是先确认协议层能容忍的最大延迟按这个延迟计算出软件环形缓冲区的大小然后把中断处理精简到“搬数据”为止协议解析全部放到应用层最后在高波特率或有突发数据的场景直接用 DMA 空闲中断 环形缓冲区的组合。如果你的项目正在调 921600 以上波特率或者接收端是 Windows 上位机加 USB 转串口建议先把这篇文章里的排查清单打印出来从驱动缓冲区设置、软件环形缓冲区深度、中断处理耗时三个点开始检查多数丢数据问题会在这三个环节里暴露出来。有可靠的 FIFO 设计和合理协议串口通信是可以做到长时间不丢一个字节的。