刚入行那会儿看Modbus协议跟看天书似的。寄存器、线圈、CRC、MBAP头一个个名词堆上来脑子全是浆糊。后来发现不是这玩意儿难是市面上教程写得忒绕。今天按我自己的理解路子把Modbus从头捋一遍争取让刚接触的人看完就能上手抓包。一、先别碰代码搞清楚Modbus到底是个啥很多人一上来就翻代码看NModbus源码两眼一抹黑。正确姿势是先搞清楚三件事第一Modbus是应用层协议。它不管数据怎么从A传到B那是串口或者TCP的事。Modbus只规定数据长什么样、怎么问、怎么答。第二Modbus是主从模式。主站发问从站回答。从站从来不主动说话你问一句它答一句。这个设计简单粗暴但也意味着从站有问题主站不知道只能靠超时判断。第三Modbus只传16位整数。什么浮点数、字符串、32位整数全是后来人们想出来的歪招。Modbus底层只认0x0000到0xFFFF别的都不认。这三条搞明白心里就有底了。剩下的全是技术细节一个坑一个坑填就行。二、从一帧最简单的报文开始别上来就搞什么01读线圈、03读寄存器先看一帧最简单的请求长什么样。假设你要读从站地址为1的设备从地址0开始读2个保持寄存器。RTU发出去的报文是这样的text01 03 00 00 00 02 C4 0B拆开看01从站地址03功能码读保持寄存器00 00起始地址0x000000 02读2个寄存器C4 0BCRC校验就这么8个字节。你要是能对着这个报文把每一字节的含义说清楚Modbus就算入门了。设备回复的报文大概长这样text01 03 04 12 34 56 78 9A 3F拆开01从站地址03功能码04数据字节数4个字节表示2个寄存器12 34第一个寄存器的值56 78第二个寄存器的值9A 3FCRC看明白了吧主站问把0号和1号寄存器的值告诉我从站答0号是0x12341号是0x5678。就这么个对话简单到令人发指。三、功能码就记四个常用的Modbus功能码几十个实际干活就四个。功能码名称干啥用01读线圈读开关量输出比如继电器状态02读离散输入读开关量输入比如按钮状态03读保持寄存器读16位数据可读可写04读输入寄存器读16位数据只读03和04的区别03读的是PLC程序能改的数据04读的是传感器直接采上来的数据。温度变送器用04读温度值变频器用03读运行频率也写目标频率。另外两个写的功能码05写单个线圈开关06写单个寄存器16位0F写多个线圈10写多个寄存器够用了别的用上的概率极低。四、地址到底怎么算这事儿我专门拎出来说新手最头疼的问题手册说温度存在40001地址你发报文时起始地址填多少答案是填0x0000。40001是PLC厂家为了让人看懂搞的映射规则跟协议本身没有半毛钱关系。Modbus协议里地址就是0~65535没有前缀。具体的对应关系线圈地址对应PLC地址00001开始协议地址从0开始离散输入10001开始协议地址从0开始输入寄存器30001开始协议地址从0开始保持寄存器40001开始协议地址从0开始所以你看到手册写温度值存放在40001意思就是功能码用03协议起始地址填0x0000读1个寄存器。手册写40003那协议起始地址就是0x0002。协议地址 PLC地址 - 40001。就这么简单。有人非要杠为什么手册写40001而不是0别问问就是历史遗留问题记住换算规则就行。五、RTU和TCP到底啥关系很多人分不清RTU和TCP以为这俩是两套完全不同的协议。其实它们的关系就一句话TCP是RTU去掉了CRC、前面加了个MBAP头。看对比RTU请求text[地址][功能码][数据][CRC]TCP请求text[事务ID][协议ID][长度][单元ID][功能码][数据]相同颜色的部分功能码和数据完全一样。TCP把地址改叫单元ID把CRC砍了前面加7个字节的头部。所以只要你学会了RTU的报文格式TCP就是个加了个头的变种。反过来也一样把TCP报文去掉前7个字节、尾部加上CRC再算一遍就变成了RTU报文。两者传输的内容一样只是包装不同。理解了这个RTU和TCP在你眼里就是同一种东西的不同马甲。六、CRC到底要不要手算CRC-16-Modbus多项式0x8005初值0xFFFF。这个东西不学行不行行但要会用工具算。网上有在线CRC计算器填上数据点一下就能出结果。调试阶段用这个完全够用。等你真的需要写代码实现通信了直接从网上抄现成的CRC计算函数哪个都行别自己发明轮子。但有一点必须清楚CRC是低字节在前。算出来是0x1234发的时候先发0x34再发0x12。这地方搞反了CRC就算对了设备也不认因为它按约定顺序接收。七、动手抓一帧报文比看十遍书都管用这是最管用的一招。装个串口调试助手或者Modbus Poll连上一个设备发一个读寄存器的请求把收到的原始数据复制出来。然后对着每一字节分析第1字节是谁第2字节是什么功能码数据部分是哪些字节CRC是哪两个字节对着手册看一遍当场就通了。比你看一百页PDF来得都快。Modbus Poll这个软件特别好用作为主站可以发各种请求作为从站可以模拟设备响应。调试时用它发命令看设备回什么所有报文都显示在界面上。初期学习阶段花半小时玩这个软件比读三章协议文档都有用。八、常见错误我见过的翻车现场错误一串口参数没对上这是新手第一坑。9600 8 N 1是默认配置但不是所有设备都用这个。你设9600设备跑19200能通就见鬼了。拿到设备第一件事翻手册查串口参数页。错误二A/B线接反RS485有极性A接AB接B。接反了能收到乱码但CRC全错。示波器看一眼波形反了就是反的别侥幸。错误三从站地址填错设备地址设的是2你发请求填1设备不会理你。如果地址填0那是广播地址所有从站都收但不回复。错误四读的地址超限手册说保持寄存器范围40001~40010你发请求从40011开始读设备回异常码02非法地址。然后你怀疑程序写错了调了半天才想起来查手册。别问我怎么知道的。错误五一次读太多RTU单帧最多读125个寄存器读126个有些设备直接不回。TCP也差不多虽然没硬性限制但设备缓冲区就那么大。九、学习路线图按这个顺序来第一天搞明白Modbus是主从模式主问从答。看一帧报文长什么样能对着报文把每个字节的含义说清楚。第二天上手Modbus Poll软件连一个实际设备或者虚拟设备发读请求看回复。把功能码01、02、03、04都试一遍。第三天把RTU的CRC算一遍不用手算用工具算但要理解低字节在前。把RTU和TCP的报文格式对比着看找出相同点和不同点。第四天写代码。用C#或者Python串口通信把SerialPort整明白TCP通信把Socket整明白。先实现读寄存器再实现写寄存器别的慢慢加。第五天抓包调试。把自己代码发出去的报文和Modbus Poll发出去的报文对比看看哪里不一样。CRC对不上就调CRC地址对不上就调地址。按这个节奏走一周时间足够把Modbus用到项目里。十、不要被协议两个字吓住说穿了Modbus就是规定了对话格式。你问问题用一种格式对方回答用另一种格式来来回回就这么点事。复杂的地方不在协议本身在现场环境。干扰、接线、参数配置、设备故障、厂家不按标准来这些才是真正消耗时间精力的地方。所以学习阶段别有压力。会看报文、会算CRC、会发请求这就叫学会了。至于现场那些幺蛾子那是经验的活儿遇到了再解决解决一次就记住了。抓包抓包抓包重要的事情说三遍。你手里有Wireshark和串口监听工具就没有查不出来的问题。