通信协议:那些让硬件“说话“的规则
通信协议那些让硬件说话的规则硬件工程师每天都在和协议打交道——调SPI、写驱动、配CAN报文。但很多人对协议的理解停留在查手册配寄存器层面没有建立起系统感。这篇文章试着把这个系统搭起来从最基本的01怎么传一直讲到为什么你的Modbus通信就是不稳定。一、先搞清楚几个基础概念协议栈为什么要分层分层不是学术产物是工程上的务实选择。┌────────────────────────────────────────────────────┐ │ 应用层 (Application) │ ← 你写的代码在这一层 │ HTTP、MQTT、Modbus、DNP3、SMTP │ ├────────────────────────────────────────────────────┤ │ 传输层 (Transport) │ │ TCP / UDP │ ├────────────────────────────────────────────────────┤ │ 网络层 (Network) │ │ IP │ ├────────────────────────────────────────────────────┤ │ 数据链路层 (Data Link) │ │ Ethernet MAC、PPP、CAN、LIN │ ├────────────────────────────────────────────────────┤ │ 物理层 (Physical) │ ← 电压/电流/光/射频 │ RS-485差分、LVDS、SGMII、PAM-4 │ └────────────────────────────────────────────────────┘每一层只关心自己的事应用层不管数据怎么被切成帧物理层不管你传的是温度值还是视频帧。分层的好处是改动某一层不影响其他层——你换掉物理层的PHY芯片上层代码不用动。封装从应用到电信号数据从应用层下到物理层每经过一层都要加个包。理解这个过程比死记硬背OSI七层有用得多。应用层: ┌──────────────────┐ │ 温度: 25.3℃ │ ← 原始数据 └──────────────────┘ ↓ 加上层头 传输层: ┌───┬──────────────┐ │TCP│ 温度: 25.3℃ │ ← 加了Src/Dst Port, Seq# └───┴──────────────┘ ↓ 加上层头 网络层: ┌────┬───┬──────────┐ │ IP │TCP│ 温度数据 │ ← 加了Src/Dst IP └────┴───┴──────────┘ ↓ 加上层头 校验 链路层: ┌──────┬────┬───┬───┬────────┐ │Ethernet│ IP │TCP│ 数据 │ CRC │ ← MAC头帧尾 └──────┴────┴───┴───┴────────┘ ↓ 编码 调制 物理层: ███0█ ██0 ████████ 101110... ← 最终的01流解封装的过程正好相反对端从下往上拆包读取。同步你得知道位从哪里开始数字通信里同步是根本问题。接收端必须知道每个bit的起止时刻否则收到的就是一堆乱码。两种基本同步方式异步通信每字节单独同步用起始位和停止位标识边界。空闲 起始 D0 D1 D2 D3 D4 D5 D6 D7 停止 空闲 1 0 1 0 1 1 0 0 1 0 1 1 ──────┐ ┌───┐ ┌───┐ │ │ │ │ │ ──────┘ └───┴───┴───┴───┴───┴───┴───┴───┴───────┘ └─── ──────── 1 byte (8N1) ─────────这是UART的方式。优点是简单缺点是双方波特率必须精确匹配一般允许±2%以内而且每字节有10~11位的额外开销。同步通信用单独的时钟线或者把时钟编码进数据流里。SPI、I2C是典型例子后面会详细讲。二、物理层电压、电流、光——01到底怎么传差分信号的好处长距离传输和工业环境里差分信号几乎是唯一选择。单端信号比如TTL的0~3.3V抗共模干扰能力很差线缆上捡到的干扰会直接叠加在有用信号上。差分信号用两根线传输互为反相的电平单端传输 差分传输 (RS-485) ┌─────────────┐ A线: ┌─────────────┐ │ Signal │ 干扰 A ──┤ ├─ B (反相) │ 0V ────────┼── 噪声 ─→ │ Signal │ └─────────────┘ B线: └─────────────┘ 接收端看到: Signal Noise 接收端: (A - B) Signal 2×Noise → 噪声直接叠加 → 共模噪声被消除RS-485/422、CAN、以太网物理层都是差分方案。RS-485规定 A-B 压差 200mV 为逻辑1 -200mV 为逻辑0共模电压范围是 -7V ~ 12V可以承受很大的地电位差。为什么高速信号要用阻抗匹配当信号上升沿时间tr小于等于走线长度的电磁延迟时导线就变成了传输线t_r ≥ 2 × L_prop ← 不需要匹配常规PCB走线 t_r 2 × L_prop ← 变成传输线必须端接典型FR4 PCB信号传播速度约 15cm/ns。上升沿1ns的信号在1.5cm以上的走线上就需要考虑阻抗连续性了。无匹配 有匹配 源 ──→ 线 ──→ 开路负载 源 ──→ 线 ──→ Z₀ 端接 ↓ ↘ Z₀ (串联) 第一次反射(正) → 线内往复 → 一次吸收无反射 眼图完全闭合 眼图清晰不做匹配高速信号会在接收端产生多次反射导致振铃、过冲、眼图闭合——通信可靠性无从谈起。三、串行外设协议嵌入式工程师的基本功UART最简单的点对点通信UARTUniversal Asynchronous Receiver/Transmitter几乎每个MCU都有。配置项就三个波特率、数据位5~9位、校验位无/奇/偶。典型应用GPS模块、蓝牙HC-05模块、串口调试口。缺点是全双工最多一对一的总线没有地址概念不能多个设备挂同一总线上。MCU GPS模块 ────────────────────────────────────────── TX ────────────────────────────────────── RX RX ←───────────────────────────────────── TX GND ──────────────────────────────────── GND布线的坑如果需要长距离1米传输TTL电平 UART强烈建议加电平转换成RS-232或RS-485。TTL直接拉长线信号完整性会出严重问题。很多工程师遇到串口时好时坏的问题最后发现就是长线传输导致的。SPI高速同步的首选SPISerial Peripheral Interface用四根线实现全双工同步通信┌─────────────────────┐ MOSI ────→│ │←─── MISO SCK ────→│ 主设备 (Master) │───→ MOSI │ │ SS1 ────→ │ │←─── SS1 SS2 ────→ │ │←─── SS2 └─────────────────────┘ MOSI: Master Out Slave In (数据从主机发出) MISO: Master In Slave Out (数据从机发出) SCK: 时钟信号 (主机产生) SS: 片选信号 (主机控制可多选)时钟极性CPOL和相位CPHA决定数据采样时刻SPI有四种组合方式接错就会通信失败CPOL0, CPHA0: SCK空闲0, 上升沿采样 CPOL0, CPHA1: SCK空闲0, 下降沿采样 CPOL1, CPHA0: SCK空闲1, 下降沿采样 CPOL1, CPHA1: SCK空闲1, 上升沿采样所以当你换了一个新的SPI FLASH芯片首先去查datasheet里的CPOL/CPHA配置而不是假设默认值能用。SPI的吞吐率可以很高——STM32的SPI最高支持 50MHz 时钟16bit宽度理论速率接近 100Mbps。实际工程中 10MHz 的SPI信号需要做好以下事情 impedance-matched 走线常见50Ω或差分100Ω、尽量短的走线、在SS和SCK信号上串联22Ω~47Ω阻尼电阻减少振铃。I2C两线解决多设备问题I2CInter-Integrated Circuit只用两根线SCL SDA挂多个设备靠设备地址区分。这在板内传感器、EEPROM、RTC等场景里是标准选择。VCC (上拉电阻 4.7k~10kΩ) ↑ SCL ────────────●────────●────────●────── │ │ │ SDA ───────────●────────●────────●────── │ │ │ [EEPROM] [IMU传感器] [RTC芯片] 地址 0x50 地址 0x68 地址 0x68I2C是开漏结构 弱上拉总线上所有设备只能拉低电平不能主动输出高电平。这样做的好处是任何一个设备故障拉死总线其他设备还能正常工作。坏处是上拉电阻的选择很讲究——太大10kΩ上升沿太慢高速模式400kHz用不了太小1kΩ灌电流太大低功耗场景不合适。I2C的坑总线空闲时两根线必须都是高电平。如果某个设备死机把SDA或SCL拉低了整个总线就锁死所有设备都无法通信。标准做法是在程序里做总线恢复手动模拟时钟脉冲把卡住的数据位吐出来。正常通信帧: START → 地址R/W → ACK → 数据 → ACK → STOP S ADDR N P 地址格式: ┌─────┬────────┬─┬────────┐ │ 7位设备地址 │R/W│ ACK │ └─────┴────────┴─┴────────┘CAN总线工业和汽车的主流选择CANController Area Network解决的是多设备、高可靠、抗干扰场景下的实时通信问题。汽车几乎所有ECU之间的通信都用CAN工业现场总线也很常见。CAN的两根线CAN_H / CAN_L是差分总线逻辑用显性dominant和隐性recessive描述——而不是简单的高或低。这意味着多个节点同时发数据时显性位会覆盖隐性位这是CAN总线仲裁的基础。CAN_H ──────────── 3.5V (隐性) / 2.5V~3.5V (显性) CAN_L ──────────── 1.5V (隐性) / 0.5V~1.5V (显性) ↓ 差分电压: 0V (隐性) / 1.5V~2.0V (显性)CAN的帧格式┌──────┬────┬─────┬────────────┬─────┬────┬─────┐ │ SOF │ID │RTR │ DLC │DATA │CRC │ ACK │ │ 1bit │11bit│1bit│ 4bit │0~8B │15bit│2bit │ └──────┴────┴─────┴────────────┴─────┴────┴─────┘ 帧起始 标识符(优先级)标识符ID不只是地址它还代表消息的优先级。ID越小优先级越高。这在汽车碰撞信号优先于车窗控制信号的场景里是硬性需求。CAN的位时序是很多人忽视的细节。CAN控制器把每个位时间分成多个段Sync_Seg、Prop_Seg、Phase_Seg1/2采样点位置在这些段之后。位时序配置错了轻则通信不稳重则整个总线挂掉。125kbps500kHz时钟和500kbps8MHz时钟的配置方式完全不同需要参考ISO 11898的规定计算。四、现场总线与工业协议工厂里怎么通信Modbus古老但依然活着Modbus 1979年由Modicon发明是工业自动化领域最老也是最普及的协议。没有版权壁垒、实现简单、文档详尽——这三个原因让它在各种PLC、变频器、仪表里存活了四十多年。Modbus RTU最常用基于RS-485物理层帧结构简洁┌──────┬──────────┬──────┬────────┬──────┬───────┐ │ 从机地址 │ 功能码 │ 数据 │ CRC16 │ │ │ 1字节 │ 1字节 │ N字节 │ 2字节 │ │ └──────┴──────────┴──────┴────────┴──────┴───────┘ 从1~247 03读保持寄存器 06写单个寄存器 10写多个寄存器读一个温度传感器值的过程主机发送[01] [03] [00 00] [00 01] [C4 0B]地址01读寄存器0x0000数量1从机应答[01] [03] [02] [09 A4] [?? ??]数据0x09A4 2476即24.76°C乘以0.01系数Modbus为什么通信不稳定常见原因终端电阻缺失RS-485总线两端必须接120Ω终端电阻。不接远距离传输时信号反射严重数据乱跳。上拉/下拉缺失RS-485总线空闲时处于不确定状态需要A/B线之间加120Ω上拉下拉偏置电阻让空闲时接收器能稳定识别隐性电平。波特率不匹配双方波特率差值超过5%CRC校验会大量失败。接地问题总线和设备之间的地电位差超过几伏差分信号会被破坏。EtherCAT高速运动控制传统现场总线Profibus、DeviceNet速率多在1Mbps以下无法满足高速运动控制的需求。EtherCATEthernet for Control Automation Technology用一种巧妙的方式在标准以太网硬件上实现了近乎零延迟的实时通信。传统以太网: 交换机存储转发延迟不确定 帧到交换机 → 存储 → 查表 → 转发 延迟 ~ 几十μs EtherCAT: 主站发一帧所有从站串行处理 帧经过从站1 ──→ 处理并转发 ──→ 从站2 ──→ ... 每个从站芯片内部读取自己对应的数据延迟约 1μsEtherCAT的每个从站芯片在数据帧经过时直接用硬件处理自己的那部分数据FMMU映射不用CPU干预抖动可以低到 1μs。1000个I/O点的刷新周期可以做到 100μs。这在半导体贴片机、飞拍视觉系统里是不可替代的优势。五、无线协议不同的距离、功耗、速率权衡无线协议选型本质上是三个维度的权衡高速率 ↑ WiFi │ 5G/LTE │ BLE 5 │ Ethernet │ │ ────────→ 低功耗 │ LoRa │ Sigfox │ NB-IoTBLE短距离低功耗的王者BLEBluetooth Low Energy的协议栈比传统蓝牙Classic Bluetooth简化得多┌──────────────────────────────────────┐ │ 应用层 (GATT/ATT) │ ← 定义数据结构和读写方式 ├──────────────────────────────────────┤ │ 安全管理层 (SM) │ ← 配对、加密 ├──────────────────────────────────────┤ │ 通用属性配置文件 (GATT) │ ← 把数据组织成 Service/Characteristic ├──────────────────────────────────────┤ │ 主机协议层 (GAP) │ ← 连接建立、广播 ├──────────────────────────────────────┤ │ 控制器 (Link Layer) │ ← 物理射频、基带 └──────────────────────────────────────┘BLE 5.0引入了2M PHY物理层速率提升到2MbpsBLE 4.2只有1Mbps。长距离模式LE Coded PHY宣称传输距离可达300米以上实际在空旷环境下100米左右问题不大穿墙就另说了。BLE的连接参数连接间隔、从机延迟对功耗影响极大。连接间隔越短延迟越低但功耗越高间隔越长功耗越低但数据更新慢。有些BLE设备能靠两颗纽扣电池工作两年靠的就是把连接间隔设到500ms以上。LoRa远距离、低速率、低功耗LoRaLong Range用扩频技术把信号扩展到很宽的带宽上在信噪比极低的情况下依然能正确解调。这让它在-130dBm的信号强度下还能通信——比手机的接收灵敏度还要低几十倍。LoRaWAN是LoRa的MAC层协议定义了设备入网、数据加密、Class A/B/C终端分类等机制。国内常用的频段是470510MHz抄表频段和779787MHz。LoRa 关键参数: SF (扩频因子) 展宽码长度 SF7: 速率快距离近灵敏度约 -124dBm SF12: 速率慢距离远灵敏度约 -137dBm 带宽 (BW): 125kHz / 250kHz / 500kHz 编码率 (CR): 4/5 ~ 4/8越高越抗干扰但有效速率越低 理论距离公式: 路径损耗 32.44 20×log(f) 20×log(d) f 频率(MHz), d 距离(km) 在城市环境需额外加 20~40dB 的损耗余量LoRa在建筑密集的城市环境里实际距离往往只有宣称值的1/5~1/10在空旷农村或海面可以远超宣称值。选型时要对实际部署环境做充分测试。六、协议设计的基本问题理解现有协议是基础但如果你需要自己设计一个通信协议下面几个问题必须想清楚。帧结构定长还是变长定长帧解析简单但浪费带宽。变长帧更紧凑但需要明确的边界标识。定长帧 (示例CAN): ┌──────┬────┬────┬────┬──────────┬────┬────┐ │ SOF │ID │DLC │DATA(固定≤8B)│CRC │ACK │ └──────┴────┴────┴────┴──────────┴────┴────┘ 每帧长度固定解析器按偏移量取值 变长帧 (示例以太网): ┌──────┬─────────┬─────────┬───────┬──────────┬────────────┐ │Preamble│ Dest MAC │ Src MAC │ Length │ Data... │ CRC │ │ 7B │ 6B │ 6B │ 2B │ 46~1500B │ 4B │ └────────┴─────────┴─────────┴───────┴──────────┴────────────┘ 通过Length字段告诉接收端Data有多少字节校验与纠错检错还是纠错CRC循环冗余校验是链路层最常用的检错手段。对于 n 位 CRC未检出错误概率约 1/2ⁿ。32位CRC的未检出概率是约 1/42亿足够应对大多数场景。但CRC只检错不纠错。纠错码ECC需要额外的冗余位开销在存储和部分无线通信里有价值但在大多数有线工业协议里检错重传是标准做法。CRC-32 (以太网, ZIP, PNG): 生成多项式: 0x04C11DB7 未检出错误概率: ~2.4×10⁻¹⁰ CRC-16 (Modbus, USB, CAN): 生成多项式: 0x8005 (CRC-16-ANSI) 未检出错误概率: ~1.5×10⁻⁵ 选哪个? 高可靠场合用CRC-32嵌入式/工业场合用CRC-16足矣。重传机制ARQ协议自动重传请求ARQ有三种基本模式Stop-and-Wait ARQ: 发一帧 → 等ACK → 下一帧 简单但效率低信道利用率 50%往返延迟大于帧传输时间时 Go-Back-N: 发送窗口N帧不用等每帧ACK 收到NACK或超时从错误帧重发窗口内所有帧 Selective Repeat: 只重发出错的帧不重发正确帧 效率最高但接收端需要缓存和排序逻辑TCP用的是改进版的Selective Repeat窗口更大。但在资源受限的嵌入式系统里Stop-and-Wait是合理选择——代码简单RAM占用少。字节序大端还是小端跨平台通信必须统一字节序。约定俗成的选择网络字节序: 大端序 (Big Endian) ← TCP/IP协议栈规定 x86/x64: 小端序 (Little Endian) ARM: 可配置大多数场景配置为小端 32位数 0x12345678 在内存中的存放: 大端: 12 34 56 78 ← 高字节在前 小端: 78 56 34 12 ← 低字节在前Modbus规定寄存器16位为大端序。不同厂家PLC对接时如果字节序没对齐读出来的数值会是错的——0x1234会变成0x3412。七、调试协议问题的排查方法抓包是根本对于以太网和USB等高速协议用Wireshark 硬件抓包网卡。Wireshark能看到每层协议的封装直接找到数据链路层的问题。Wireshark 中的协议解析: Frame 14: 74 bytes on wire, 74 bytes captured └─ Ethernet II, Src: STMicro_xx:xx:xx, Dst: Espressif_xx:xx:xx └─ Internet Protocol Version 4, Src: 192.168.1.100, Dst: 192.168.1.1 └─ User Datagram Protocol, Src Port: 3333, Dst Port: 8888 └─ Data (12 bytes) 0x01 0x00 0x00 0x00 0x4D 0x00 ...逻辑分析仪嵌入式协议的标配SPI/I2C/CAN/UART的调试示波器不够用逻辑分析仪才是正确的工具。Saleae现Digitalo Probe和梦源逻辑是常见选择。逻辑分析仪抓I2C通信: 时钟 ──→ _‾‾‾_‾‾‾_‾‾‾_‾‾‾_‾‾‾_‾‾‾_‾‾‾_‾‾‾_ 数据 ──→ START 0x68W ACK 0x00 ACK ... 触发设置: 找到 地址0x68 且 R/W0 的 START 条件 就能定位到特定设备的通信窗口花200块买一个8通道逻辑分析仪能解决你80%的嵌入式通信调试问题。别省这个钱。CAN调试的特殊性CAN的问题排查需要专门的CAN分析仪PCAN、CANalyst、ZLG盒。普通示波器看不了CAN总线——CAN_H/CAN_L的差分信号瞬态速度很快模拟示波器根本抓不住。CAN总线正常波形示意: 隐性: CAN_H 2.5V ──────────────── CAN_L 2.5V ──────────────── → 差分 0V 显性: CAN_H 3.5V ─────── CAN_L 1.5V ─────── → 差分 2.0V 常见故障现象: - 波形顶部削顶 → 总线阻抗不匹配反射严重 - 眼图不对称 → 线缆质量差信号质量差 - ACK错误频繁 → 终端电阻配置错误或总线负载过重结语协议这东西说到底是人和机器都要遵守的约定。人这一侧要读得懂手册、配得对参数、查得出问题机器那一侧要跑得通逻辑、守得住时序、不出边界错误。大多数协议问题本质上都出在这几个地方物理层信号质量不够阻抗、终端、线缆、参数配置不匹配波特率、位时序、字节序、状态机处理有漏洞超时、重传、错误恢复。掌握这三个方向大多数协议调试工作都能有条不紊地推进。下一步建议找一款你最常用的协议WIFI/BLE/CAN/SPI/I2C把它的RFC文档或datasheet认认真真读一遍比看十篇博客有用。本文适合硬件工程师、嵌入式工程师、IoT开发者和需要对通信协议有系统性理解的读者。具体实现请以器件原厂手册为准。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2475692.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!