资讯动态

数字信号编码从NRZ到8B/10B:物理层比特映射与工程选型详解

发布时间:2026/9/10 10:33:08 来源:尧图企业网站定制
做嵌入式、通信或者底层硬件开发的同行应该都有过这种时刻拿着示波器戳在芯片引脚上明明协议栈里跑的全是0和1的逻辑示波器上却是一串完全不认识的电平波形翻了大半天手册最后发现问题是出在物理层编码方式上。数字信号的编码方式看起来是个老生常谈的基础话题但真正到了工程现场NRZ、NRZI、曼彻斯特、8B/10B这些东西混在一起还是很容易把人绕晕。这篇文章我打算一次性把这些常见编码方式串起来讲清楚——不光是它们各自怎么工作还包括为什么会有这么多花样、不同场景为什么选不同的编码、以及接收端译码器到底是怎么把波形还原成比特流的。适合刚接触通信和嵌入式开发的初学者也适合那些平时在用协议栈但没细究过物理层的工程师。1. 数字信号不是“0和1”而是一串物理电平1.1 示波器上看到的东西和协议手册里写的东西不是一回事数字信号这个词有两层含义大家经常混着用。逻辑层面的数字信号是离散的0和1是协议栈、CPU、内存里那个干干净净的比特世界物理层面的数字信号是线缆上实际存在的高电平和低电平是有电压、有电流、有上升沿下降沿的物理量。编码方式处理的就是这两个世界之间的映射关系。通信双方要传数据不可能把寄存器里的0和1直接搬过去必须先把比特变成线缆上的电压序列。这个过程就是编码。比如规定3.3V代表逻辑1、0V代表逻辑0这是一种最简单的映射。但真实工程里几乎不会用这种直连方式因为这里头有一堆问题要解决时钟怎么同步、直流分量怎么处理、抗干扰能力怎么保证每一个问题都会推动编码方式往更复杂的方向演进。我自己刚入门时最大的误区就是以为协议分析仪上看到的“0101”就是线缆上实际传的东西。后来拿示波器一抓发现波形和想象完全对不上才明白逻辑比特和物理波形之间隔着一层“编码”的鸿沟。理解这层鸿沟是看懂所有通信系统的第一步。1.2 模拟与数字的本质分界噪声容限与阈值判定很多人对模拟信号和数字信号的理解停留在“连续”和“离散”上这在课程里没错但对实际工程来说更关键的区别是抗噪声的方式。模拟信号的每个电平都可能携带信息理想情况下要把信号原样还原才能解码数字信号则只关心几个离散电平只要噪声没有把电平顶过阈值就能正确判定。举一个直观的例子一个5V供电的数字接口接收端通常把2.0V以上的电压判定为逻辑10.8V以下判定为逻辑0中间那段叫不确定区。只要外界干扰不超过这个容限信号就算有一点点畸变也能被正确解码。这就是数字信号能用编码方式去“折腾”的基础——因为它允许一定程度的失真编码器才有空间去设计各种跳变规则。这里也顺带回应一下“微积分”和数字信号的关系。模拟信号的完整描述依赖微积分因为电压连续变化要算变化率、积分能量都逃不掉微积分数字信号在时间轴上是离散的跳变逻辑上不需要微积分但分析编码后的频谱、上升沿带宽这些物理特性时傅里叶变换这套微积分体系照样会冒出来。编码的一个重要指标就是带宽本质上就是在控制信号的频率分量这背后全是数学。下面这张表可以快速看出模拟和数字在工程视角的核心差异维度模拟信号数字信号取值空间连续无穷多个电平离散有限个电平抗噪能力噪声直接叠加进信息噪声只要不越过阈值就不影响判定典型数学工具微积分、微分方程离散数学、逻辑代数、频谱分析失真容忍度极低失真即信息丢失较高有噪声容限和裕量编码空间几乎不做额外编码可以设计丰富编码方式优化传输2. 编码的本质逻辑比特如何映射到线路电平2.1 基带编码和线路编码别混为一谈聊编码方式之前先把两个经常混淆的概念拆开基带编码和线路编码。基带编码解决的是“每个比特用什么波形发送”比如高电平发1、低电平发0这是最基础的信号映射线路编码则是在原始数据之上再叠加一层变换比如4B/5B、8B/10B目的是解决同步、直流平衡、频谱分布这些额外的问题。不过实际工程里大家习惯把这两层都叫“编码”所以后面我不刻意区分但心里要有数NRZ、RZ、曼彻斯特这些都是基带编码解决“每个bit怎么放”8B/10B、64B/66B是线路编码解决“一批bit怎么组织”。USB、以太网这些协议往往是两层配合使用。为什么需要区分因为这两层优化的目标不一样。基带编码往往受限于物理实现越简单越好线路编码则更关注统计特性——比如整个码流里0和1的比例是否均衡、最长连续相同bit有多长、频谱能量集中在哪个频段。把这些概念分开看协议文档时就不会被一堆缩写搞糊涂。2.2 最基础的NRZ编码以及它为什么让工程师头疼NRZNon-Return-to-Zero不归零编码。规则非常简单逻辑1发高电平逻辑0发低电平一个bit持续一个码元周期电平在这期间不回到零。名字里的“不归零”是针对RZ说的它不像后面的RZ那样每个bit结束都回到零电平。NRZ的优点是频谱利用率高、实现简单缺点是两个致命问题。第一如果数据里出现长串的连续0或连续1线上电平长时间不变接收端就无法确定每个bit的边界时钟慢慢漂掉最终采样错位导致误码。第二长时间不变化意味着信号含有很大的直流或极低频分量很多链路中间会用电容做交流耦合这个电容会把低频分量滤掉波形塌陷接收端看着电平慢慢“飘”向中间最后直接无法判断。在低速短距离场景下NRZ的问题不明显所以早期很多芯片接口、存储接口直接用它。但只要跑高速、跑远距离就必须想办法解决“长时间没有跳变”的麻烦。后面讲的每一种编码几乎都是在NRZ的基础上针对这个问题打补丁。2.3 归零编码RZ用带宽换同步的早期方案RZReturn-to-Zero归零编码。思路很直接既然怕电平长时间不变那干脆每个bit结束都回到零电平。逻辑1在码元前半段发高电平后半段强制回零逻辑0整个码元保持低电平。这样每个1 bit中间一定有一个明显的下降沿接收端可以根据沿来同步。但代价也很明显同样一个bit周期真正传输能量、传递信息的时间只有一半意味着要达到同样的数据率信号带宽要加倍。而且连续的0还是会让信号长时间保持低电平同步问题依然存在。所以RZ在实际总线里很少大规模使用更多是作为一个教学概念给后面曼彻斯特编码做铺垫。把NRZ和RZ放在一起对比能更清楚地看到“同步”和“带宽”之间的博弈编码电平特征自带时钟能力带宽开销典型问题NRZ1高0低不归零无依赖外部时钟1倍长串相同bit丢失同步直流分量大RZ1前半周期高后半回零0全低每个1都有归零沿2倍连续0仍丢同步带宽浪费3. 自带时钟的经典方案曼彻斯特与差分曼彻斯特3.1 曼彻斯特编码一次跳变同时传数据位和时钟曼彻斯特编码的思路堪称经典每个bit周期中间一定有一次电平跳变这个跳变既当数据又当时钟。具体规则是逻辑1用“从高到低”的下降沿表示逻辑0用“从低到高”的上升沿表示反过来定义也可以看协议标准怎么约定。由于每个bit中间必定有沿接收端不需要额外恢复时钟直接从波形边缘就能找到采样点彻底解决了长串相同电平导致的同步丢失问题。代价是带宽翻倍一个bit周期内电平至少要变化一次同样的数据率信号基频直接翻番。曼彻斯特这种“又传数据又传时钟”的机制在低速、短距离、设备成本敏感的场合非常吃香。早期10M以太网、很多RFID通信、一些传感器总线都用它。我调试RFID读卡器时见过它的实际波形毛刺很多、幅度还有波动但每bit中间那个跳变清清楚楚读卡芯片只用很简单的电路就能把数据解出来这在成本受限的标签芯片里是巨大优势。3.2 差分曼彻斯特抗干扰更强的变体差分曼彻斯特编码在曼彻斯特基础上做了改进不再用绝对电平表示0和1而是用“bit周期起始处有没有跳变”来区分。规则是每个bit中间一定有一次跳变逻辑0在bit周期开始处额外多一次跳变逻辑1在bit周期开始处不跳变。这样一来0和1的区别不依赖电平高低而依赖跳变本身抗干扰能力更强。因为在一个有串扰、有共模干扰的环境里绝对电平容易被拉偏但跳变沿不太容易被伪造。代价是译码逻辑稍复杂接收端必须记住上一个bit末端的状态才能判断当前bit起始处有没有跳变本质上是一个差分检测问题。实际使用中差分曼彻斯特在长线缆、电机驱动附近这类噪声恶劣的场景更稳。但它的逻辑复杂度高一些在成本敏感的小芯片里用得不如普通曼彻斯特普及。3.3 带宽翻倍为什么还能接受10M以太网的算账方式10M以太网当年选择曼彻斯特编码很多人觉得奇怪明明带宽翻倍为什么还用这里要算一笔综合账。10Mbps的数据率曼彻斯特编码后的信号基频是20MHz在双绞线上传100米问题不大。如果用更复杂的编码把带宽压下去就得换更好的线材、更贵的收发器在那个芯片工艺还很粗糙的年代成本完全不可控。换句话说当年选型的第一约束不是带宽而是成本和抗干扰能力。曼彻斯特编码的信号在每个bit中间都有跳变接收端电路可以做得非常简单不需要锁相环不需要复杂时钟恢复这在当时的技术条件下就是最大的优势。这也是为什么老一代接口里到处都是曼彻斯特编码。从协议演进的角度看10M以太网用曼彻斯特、100M以太网换4B/5B、千兆以太网换8B/10B、再往后换64B/66B背后就是一条“随着芯片和信号处理能力提升用更复杂的编解码换取更高带宽效率”的清晰路径。4. 工程中最常见的NRZI以USB2.0为例拆解4.1 USB2.0为什么放弃曼彻斯特USB2.0的物理层用的是NRZINon-Return-to-Zero Inverted反向不归零编码不是曼彻斯特。原因很现实速度上去了曼彻斯特带宽翻倍的代价吃不消。USB2.0高速模式是480Mbps如果用曼彻斯特线缆上的有效信号频率要奔着960MHz去无论是PCB布线还是线材连接器都会变得极其苛刻。NRZI的规则是逻辑0发生电平翻转逻辑1保持电平不变。它和NRZ最大区别是信息不依赖绝对电平而依赖“有没有翻转”这也是名字里“Inverted”的由来。所以哪怕共模电平整体漂移、衰减接收端只要抓到跳变沿就能正确恢复数据抗干扰能力明显强于NRZ。为了更直观假设原始数据是11010001原始bit11010001NRZI是否翻转不翻不翻翻转不翻翻转翻转翻转不翻假设起始高电平后的电平高高低低高低高高注意看连续两个1时电平不变遇到0才翻转。这就是NRZI它把“0”定义成动作把“1”定义成静止。这种设计让接收端对绝对电平不敏感却带来一个新问题如果数据里出现很多连续的1线上照样长时间没有跳变时钟同步依然会丢。4.2 位填充机制强制翻转的“土办法”USB2.0的解决方案很巧妙在发送数据前先做一次“位填充”如果数据流里连续出现6个1就在第6个1之后强制插入一个0。因为NRZI规则里0会翻转这就保证线上最多只会有6个连续的相同状态接收端时钟不会丢。举个例子原始数据里有7个连续的11111111发送端会把它变成11111101中间插入的那个0就是填充位。接收端收到数据后要做的第一件事就是“去填充”连续识别到6个1后把后面那个0丢掉再恢复出原始数据。这个机制听着土但极其有效代价只是最多约14%的速率损耗——6个数据bit里最多插入1个冗余bit实际填充开销取决于数据内容。这个细节在链路层手册里通常会写但真正理解它要回到NRZI的物理特性上。位填充不是数据传输格式的“规范洁癖”而是为了解决时钟同步和直流平衡这两个物理层硬问题。4.3 编码开销和有效带宽的换算一个很容易在工程里被忽略的问题是协议标称速率和有效数据吞吐之间的关系。USB2.0高速模式标称480Mbps但经过位填充、包结构、CRC、握手等等开销之后实际可用带宽通常只有320Mbps左右。其中位填充带来的损失跟数据内容强相关——如果传输的内容全是0xFF这样的数据全是1每个包都要填充大量0吞吐会明显下降如果内容随机填充率低一些吞吐会好一些。所以我常说做高速数据传输系统不能只看协议标称速率一定要算编码开销。这个习惯在后面的8B/10B、64B/66B里同样适用。这也是为什么很多老工程师看带宽会先问一句这是编码前还是编码后的速率。5. RS232到万兆以太网不同场景的编码选型逻辑5.1 UART的异步起止位简单可靠的代价RS232、UART这类异步串口用的是最简单的解决方法不搞自同步编码而是用起止位来框定每个字节。平时线路维持在高电平空闲态要发送一个字节时先拉一个低电平的起始位然后按约定波特率一个bit一个bit地把数据发出去最后再拉回高电平的停止位。这种方式不需要专门恢复时钟接收端只要检测到起始位的下降沿就按波特率在每一个bit的中间点采样。缺点是效率低每个字节都要带上起止位开销而且双方时钟偏差太大就会误码。但在调试口、传感器、低速控制场景这种简单可靠、不需要同步电路的方案依然是最优选。我做单片机开发时最常用的就是115200波特率的UART两块芯片之间直接飞线就能通信压根不用考虑编码复杂度这就是“适合场景”四个字最好的注脚。5.2 4B/5B与8B/10B让码流保持直流平衡到了100M以太网问题变了数据率更高不能再接受曼彻斯特的带宽翻倍但也必须解决直流平衡问题。100M以太网用了4B/5B编码把4个bit映射成5个bit通过查表保证输出码流里最长连续相同bit受限再配合MLT-3线路编码把信号压到低频。8B/10B编码是另一个经典把8个bit变成10个bit额外多出的2个bit用来做直流平衡和游程控制保证码流里0和1的数量长期近似相等并且最多连续5个相同bit。PCIe、千兆以太网、光纤通道都是8B/10B的忠实用户。代价是20%的编码开销换算过来就是标称带宽打八折。我一直觉得8B/10B是特别值得学习的设计它用一张相对简单的映射表同时解决了直流平衡、时钟同步、错误检测三个问题而且编解码都可以用组合逻辑实现不需要复杂的算法。理解8B/10B之后再去看更复杂的编码思路会清晰很多。5.3 64B/66B和PAM4高速链路里编码越来越“最少干预”到了10G甚至更高的速率20%的开销就太肉疼了所以以太网在10G时代转向了64B/66B编码输入64个bit加上2个同步头总共66个bit。同步头用来区分数据块和控制块后面64个bit除了做一次多项式扰码外不再做查表用扰码来避免长串相同电平尽量让码流随机化。高速SerDes里还有PAM4用4个电平一次传2个bit把带宽效率提升一倍。但它对信噪比的要求也成倍提高这就是为什么同样速率下PAM4系统对PCB板材、连接器、眼图余量的要求严苛得多。编码方式选型到了这个层级本质上是在带宽效率、信号完整性和成本之间做博弈。各代际典型编码的开销对比非常直观编码方式映射关系编码开销典型应用NRZ1bit→1电平0%早期芯片接口曼彻斯特1bit→1bit但带宽翻倍带宽100%10M以太网、RFID4B/5B4bit→5bit25%100M以太网8B/10B8bit→10bit20%千兆以太网、PCIe、光纤通道64B/66B64bit→66bit3.125%10G/25G/100G以太网PAM44电平每电平2bit带宽减半但信噪比要求高56G/112G SerDes6. 接收端的逆向工程译码器如何从波形恢复比特流6.1 时钟恢复确定采样点才是第一步不管发送端用什么编码接收端第一件事都是从进来的波形中找到采样时刻这在通信里叫时钟恢复。常见做法是用锁相环锁定输入信号的跳变沿再用这个恢复出来的时钟在每个bit的中间位置采样。对于曼彻斯特这种自带跳变的编码锁相环相对好锁对于NRZI就需要位填充保证有足够多的跳变来维持锁相环更新。很多初学者以为译码就是把高低电平翻译成0和1其实这是个大误区。采样点偏了哪怕电平完全正确也会出错。实际工程中眼图测试很大程度上就是在看采样点附近的张开度够不够——张开度好说明采样裕量大误码率低张开度差说明哪怕现在能通温度和噪声一变化就可能出问题。一个具体场景低速调试时我习惯用示波器直接看波形数电平判断数据对不对但在高速链路上用示波器看“有没有信号”完全不够必须看眼图、看抖动、看裕量因为译码器真正关心的是“在正确的时间点上电平是否离阈值足够远”。6.2 边界条件和真实场景里的误码译码器除了要恢复时钟、翻译电平还要处理一些边界情况。比如接收信号幅度太小低电平抬升、高电平下降导致电平落在判定阈值附近比如信号速率和本地时钟不一致锁相环还没锁定数据就已经来了再比如长距离线路中高频分量衰减比低频严重波形边沿变缓采样点的裕量被不断压缩。这些边界条件平时不会出现但温度变化、线材老化、接头氧化都会让它们突然冒出来。所以真正稳定的系统在设计时就会留出足够的电压裕量和时间裕量而不是指望译码器“智能纠错”。这也是我要反复强调的一点编码方式的选型和译码端的实现是同一个问题的一体两面发送端做得再好接收端的采样时钟不稳一切白搭。你在手册里经常看到“误码率”“抖动容限”“眼图模板”这些指标它们本质上都是对“译码端能否在真实条件下正确恢复比特流”的量化描述。搞懂这一点就不会再把编码当成一个纯粹的发送端话题。7. 我实际工程中踩过的几个编码坑7.1 交流耦合电容和长串相同电平的“合谋”我曾经调试过一个板间通信链路现象很奇怪跑测试图案时一切正常一跑真实业务就随机误码而且只在某个方向出现。查了很久最后定位到链路中间有个交流耦合电容而业务数据里恰好经常出现长串相同的电平状态低频分量太大过不了电容波形被拉塌。换成带编码的传输方式之后问题立刻消失。这件事之后我形成了条件反射凡是链路里存在交流耦合就一定关注编码的最长连续相同bit长度。这也是为什么很多标准强制规定线路编码必须有游程限制因为这不是理论洁癖是工程里真会炸的问题。排查这类问题有个实用技巧如果你怀疑是编码相关问题先用伪随机码或者特定图案比如全0、全1、0xAA做压力测试。全0全1能暴露长串相同电平问题0xAA能暴露最高翻转频率问题伪随机码则更接近真实场景。哪个图案出错心里基本就有数了。7.2 选编码方式不能只盯着带宽另一个体会是很多人选编码只看带宽和实现复杂度忽略了误码率、抖动容限、EMI这些维度。比如曼彻斯特带宽翻倍但抗干扰强、实现极简8B/10B开销大但直流平衡好64B/66B效率高但对锁相环要求高。没有绝对的“最优编码”只有最适合当前应用场景的编码。搞清楚每个编码解决了什么问题、引入了什么问题比背下每一个编码表有价值得多。实际项目里我建议先把链路最恶劣的情况列出来最长的连续相同bit是多少、有没有交流耦合、对误码率的容忍度是多少、成本预算允许多复杂的编解码逻辑。把这些约束摆出来选型往往一下子就清楚了。最后分享一个排查编码问题的土办法手工把数据喂给发送端用示波器一bit一bit地对比编码后的波形。工作正常后再引入干扰源、改变线长、调节温度看看哪个环节先扛不住。这套流程虽然慢但能让你对编码的本质理解得特别扎实。编码方式这堂课说到底不是在背规则而是在理解物理层做事的逻辑。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价