4、Modbus协议详解(上):从诞生到基础帧结构

各位同学,今天我们来聊聊Modbus协议。说实话,这个协议在工业现场的地位,就像普通话在中国人日常交流中的地位一样——你可能觉得它不够时髦,但离了它还真不行。

我最早接触Modbus是在2008年,那时候调试一台进口的温控仪表。设备手册上写着"支持Modbus RTU",我当时还纳闷:这玩意儿到底是个什么协议?后来踩了不少坑,才慢慢摸透了它的脾气。

4.1 Modbus协议发展史

Modbus协议诞生于1979年,由Modicon公司(就是现在的施耐德电气)提出。你想想看,那是40多年前的事了。那时候互联网还没普及,个人电脑还是稀罕物,但工业现场已经需要一种简单可靠的通信方式了。

为什么Modbus能活这么久?说白了就三个字:够简单

  • 1979年:Modicon发布Modbus协议,最初用于PLC之间的通信
  • 1990年代:随着自动化设备普及,Modbus成为事实上的工业标准
  • 2004年:Modbus组织正式成立,协议进入标准化管理阶段
  • 至今:Modbus TCP、Modbus RTU、Modbus ASCII三种变体并存

核心观点:Modbus之所以长寿,不是因为它技术多先进,而是因为它足够简单、足够开放。任何厂家都可以免费使用,没有任何专利壁垒。

我记得有一次,客户要求把一台2005年出厂的西门子PLC和一台2020年的变频器连起来。我本来以为要折腾半天,结果发现两边都支持Modbus RTU,直接两根线一接,配置几个参数就搞定了。这就是Modbus的生命力——向下兼容,向上扩展

4.2 Modbus RTU帧格式

RTU模式是Modbus最常用的传输模式。它的帧结构非常紧凑,适合在RS-485等串行线路上传输。

一个完整的Modbus RTU帧长这样:

| 地址码 | 功能码 | 数据区 | CRC校验 |
| 1字节  | 1字节  | N字节  | 2字节   |

咱们拆开来看:

  • 地址码(1字节):设备地址,范围1-247。0是广播地址,所有设备都会接收但不回复
  • 功能码(1字节):告诉设备要干什么,比如读线圈、写寄存器
  • 数据区(N字节):具体的数据内容,长度取决于功能码
  • CRC校验(2字节):循环冗余校验,确保数据在传输过程中没出错

实战经验:我刚开始写Modbus驱动时,经常遇到通信时好时坏的情况。后来发现是CRC计算错了。记住:CRC校验是Modbus RTU的命根子,算错一个字节,整个帧就废了。

这里有个关键点:帧与帧之间要有至少3.5个字符时间的静默间隔。如果间隔太短,接收端会把两帧当成一帧处理。我在项目里见过有人把这个参数设错了,结果数据全乱套了。

4.3 Modbus ASCII帧格式

ASCII模式是RTU的"老大哥",它用可读的ASCII字符来传输数据。虽然效率低,但在某些场景下反而更稳定。

ASCII帧格式:

| 起始符 | 地址码 | 功能码 | 数据区 | LRC校验 | 结束符 |
| 1字节  | 2字节  | 2字节  | N字节  | 2字节   | 2字节  |
| ':'    | 十六进制ASCII | 十六进制ASCII | 十六进制ASCII | 十六进制ASCII | CR+LF |

你看,每个字节都被拆成了两个ASCII字符。比如地址0x01,在ASCII模式下就变成了字符'0'和'1'(即0x30和0x31)。

ASCII模式的好处是:

  • 数据可读性强,调试时直接用串口助手看文本就行
  • 帧边界清晰,有明确的起始和结束符
  • 对时序要求没那么严格

但缺点也很明显:传输效率只有RTU的一半。同样发100个字节,RTU只要100个字节,ASCII要200个字节再加额外开销。

避坑指南:我曾经在一个项目中,因为通信距离超过1000米,RTU模式老是丢包。后来换成ASCII模式,虽然速度慢了,但通信稳定多了。所以别一味追求速度,稳定才是工业现场的第一要义

4.4 功能码详解(01-06)

功能码是Modbus协议的核心。它告诉从站设备:你要干什么?下面我们逐个来看01到06这六个最常用的功能码。

4.4.1 功能码01:读线圈状态

读取从站的DO(数字量输出)状态。线圈就是继电器输出,只有0和1两种状态。

主站请求:01 01 00 00 00 0A BC D0
从站响应:01 01 02 CD 01 3A 9B

解释一下:地址01,功能码01,从地址0x0000开始读10个线圈。从站返回2个字节的数据(0xCD和0x01),共16个位,但只有前10位有效。

4.4.2 功能码02:读离散输入

读取从站的DI(数字量输入)状态。和01的区别是:02读的是输入,01读的是输出。

主站请求:01 02 00 00 00 08 79 CC
从站响应:01 02 01 0F 90 4B

4.4.3 功能码03:读保持寄存器

这是最常用的功能码。读取从站的保持寄存器,每个寄存器2个字节。

主站请求:01 03 00 00 00 02 C4 0B
从站响应:01 03 04 00 0A 00 14 7A 5C

这里读了2个寄存器,返回4个字节:0x000A(10)和0x0014(20)。

个人习惯:我调试设备时,90%的时间都在用功能码03。因为保持寄存器是设备参数的主要存储区,读懂了它,基本就摸清了设备的"脾气"。

4.4.4 功能码04:读输入寄存器

读取从站的AI(模拟量输入)值。和03的区别是:04读的是只读的输入寄存器,03读的是可读写的保持寄存器。

主站请求:01 04 00 00 00 01 31 CA
从站响应:01 04 02 01 F4 B8 3A

4.4.5 功能码05:写单个线圈

控制单个DO(数字量输出)的通断。数据区:0xFF00表示ON,0x0000表示OFF。

主站请求:01 05 00 00 FF 00 8C 3A
从站响应:01 05 00 00 FF 00 8C 3A

注意:从站响应和主站请求完全一样,这叫"回显确认"。

4.4.6 功能码06:写单个寄存器

写入单个保持寄存器的值。数据区2个字节,就是要写入的值。

主站请求:01 06 00 00 00 64 48 0A
从站响应:01 06 00 00 00 64 48 0A

这里把地址0x0000的寄存器写成了0x0064(100)。

实战技巧:写单个寄存器时,一定要确认写入的值在设备允许范围内。我曾经在调试变频器时,不小心把频率写成了500Hz(设备只支持0-400Hz),结果变频器直接报错停机。所以写操作前,先读一下设备手册的参数范围

4.5 本章知识体系

为了让大家更直观地理解Modbus协议的整体结构,我画了一张图:

Modbus协议知识体系 发展历史 帧格式 功能码 1979年 Modicon提出 1990年代 成为工业标准 2004年 标准化管理 RTU模式(二进制) ASCII模式(文本) 地址+功能码+数据+校验 01:读线圈 02:读输入 03:读保持 04:读输入 05:写线圈 06:写寄存器 核心要点 • 简单开放是Modbus的生命力 • RTU效率高,ASCII调试方便 • 功能码01-06覆盖80%的日常应用

嗯,这张图基本把本章的核心内容串起来了。从发展历史到帧格式,再到具体功能码,Modbus其实没那么复杂。你只要记住:地址、功能码、数据、校验,这四个要素构成了Modbus通信的"四梁八柱"。

最后说一句:学Modbus最好的方法就是动手。找两个支持Modbus的设备,或者用电脑上的Modbus模拟软件,亲自抓包看看数据长什么样。我当年就是这么学的,虽然走了不少弯路,但印象特别深刻。


公众号:蓝海资料掘金营,微信deep3321