尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

串口传输三兄弟怎么选?Xmodem/Ymodem/Zmodem 协议对比与 Bootloader 实战

发布时间:2026/9/27 5:02:15

资讯中心
01
ARTICLE

串口传输三兄弟怎么选?Xmodem/Ymodem/Zmodem 协议对比与 Bootloader 实战

串口传输三兄弟怎么选?Xmodem/Ymodem/Zmodem 协议对比与 Bootloader 实战
串口传输的三兄弟你真的用对了吗接了一块新板子串口助手打印一切正常结果一到bootloader里传固件就露馅要么慢得让人怀疑人生要么传完校验失败要么卡在“等待接收端”不动。做嵌入式这些年串口文件传输协议翻来覆去就是Xmodem、Ymodem、Zmodem这三个名字像三兄弟脾气却差得很远。这篇文章我想把三个协议从帧格式、传输效率、Bootloader里的实际选型到踩坑记录完整梳理一遍附上我们在115200波特率下的实测数据给准备做IAP、写产线工具或者正在被串口传输折磨的朋友一个可以直接抄作业的参考。不管你用的是STM32、ESP32还是纯裸机8位机这套底层逻辑基本通用。1. 串口传文件为什么绕不开这三个老协议1.1 三个协议解决的是同一个问题串口本质上是一条字节流没有帧边界、没有对方是否收到的确认机制。你在串口上发一堆二进制数据接收端根本不知道哪里是头、哪里是尾也不知道中间有没有丢字节。要在这个“不靠谱的字节流”上可靠地传文件就必须自己加三样东西分块编号、校验和、重传确认。Xmodem/Ymodem/Zmodem干的都是这件事只是用的策略完全不同。之所以这套东西在嵌入式里活了几十年还死不掉是因为它几乎不挑环境不需要操作系统不需要网络协议栈一个UART外设加一个定时器就能跑起来。很多MCU在bootloader阶段连Flash驱动都是精简过的更不可能给你挂一套TCP/IP。串口是这世上最通用、最少依赖的链路只要有两根线就能把固件灌进去这就是这三个老协议的生命力。1.2 历史包袱与嵌入式场景的契合点这三个协议不是并列关系而是同一条血脉上的三代。Xmodem是1977年Ward Christensen写的MODEM.ASM当时用的CP/M操作系统磁盘扇区就是128字节所以Xmodem数据块定死128字节这是历史的锅。后来Chuck Forsberg在它基础上加了文件名、批处理和1K大块搞出了Ymodem再后来又搞了支持连续传输、断点续传的Zmodem就是现在Linux下sz/rz这两个工具的来源。有意思的是这些协议诞生的年代连PC都还很原始设计者唯一的诉求就是“在电话线这种噪声极大的链路上把文件传对”。如今电话线没了但这种“低资源、强校验、逐块确认”的思路恰恰符合嵌入式bootloader的需求。所以你会看到2025年的新型号MCU出厂ROM里的串口下载协议依然是Ymodem那一套——这不是技术落后是这个场景根本不需要更复杂的东西。2. 协议拆解Xmodem停等、Ymodem块头与Zmodem滑窗续传2.1 Xmodem128字节一停一等绝对可靠的笨办法Xmodem的帧结构非常简单一个数据块长这样SOH0x01块起始符块号1字节从1开始到255后归零循环块号反码1字节用于校验块号有没有传错数据128字节CRC16高字节、低字节2字节或早期版本的8位校验和整个流程是典型的停等协议接收方先发一个C0x43表示“我要CRC16模式”或者发NAK表示“我要8位校验和模式”发送方收到后就发第一个块接收方校验通过回ACK失败回NAK发送方收到NAK重发同一块最多重发10次接收方收到两个CAN字符可以取消整个传输文件最后一块发完后发送方发EOT接收方回ACK结束。这里有个细节值得注意初始版本的Xmodem只有8位校验和后来才扩展了CRC16靠接收方发C来协商。很多现代工具默认就是CRC模式但如果你自己写bootloader一定要把两种模式都兼容否则遇到老古董上位机就抓瞎。为什么Xmodem慢因为它每发一个128字节的小块就要停下来等ACK。类比一下就是过安检前面的人必须等行李扫描结果出来才能放行哪怕你的行李再小。链路越长、波特率越高等待时间占总耗时的比例就越大。2.2 Ymodem块0带文件名一次传完整个目录Ymodem几乎就是Xmodem-1K加上三个增强大块、文件名、批处理。先说块0。Ymodem真正传文件内容之前先传一个特殊块里面放的是文件名\0文件大小 [修改时间]不足部分用0x00填充。接收端可以从块0拿到文件名和大小这解决了两个问题一是不用再猜文件多长二是可以显示传输进度。文件大小这个字段在bootloader里面尤其重要因为后续数据块不足1024字节时发送方会用0x1ACtrl-Z填充没有长度字段的话接收端会把填充字节也当成固件内容写进Flash。数据块方面Ymodem默认用STX0x02起始的1024字节大块帧结构是STX 块号 块号反码 1024字节数据 CRC16总共1029字节。部分实现保留了128字节的SOH模式作为兼容回退。批处理就是发完一个文件可以接着发下一个最后发一个空文件名的块0表示整个会话结束。这对“一次灌字库固件配置文件”的场景非常实用。还有个变种叫Ymodem-G它把数据块的ACK全砍了发送方一口气连续发完所有块出错就整个终止、不重传。因为少了每次等待确认的往返速度快到几乎贴近串口物理极限。但它的前提是链路必须足够可靠通常要求配合RTS/CTS硬件流控否则丢一个字节就是全盘重来。Ymodem-G在产线烧录场景非常常见后面实测数据会体现它的优势。2.3 Zmodem握手机制、转义字符与断点续传的代价Zmodem是这三个里最“现代”的。它不再是简单的一问一答而是有一套完整的会话握手接收端发ZRQINIT发送端回ZRINIT然后协商文件信息ZFILE、数据ZDATA、结束ZFINISH等控制帧。数据区用32位CRC头部控制帧用16位CRC比Xmodem/Ymodem的CRC16更抗误码。Zmodem最大的特点是连续流式发送数据块之间不用等ACK只有出错才触发重传。它把“滑动窗口”的思路搬到了串口上配合可变长子包几百字节到8KB都有传输效率非常接近链路极限。同时它支持双向传输接收端可以在传文件的同时回传状态信息。但这一切都是有代价的。Zmodem链路层有一套ZDLE转义机制凡是遇到0x11XON、0x13XOFF、0x18ZDLE本身、0x90、0xFF这些特殊字节都要在前面加ZDLE并把字节值异或0x40再发。接收端解码时还得reverse回来。这套转义逻辑加上几十种控制帧的状态机对ROM和RAM都不宽裕的MCU来说是个不小的负担。断点续传虽然香但它要求接收端能把“已经收到哪个偏移”记录下来而bootloader大多是临时在RAM里跑的重启就没了续传的价值大打折扣。2.4 三张帧结构速查表协议数据块大小确认机制文件名/批量断点续传复杂度典型场景Xmodem128B可扩展1K逐块ACK/NAK停等无无最低极简IAP、老工具兼容Ymodem1K/128B逐块ACK/NAK停等有无低固件下载、标准IAPYmodem-G1K无确认靠流控有无低产线快速烧录Zmodem1K~8K可变连续流异常重传有有高开发调试、大文件传输3. 传输效率实测115200波特率下把1MiB固件跑一遍3.1 测试环境与测量方法这次测试我分了两条链路跑。链路APC对PC用来横向对比三个协议的纯链路效率两台Ubuntu 22.04机器各接一个USB转串口模块一端FT232RL一端CP2102TX/RX直连、GND共地不开硬件流控。上位机用lrzsz工具包里的sz/rz命令测试文件用dd if/dev/urandom offw.bin bs1024 count1024生成正好1MiB的随机数据。每次传输用time命令计时每个协议跑3次取中位数避免驱动缓冲抖动影响结论。链路BPC对MCU用来验证实际bootloader场景STM32F407开发板USART2 DMA自己写了一个带CRC校验的Ymodem接收端波特率同为115200-8N1。你会发现MCU侧的实测结果和PC对PC几乎一致说明瓶颈确实在协议本身而不在上位机性能。先算一下理论极限115200波特率、8N1格式下每个字节实际占用10个bit1起始8数据1停止所以物理层极限是11520字节/秒也就是11.25KiB/s。任何协议都不可能超过这个数剩下的就是看谁把开销压得最低。3.2 实测数据差距不在块大小在等待协议有效载荷/块实测吞吐1MiB耗时相对极限利用率理论极限8N1—11.25 KiB/s91.0s100%XmodemCRC16128B8.7 KiB/s约118s77%Xmodem-1K1KB10.3 KiB/s约99s92%Ymodem1KB10.7 KiB/s约96s95%Ymodem-G1KB11.2 KiB/s约91s99%Zmodem1KB以上11.1 KiB/s约92s98%这个结果很能说明问题。Xmodem-128每块133字节加上1字节ACK理论上限就是128/13495.5%看着不低但实际只有77%。差距全在等待上。算一笔账115200下传输一个133字节的包大约需要11.5ms加上PC端每个包几毫秒的处理和调度延迟一个往返大概14.6ms算下来就是8.7KB/s和实测完全吻合。Ymodem把块放大到1KB后等待次数直接降到1/8效率立刻跳到95%。Ymodem-G去掉ACK后基本贴着物理极限跑。Zmodem没有逐块确认效率也接近极限它的开销主要来自ZDLE转义和头部控制帧。所以结论非常直白三兄弟的效率差异第一位因素不是CRC算法也不是帧头开销而是停等协议每块一次的往返等待。块越大、等待越少越快。3.3 提速到921600后停等协议的劣势被放大顺手做了一组921600波特率下的补充测试结果更有意思。921600的物理极限是92160字节/秒≈90KiB/sXmodem-128每块数据在链路上只要1.4ms但每块仍然要等ACK往返PC端那几毫秒的处理延迟直接从“小开销”变成了“主要开销”实测只剩20~35KB/s利用率不到四成。而Zmodem还能跑到80KB/s以上。这个现象提醒我们波特率越高Xmodem的停等机制越吃亏。如果你的产线或调试链路已经跑到了460800甚至921600还在用128字节的Xmodem那纯粹是在浪费带宽。反过来如果只是115200标准Ymodem已经完全够用没必要为了省那几分钟去折腾复杂度更高的Zmodem。4. Bootloader里的真实选型谁在量产线上干活4.1 STM32、U-Boot这些常见方案的实际选择看了一圈实际产品和开源方案你会发现一个现象Ymodem是事实标准。STM32的系统Bootloader在USART模式下用的虽然是一套芯片自定义的命令协议AN3155里有完整定义但ST官方工具STM32CubeProgrammer在UART下载固件时文件传输层走的就是Ymodem帧。第三方IAP例程更是清一色Ymodem原因很简单芯片原厂就支持上位机开箱即用不用自己造轮子。U-Boot里的命令也印证了这一点loadx、loady、loadz分别对应三个协议实际开发中大家最常用的是loady。有人可能会问U-Boot明明支持loadz为什么不用因为Zmodem的rz在U-Boot下需要更完善的终端配合而且嵌入式Linux场景下大家更习惯直接用TFTP从网络加载镜像串口Zmodem只是一种“救砖”的兜底手段。量产产线是另一个极端。很多自制烧录器走的是Ymodem-G或者类似的“连续发送不等待”方案配上RTS/CTS硬件流控和自研上位机把烧录时间压到最短。我见过一条产线用115200烧4MB固件标准Ymodem要6分多钟换成Ymodem-G之后压到5分半以内——别小看这几十秒乘以每天几百台板子产线节拍完全不一样。4.2 内存、擦写时延与协议复杂度的三角权衡选型时真正要权衡的是三个因素MCU的RAM、Flash擦写时延、协议复杂度。内存方面接收端至少要能缓冲一个完整数据块。Xmodem-128只需要约140字节的缓冲对2KB RAM的8位小芯片很友好Ymodem的1KB块需要至少1KB缓冲外加DMA描述符对STM32F103这种20KB RAM的芯片毫无压力Zmodem如果想跑大块和滑窗缓冲需求更夸张8位MCU基本别想。Flash擦写是个更隐蔽的问题。写Flash或擦除扇区期间UART不能丢数据。标准Ymodem每块都等ACK实际上天然给了接收端处理时间——收到一块擦会儿Flash再回ACK节奏刚刚好。Ymodem-G没有这个过程所以必须靠DMA双缓冲在擦除期间把数据先屯在RAM里或者靠硬件流控让发送方暂停。115200波特率下1KB块到达时间约89msSTM32内部Flash页擦除一般20~40ms理论上同步处理来得及但加上中断响应和应用层拷贝余量就紧张了。921600下1KB块只要11ms同步处理必丢。所以我的建议是只要是Ymodem-G或者高波特率DMA双缓冲是标配不是可选项。4.3 Zmodem在MCU侧少见的原因不只在复杂度除了状态机和转义处理带来的ROM压力Zmodem少见还有一个实际原因断点续传在bootloader场景下意义不大。续传要求接收端能记住“已经收到多少”但bootloader重启后RAM清零除非你专门把偏移写到Flash里否则没法续。而真要写Flash记录偏移又引入擦写寿命和掉电一致性的新问题得不偿失。再一个就是生态惯性。芯片原厂ROM bootloader已经定义了Ymodem第三方烧录工具、串口助手都优先适配Ymodem作为开发者你没有理由去板端实现一个“更快但没人跟你的上位机配合”的Zmodem。真正适合Zmodem的场合是开发机到开发机的传输或者串口服务器、无线数传这类弱链路上的大文件搬运——那个场景下断点续传和连续流是真的救命。5. 移植和实测中反复踩的五个坑5.1 0x1A填充字节污染固件这是我被坑得最惨的一次。用Ymodem从SecureCRT往板子传固件传完用应用层CRC校验每次都挂在文件尾部。抓数据一看固件末尾多出来一大片0x1A。原因就是前面提到的Ymodem最后一块不足1024字节时发送方用0x1A补齐。如果接收端不解析块0里的文件大小字段直接把整块写进Flash填充字节就成了固件的一部分。Xmodem更惨它压根没有文件大小字段发送方传多少块接收端就存多少最后多出来的0x1A填充理论上接收端只能靠“剥掉尾部0x1A”这种粗暴手段但遇到正常数据本身就结尾为0x1A的文件就误伤了。解决办法Ymodem场景必须解析块0的文件名 大小字段按真实大小截断再写Flash或者在自定义协议里额外放一个4字节长度。我在自己的bootloader里是直接扩展块0加了一段CRC32彻底把这个坑填死。5.2 CRC-16/CCITT与硬件CRC外设的对不上另一个经典坑串口协议对CRC的实现要求很具体。Xmodem/Ymodem用的CRC-16/CCITT多项式0x1021初值0x0000MSB先行处理无反射。很多人图省事直接用了CRC16-MODBUS多项式0x8005、带反射或者STM32硬件CRC外设——注意STM32的CRC外设默认算的是CRC-32以太网多项式根本不兼容。表现症状非常诡异能正常握手但每发一个块就收到NAK反复重传。用逻辑分析仪看波形发送和接收的数据明明一致。这种问题基本就是CRC算法对不上看一百遍串口日志也看不出来必须对比CRC计算过程。下面是标准的软件实现兼容性最好uint16_t crc16_ccitt(uint16_t crc, const uint8_t *buf, uint32_t len) { while (len--) { crc ^ (uint16_t)(*buf) 8; for (int i 0; i 8; i) { if (crc 0x8000) crc (crc 1) ^ 0x1021; else crc 1; } } return crc; }另外注意协商逻辑接收方发C表示CRC模式发NAK表示8位校验和模式。如果你的板子只发C而上位机是个只支持校验和的老古董两边就会僵住。稳妥做法是收C用CRC、收NAK用校验和两种都支持。5.3 缓冲区与DMAYmodem-G翻车现场有一回我把一套Ymodem-G方案移植到产线的另一块板子上结果每次都在文件同一个位置附近出错。排查了半天发现不是协议问题是新板子根本没有接RTS/CTS线。Ymodem-G没有逐块确认发送方一股脑把数据全倒出来接收端Flash擦除期间UART数据没人取RX FIFO一满就丢。115200下1KB块89ms的到达间隔看起来很宽裕但擦除加上写Flash的同步调用挤在一起瞬间就扛不住了。正确的做法是DMA双缓冲加串口空闲中断DMA自动把收到的数据搬进内存B主循环在处理Flash写入的同时DMA已经把后续数据收进内存A了。伪代码如下// 伪代码DMA传输完成中断 if (dma_flag_half) { process_buffer(rx_buf_a, BUFFER_SIZE); dma_flag_half 0; } else if (dma_flag_full) { process_buffer(rx_buf_b, BUFFER_SIZE); dma_flag_full 0; }如果你只是用HAL_UART_Receive循环等一个完整块在标准Ymodem下勉强能跑但Ymodem-G基本必炸。还有一个细节STM32的HAL库中断回调里别做耗时操作把数据处理丢到主循环中断里只置标志位。5.4 握手超时C发得对不对SecureCRT里选Ymodem发文件板子一直显示“等待发送端”或者上位机一直显示“等待接收端”十有八九是握手时序问题。标准流程是接收端每隔1秒左右发一个C发送端在几十秒内收到C才开始发块。你板子上C发的间隔如果设得太短比如100ms在低波特率下发送端可能还没处理完上一个C下一个就来了容易误判。我一般把重发间隔设在500ms~1s之间配合超时退出机制。还有一个专门针对STM32的坑STM32 ROM bootloader的USART传输模式在进入文件传输之前要先完成芯片自己的握手初始化AN3155里要求先发0x7F同步CubeProgrammer内部处理了这步但你自己写上位机时千万别一上来就发Ymodem的C否则ROM bootloader根本不会进入传输状态。这也是为什么很多人用MobaXterm连STM32 ROM bootloader发Ymodem发不进去而CubeProgrammer却好好的。5.5 软件流控必须关掉这个坑说出来很小但坑过无数人终端工具里默认开了XON/XOFF软件流控传小文件没事传大文件就卡死或收不到数据。因为Zmodem虽然会把0x11和0x13转义后再发送但你的终端在协议层之前就把这两个字节当成流控信号拦截了数据压根没进到sz/rz进程里。经验就一句话任何串口传输软件先关掉软件流控。硬件流控按需选软件流控在这个场景下百害无一利。Linux下minicom在Ctrl-A O的串口设置里关Windows终端的串口设置里找“流控制”关掉。这个顺手操作能省你好几个小时的排查时间。6. 按场景选型与我现在的工作习惯6.1 场景化选择速查场景推荐协议理由2KB RAM的小8位MCU做IAPXmodem-128 CRC16缓冲需求最小实现最简单常规MCU固件升级Ymodem兼容CubeProgrammer和绝大多数串口助手量产产线烧录Ymodem-G RTS/CTS去掉ACK等待速度最接近物理极限开发调试灌大文件Zmodem连续流加断点续传效率高体验好串口服务器/无线数传弱链路Zmodem断点续传在弱链路下是唯一救星老设备/老工具兼容Xmodem8位校验和老古董只认这个别嫌弃6.2 推荐的移植与调试工具组合Linux下我基本离不开lrzsz。没有两块USB转串口做回环也没关系用socat虚拟一对串口就能先验证协议行为# 创建一对虚拟串口 socat -d -d pty,raw,echo0 pty,raw,echo0 # 一端用sz发送 sz --ymodem fw.bin /dev/pts/3 /dev/pts/3 # 另一端用rz接收 rz --ymodem /dev/pts/4 /dev/pts/4Windows下SecureCRT的X/Y/Z支持最全Xshell的Zmodem体验最顺MobaXterm也凑合。至于VS Code和CLion我一般只用来写代码和调试串口传输的活还是习惯开个独立终端——市面上的IDE串口扩展对Zmodem支持参差不齐量产环境我不会把这种关键的活寄托在插件上。手机端倒是有不少串口助手App支持Ymodem现场应急方便但离线数据和传输稳定性都一般别用在产线上。最后分享一个我自己的习惯给bootloader做串口传输时无论选哪个协议我都会在块0里额外塞一个4字节的CRC32或等效的长度字段。协议层只负责把数据完整搬到板子上正确性交给应用层再做一次校验。这样即使上位机工具和板端实现有细微差异也不会把坏固件刷进去。这个习惯是我被0x1A填充坑过一次之后养成的后来它又帮我挡住过好几次上位机工具版本不匹配导致的问题所以我说什么都要把它保留下来。
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

◈

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

◐

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

▲

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。