Modbus 学习笔记(第一部分)通信协议基础知识

你好,欢迎来到 Modbus 学习的第一站。

这一部分我们不写一行代码,只做一件事:把 Modbus 协议的”底层逻辑”彻底讲明白。为什么要先学这些?因为后面你要写的串口助手、数据看板,本质上都是在”按照 Modbus 的规矩发消息、收消息”。规矩没弄懂,代码写得再顺也是稀里糊涂的。

我会尽量用大白话和生活中的例子来讲,每一个新概念都从一个具体的问题出发。你不用一次全部记住,跟着我一步步往下走就行。遇到看不懂的地方,停下来读两遍,再继续。


1.1 Modbus 协议背景及发展历程

1.1.1 先搞清楚一件事:什么是通信协议

在讲 Modbus 之前,我们先花一分钟解决一个更根本的问题:两台设备之间,是怎么"说话"的?

打个比方。两个人打电话,要能听懂对方,必须事先约好三件事:

  1. 用什么语言(都说中文,还是都说英语);
  2. 先说什么、后说什么(是”喂你好”开头,还是直接说正事);
  3. 说完一句怎么表示自己说完了(是停顿一下,还是说一句”完毕”)。

如果没有这些约定,一个人说中文、一个人说英语,或者两个人抢着说,通话就乱套了。

设备之间通信也是一模一样的道理。设备不会像人一样自由发挥,它们必须遵守一套非常死板的”规矩”,这套规矩就叫通信协议(Protocol)

通信协议规定了设备之间交换数据时的统一格式,包括:

  • 数据长什么样(一条消息由哪些部分组成);
  • 谁先说话、谁后说话(通信的先后顺序);
  • 怎么判断对方说的话是不是完整的、有没有传错。

有了协议,不同厂家、不同型号的设备,只要都遵守同一套协议,就能互相听懂。这就是协议存在的意义。

1.1.2 PLC 是什么

你可能已经听说过 PLC,这里用最简单的话解释一下。

PLC 全称是”可编程逻辑控制器”(Programmable Logic Controller),你可以把它理解成工业现场的一台”小电脑”。它专门负责控制机器干活,比如控制电机转不转、阀门开不开、传送带快还是慢。

工控现场的实际情况是:往往有很多台 PLC 分散在不同的地方,它们需要互相交换数据。比如一号 PLC 检测到温度超标了,要通知二号 PLC 赶紧打开冷却风扇。这个时候,就迫切需要一套统一的通信方法,让这些 PLC 能”互相打电话”。

1.1.3 Modbus 的诞生

  • 发明公司:Modicon(中文音译”莫迪康”),后来这家公司被 Schneider(施耐德)收购,所以现在 Modbus 归施耐德。
  • 命名:Modbus 这个名字是拼出来的,Mod 取自 Modicon 公司的名字,bus 就是”总线”的意思,合起来就是”Modicon 公司的总线协议”。
  • 诞生时间:第一台 PLC 诞生于 1969 年,Modbus 协议诞生于 1979 年。

这里有个很有意思的背景:1979 年的时候,工业通信还没有一个大家都认可的标准,各家公司各搞各的,A 家的 PLC 没法跟 B 家的 PLC 说话,客户买了谁家的设备就被谁家绑死了。Modicon 公司为了解决这个痛点,发明了 Modbus 协议,专门用来让 PLC 控制器之间能够互相通信。

1.1.4 Modbus 协议的特点

Modbus 之所以能活到今天、用得这么广,靠的是三个特点:

第一个特点:免费。

Modbus 协议是公开免费的,任何人都可以下载它的规范文档,任何人都可以照着实现,不需要交专利费、授权费。这一点非常关键。想想看,如果一个协议要收钱,厂家就不愿意用;免费的协议,厂家随便用,用的人就越来越多,最后就成了事实上的标准。

第二个特点:简单。

Modbus 的报文(也就是设备之间发的那条消息)非常短小、非常紧凑,格式一目了然。对用户来说容易看懂,对设备厂家来说容易实现(哪怕是一块很便宜的单片机,也能轻松跑 Modbus)。简单,意味着门槛低,也意味着稳定、不容易出错。

第三个特点:接口多样,不挑传输介质。

Modbus 是一个应用层协议。这句话可能有点抽象,我用寄快递来打比方:

快递包裹里装的东西(信件内容)是”应用层”,而运送包裹的交通工具(汽车、火车、飞机、轮船)是”传输层”。信件内容写好了,用哪种交通工具送都可以。

Modbus 就是那个”信件内容”。它可以跑在串口上(RS232、RS485、RS422),也可以跑在以太网上,还可以跑在光纤、蓝牙、无线等各种各样的通信介质上。换一种”交通工具”,Modbus 的内容格式基本不变。这种”不挑介质”的特性,让它能适应各种各样的工业现场。

1.1.5 协议总结

这一节最后,我们把最核心的一句话记住:

协议,本质上就是设备或控制器之间交换数据的一套自定义规矩。

很多人一听”标准协议”就觉得高大上、神秘。其实 Modbus 当年也就是 Modicon 公司自己定义的”自定义协议”,只不过因为它免费、简单、好用,用的人越来越多,慢慢就成了整个行业公认的”标准协议”。

所以,你完全不需要敬畏它。它就是一个几十年前定下来的、现在大家都在用的”通信规矩”。搞懂了它,将来学其他协议,套路其实都差不多。

1.1.6 我们为什么要学它

  • 在工控领域,Modbus 的使用极其广泛,几乎所有 PLC、仪表、传感器都支持 Modbus,学上位机绕不开它。
  • 要写好上位机程序(比如用 C# 写一个采集软件),必须理解协议底层知识,不然你连”该发什么字节、收到的是什么意思”都说不清。
  • Modbus 是最容易入门的工业协议,把它作为基础,之后再去学别的协议(比如西门子的 S7 协议、OPC 等),你会轻松很多。

1.2 Modbus 调试软件安装使用

1.2.1 学习过程中要用到的几个软件

学 Modbus,光看文字是学不会的,一定要”亲眼看到报文、亲手收发数据”。所以我们需要几个调试软件来配合。常用的有这么几个:

软件 作用
Modbus Poll 充当 Modbus 主站(也叫 Modbus 客户端),主动发起请求
Modbus Slave 充当 Modbus 从站(也叫 Modbus 服务器),被动响应请求
VSPD 虚拟串口软件,可以在电脑里虚拟出一对串口,用来做串口通信实验
串口调试助手 查看和收发串口数据
网络调试助手 查看和收发网络(TCP/UDP)数据

1.2.2 先理解一对最重要的概念:主站和从站

这是整个 Modbus 学习里最基础、也最重要的一对概念,一定要先吃透。

Modbus 通信中,设备分为两种角色:

主站(Master),也叫客户端(Client)。

主站是"主动发起对话"的一方。它负责提出问题,比如"把你第 100 号寄存器的数据告诉我"。在 Modbus 里,一次通信总是由主站先开口的。

从站(Slave),也叫服务器(Server)。

从站是”被动回答问题”的一方。它平时不说话,只有当主站问它的时候,它才回答。

用生活中的例子来理解:

主站像一个领导,从站像一个员工。领导不开口,员工是不会主动汇报的;领导问一句,员工答一句。这就是 Modbus 的通信方式,专业上叫”主从模式”。

注意这两个叫法的对应关系,很多资料会混着用,你看到时要知道它们说的是同一个东西:

  • 主站 = Master = 客户端 = Client;
  • 从站 = Slave = 服务器 = Server。

再举一个具体的例子。你电脑上装一个 Modbus Poll 当主站,再装一个 Modbus Slave 当从站,让它们俩通信。整个过程就是:

  1. Modbus Poll(领导)问:”1 号从站,把你第 1 个保持寄存器的值告诉我。”
  2. Modbus Slave(员工)回答:”我第 1 个保持寄存器的值是 42。”
  3. Modbus Poll 收到答案,显示在界面上。

这一个小实验,就是 Modbus 通信最核心的流程,后面的一切都是在这个基础上加东西。

1.2.3 三个名词:串口、虚拟串口、网络

串口(Serial Port)

串口是一种很古老但工业上极其常用的通信接口。你电脑后面或者 USB 转串口线出来的那种口,就叫串口。串口通信的特点是:一次只传一个比特位,一个接一个地传(所以叫”串”口)。

串口下又分几种标准,最常用的是 RS232、RS485、RS422。它们的主要区别在传输距离和接线方式上,协议层的 Modbus 内容是一样的,现在你只需要知道”串口是 Modbus 常用的一种传输介质”就够了。

虚拟串口(VSPD 软件的作用)

做实验的时候有个小麻烦:真实的串口通信需要两台设备、两根线连起来,你电脑上可能没有那么多真实串口。

VSPD(Virtual Serial Port Driver)这个软件就是来解决这个问题的。它能在你的一台电脑上”凭空造出”一对串口(比如 COM3 和 COM4),并且让这两个串口”背靠背”连在一起:从 COM3 发出去的数据,COM4 能收到;反过来也一样。

这样一来,你不需要任何真实硬件,就能在电脑上做串口通信实验。比如让 Modbus Poll 打开 COM3,让 Modbus Slave 打开 COM4,它们就能通过这对虚拟串口互相通信了。

网络(以太网 TCP/UDP)

除了串口,Modbus 也能跑在以太网上(就是普通的网线、局域网、互联网)。这时通信靠的是网络协议 TCP 或 UDP。网络调试助手就是用来收发这种网络数据的工具。

1.2.4 这些软件分别怎么用(先有个印象)

这里先给你一个整体的使用思路,等后面真正做实验时,我会手把手带你操作:

  • 做”串口 Modbus”实验:用 VSPD 虚拟出一对串口,Modbus Poll 连其中一个,Modbus Slave 连另一个,两端都用 Modbus RTU 模式。
  • 做”网络 Modbus”实验:Modbus Poll 用 TCP 模式连到 Modbus Slave 的 IP 和端口,直接在局域网里收发。
  • 想直接看底层报文长什么样:用串口调试助手(或网络调试助手)以十六进制方式显示收发的原始字节。

现在你不需要真的去装,只要先记住这几个软件是干嘛的就行。等我们进入实操环节,我会一步一步带你装、带你点。


1.3 Modbus 协议存储区说明

这一节讲的是:数据在设备里到底放在哪里。

1.3.1 通信的本质是数据交互

先想一个问题:两台设备通信,到底在”通”什么?

答案很简单:数据。主站问从站要数据,从站把自己的数据报给主站;主站也可以下命令,让从站的数据发生变化。所以通信的本质,就是数据的交换

那数据存在哪里呢?存在设备的”存储区”里。这个概念,如果你接触过 PLC,一定不陌生。PLC 里有各种软元件,比如:

  • X 表示输入点;
  • Y 表示输出点;
  • M 表示中间继电器(内部标志位);
  • D 表示数据寄存器。

这些 X、Y、M、D,其实就是 PLC 内部的一块块”存储区”。通信的时候,就是从这些存储区里读出数据,或者往这些存储区里写入数据。

Modbus 也是一样的思路。它把设备内部的存储空间,划分成了几个不同的”区域”,每个区域有固定的编号和用途。下面我们就来认识这几个区域。

1.3.2 先搞懂两个基本概念:线圈 和 寄存器

在讲存储区之前,有两个词必须先弄懂,因为整个 Modbus 的数据都是靠它们来区分的。

线圈(Coil)

线圈是”位”类型的数据,也就是说,它只有两种状态:开(1) 或者 关(0)。你可以把它理解成一个”开关”或者一个”灯泡”,要么亮要么灭,没有中间状态。

寄存器(Register)

寄存器是”字”类型的数据,它是一个具体的数字,比如 0、42、1000、65535 都可以。一个 Modbus 寄存器通常是 16 位,能表示的数字范围是 0 到 65535。

用最直观的比喻:

  • 线圈 = 开关(只有开和关两种状态);
  • 寄存器 = 计数器(上面能显示一个具体的数字)。

1.3.3 只读 和 读写

除了”位还是字”这个区别,存储区还分”能不能改”:

  • 只读:这个区域的数据,设备自己才能改(比如传感器测到的温度、开关的输入状态),外部(主站)只能读,不能写。
  • 读写:这个区域的数据,主站既可以读,也可以写(比如主站可以下命令设置某个参数)。

1.3.4 Modbus 的四个存储区

把”位还是字”和”只读还是读写”这两组特点交叉组合,就得到了 Modbus 的四个存储区:

读写特性 数据类型 存储区名称 代号
只读 布尔(位) 输入线圈 1 区
只读 输入寄存器 3 区
读写 布尔(位) 输出线圈 0 区
读写 输出寄存器(保持型寄存器) 4 区

下面把每一个区都讲清楚:

0 区:输出线圈(读写,位类型)

这是一个”开关”集合,主站可以读它的状态,也可以写它(把它打开或关闭)。它通常对应设备的一些可以被外部控制的开关量输出,比如控制某个继电器吸合、某个指示灯亮灭。

注意:名字里虽然有”输出”,但主站是可以”写”它的,别被”输出”两个字绕晕。

1 区:输入线圈(只读,位类型)

这也是一个”开关”集合,但它只能读、不能写。它通常对应设备外部输入的开关量状态,比如某个按钮有没有被按下、某个限位开关有没有被触发。这些状态是现场硬件决定的,主站只能看,不能改。

3 区:输入寄存器(只读,字类型)

这是一个”数字”集合,只能读、不能写。它通常对应设备采集到的模拟量数据,比如温度、压力、流量、转速等。这些数据是设备测量出来的,主站只能读结果。

4 区:输出寄存器,也叫保持型寄存器(读写,字类型)

这是最重要的一个区,也是工控里用得最多的。它是一个”数字”集合,主站既能读、也能写。它通常对应设备的一些可设置的参数,比如目标温度、频率设定值、报警上下限等。

“保持型”这个词的意思是:这个寄存器的值即使设备断电,再上电也还能保持住(保存在断电不丢失的存储里),所以叫”保持型寄存器”。

1.3.5 为什么要分这么多区

你可能会问:搞这么多区,不嫌麻烦吗?

其实这样分是有道理的。因为它把数据的”用途”和”性质”说清楚了。看到某个数据属于”输入寄存器”,你就立刻知道:这是设备测出来的量,只能看不能改。看到它属于”保持寄存器”,你就知道:这是个参数,可以读也可以写。

这种明确的分区,让通信双方(主站和从站)对”这块数据是干嘛的、能不能动”有一致的认识,不会乱来。


1.4 Modbus 协议功能码说明

1.4.1 功能码是什么:行为的代号

上一节我们知道了数据存在哪,这一节我们解决另一个问题:主站想对数据做什么?

主站能对数据做的操作,无非就是这么几种:读、写。但是”读”要区分读线圈还是读寄存器,”写”要区分写一个还是写多个。Modbus 给每一种操作都编了一个号,这个号就叫功能码(Function Code)

打个比方:功能码就是”行为的代号”。就像部队里用数字代号代表不同命令,”1”代表前进、”2”代表撤退一样。Modbus 用 01 表示”读输出线圈”、03 表示”读保持寄存器”,双方一看到这个数字,就知道对方想干什么。

所以一句话记住:功能码,本质就是行为的代号。

1.4.2 常用功能码一览表

功能 功能码
读取输出线圈 01 Hex
读取输入线圈 02 Hex
读取输出寄存器(保持型) 03 Hex
读取输入寄存器 04 Hex
写入单线圈 05 Hex
写入单寄存器 06 Hex
写入多线圈 0F Hex
写入多寄存器 10 Hex

下面逐个解释,同时把每个功能码和上一节的存储区对应起来,这样你就串起来了:

01 Hex:读取输出线圈(0 区)

主站用这个功能码,去读从站”输出线圈”的开关状态。一次可以读一个,也可以读一串(连续多个线圈)。

02 Hex:读取输入线圈(1 区)

主站用这个功能码,去读从站”输入线圈”的开关状态。和 01 的区别只是:01 读的是可读可写的输出线圈,02 读的是只读的输入线圈。

03 Hex:读取保持寄存器(4 区)

主站用这个功能码,去读从站”保持寄存器”的数值。这是工控里最最常用的功能码,采集模拟量、读参数,基本都用它。

04 Hex:读取输入寄存器(3 区)

主站用这个功能码,去读从站”输入寄存器”的数值。和 03 的区别:03 读的是可读可写的保持寄存器,04 读的是只读的输入寄存器。

05 Hex:写入单个线圈(0 区)

主站用这个功能码,去控制某一个线圈的开关(把它置为开或关)。

06 Hex:写入单个寄存器(4 区)

主站用这个功能码,去设置某一个保持寄存器的值。比如把目标温度寄存器设置成 80。

0F Hex:写入多个线圈(0 区)

和 05 一样是写线圈,但 05 一次只能写一个,0F 一次可以写连续的一串。

10 Hex:写入多个寄存器(4 区)

和 06 一样是写寄存器,但 06 一次只能写一个,10 一次可以写连续的一串。

1.4.3 几个容易混淆的点,帮你理清楚

读和写,各有一组”单个”和”多个”:

  • 写线圈:05(单个)、0F(多个);
  • 写寄存器:06(单个)、10(多个)。

注意多写的时候,0F 和 10 不是 0A 0B 那种连续编号,而是跳到了 0F、10(十六进制),这个记一下就行,别跟十进制搞混。

线圈和寄存器分得清清楚楚:

  • 01、02、05、0F 这四兄弟,都是跟”线圈(开关)”打交道的;
  • 03、04、06、10 这四兄弟,都是跟”寄存器(数字)”打交道的。

读的时候:01、02 读线圈,03、04 读寄存器;写的时候:05、0F 写线圈,06、10 写寄存器。这样一归类,8 个功能码就很好记了。

1.4.4 异常码:当从站”拒绝回答”的时候

正常情况下,主站发一个请求,从站乖乖照做。但有时候从站没法照做,比如主站要读的地址不存在、或者发过来的功能码从站不支持。这时候从站不能什么都不说,它要”回一句”告诉主站:出错了。

从站回错误的办法,是把功能码的最高位置 1,这个回应就叫异常响应

具体是这样的:假设主站发的是功能码 03(读保持寄存器),如果出错,从站回应的功能码就是 03 加上 0x80,等于 0x83

这就是你目录里写的”异常码 0x83”的来历:它对应的是”03 号功能码执行失败”。同理,如果是 06 号功能码执行失败,从站会回 0x86;01 号失败回 0x81。

记住这条规律就行:正常功能码加上 0x80,就是对应的异常码。

(至于具体是什么错误原因,从站还会在报文里带一个”异常原因码”,这个我们到后面看实际报文时再讲,现在先知道有”异常码”这回事就行。)


1.5 Modbus 协议地址模型说明

这一节解决一个特别容易把新手绕晕的问题:Modbus 的地址到底是怎么算的?

1.5.1 PLC 的地址模型

先回忆一下 PLC 里的地址是怎么表示的。

PLC 里的地址,通常由”存储区代号 + 偏移量”组成。比如:

  • D100:表示 D 区(数据寄存器区)里的第 100 个字;
  • M10:表示 M 区(中间继电器区)里的第 10 个位。

这里 D、M 是存储区代号,100、10 是偏移量(就是”第几个”的意思)。

这个模型的特点是:存储区代号和编号是分开写的,一看到 D100,就知道是”数据寄存器区的第 100 个”。

1.5.2 Modbus 的地址模型

Modbus 的地址,本质上也是”存储区代号 + 偏移量”,但有一个很关键的小变化:

Modbus 地址 = 存储区代号 +(偏移量 + 1)

注意后面这个”加 1”。Modbus 的编号习惯是从 1 开始数,而不是从 0 开始数。所以:

  • 4 区第 1 个寄存器,编号就是 40001(而不是 40000);
  • 4 区第 100 个寄存器,编号就是 40100。

这个”从 1 开始”的约定,是新手最容易出错的地方,一定要记住:Modbus 的地址编号从 1 开始。

1.5.3 长地址模型(六位地址模型)

所谓”长地址”,就是完整写出六位数字的地址。格式是:4XXXXX(第一位是区号,后面跟五位数字)。

比如:

  • 4 区第 100 个寄存器,长地址写作 400100
  • 4 区第 1 个寄存器,长地址写作 400001

六位数字里,第一位是区号(这里是 4),后面五位是寄存器编号(从 1 开始)。这样一眼就能看出:这是 4 区的、第多少个寄存器。

1.5.4 短地址模型(五位地址模型)

所谓”短地址”,就是省略掉一位的写法,格式是:4XXXX(第一位是区号,后面跟四位数字)。

比如:

  • 4 区第 100 个寄存器,短地址写作 40100
  • 4 区第 1 个寄存器,短地址写作 40001

你会发现:短地址里,区号”4”仍然在第一位,但后面的编号少了一位。这其实是早期 Modbus 规范里,寄存器编号只用了四位(最大 9999)时的写法。

1.5.5 长地址和短地址的区别

简单说:

  • 长地址(六位):区号 + 5 位编号,编号可以到 65535,能表示的范围更大;
  • 短地址(五位):区号 + 4 位编号,编号最多到 9999,范围小一些。

现在大多数设备和软件都支持长地址了,但你在一些老设备、老资料里还会看到短地址的写法。看到一个地址,先数数有几位,就知道它是长地址还是短地址了。

1.5.6 存储区范围(长地址)

下表列出了四个存储区的完整地址范围:

存储区 地址范围 偏移范围
输出线圈 0x 000001 到 065536 0 到 65535
输入线圈 1x 100001 到 165536 0 到 65535
输入寄存器 3x 300001 到 365536 0 到 65535
输出寄存器 4x 400001 到 465536 0 到 65535

这里解释两个概念:

地址(带区号的那个数):是我们平时说的”绝对地址”或者”编号地址”,比如 400001。注意它从 1 开始。

偏移(Offset):是”从第 0 个开始数,这是第几个”,从 0 开始。比如 400001 这个寄存器的偏移是 0,40100 的偏移是 99。

你会发现一个规律:地址 = 偏移 + 1。偏移是 0,地址就是 1;偏移是 99,地址就是 100。这就是 1.5.2 里说的”加 1”的由来。

1.5.7 绝对地址 和 相对地址

这是整个地址模型里最重要的一个区分,很多新手就是在这里被绕晕的。我们慢慢说。

绝对地址

绝对地址就是前面说的那种”带区号”的完整地址,比如 400001、30100、10001。它的好处是:一看就知道是哪个存储区、第多少个

绝对地址是给人看的。说明书、资料、工程师之间交流,用的都是绝对地址。比如同事跟你说”读一下 40001 这个寄存器”,你立刻就明白是 4 区的第 1 个寄存器。

相对地址

相对地址就是”偏移量”,也就是把区号去掉、从 0 开始数的那种地址。比如 40001 对应的相对地址就是 0,40100 对应的相对地址就是 99。

关键结论来了:在 Modbus 实际的报文里,传输的都是相对地址,不是绝对地址。

为什么?因为报文里已经有”功能码”了,而功能码本身就说明了要访问哪个存储区。比如功能码 03 就是读 4 区(保持寄存器),那报文里的地址就只需要告诉对方”从第几个开始读”就行了,没必要再把”4 区”写一遍。如果硬要写绝对地址,反而会和功能码表达的信息重复、产生冲突。

所以记住这个对应关系:

  • 绝对地址:给人看、写说明书、口头交流用的,能直接看出存储区和编号;
  • 相对地址:给机器看、写在报文里用的,只有偏移量,存储区由功能码来体现。

用一个例子把两者串起来:

你要读”4 区第 1 个寄存器”(绝对地址 400001)。在报文里,你会看到:

  • 功能码 = 03(表示读保持寄存器,也就是 4 区);
  • 起始地址(相对地址)= 00 00(表示从偏移 0 开始,即第 1 个寄存器)。

这样,功能码说明了”读 4 区”,相对地址说明了”从第 1 个开始”,两者合起来,就是”读 4 区第 1 个寄存器”。绝对地址里的信息,被功能码和相对地址”分工”表达了。


1.6 Modbus 协议分类及测试

这一节,我们把前面所有的概念串起来,看看一条完整的 Modbus 报文到底长什么样,以及 Modbus 有哪些分类。

1.6.1 Modbus 报文帧的三种类型

一条 Modbus 消息,专业上叫一个”报文帧”(Frame)。根据传输方式和校验方式的不同,Modbus 报文帧主要分三种:

帧类型 校验方式 说明
RTU CRC 校验 二进制传输,效率高,最常用
ASCII LRC 校验 字符传输,每个字节用两个字符表示,效率低但易读
TCP 没有校验(交给底层网络协议处理) 跑在以太网上,加了一个 MBAP 报文头

RTU 帧(最常用,重点掌握)

RTU 是工控里最常用的格式,尤其是串口通信,几乎都是 RTU。它用二进制直接传输数据,报文紧凑、效率高。为了确保数据在传输中没出错,它在报文末尾加了一段 CRC 校验码(16 位)。接收方收到报文后,自己也算一遍 CRC,跟收到的 CRC 对比,一致就说明数据没传错。

ASCII 帧

ASCII 格式比较古老,它把每一个字节拆成两个字符来传输(比如字节 0x03 变成字符 ‘0’ 和字符 ‘3’)。好处是人一眼能读懂,坏处是报文长度翻倍、效率低。它用的是 LRC 校验(一个比较简单的纵向冗余校验)。现在新设备基本不用 ASCII 了,了解即可。

TCP 帧

Modbus TCP 是跑在以太网上的 Modbus。因为底层的 TCP 协议自己已经做了数据校验,所以 Modbus TCP 报文里不再带 CRC 校验,而是加了一个 MBAP 报文头(里面包含事务标识、协议标识、长度、单元标识等信息),用来在网络上正确传输。这一点要记牢:Modbus TCP 没有 CRC。

1.6.2 通信介质

Modbus 报文跑在什么物理通道上,就是”通信介质”。常见的有两类:

  • 串口:RS232、RS485、RS422。特点是一对一(RS232)或一主多从(RS485),距离有限但抗干扰、成本低,是工业现场的主力。
  • 以太网:TCP、UDP。特点是速度快、距离远、可以走局域网或互联网,越来越普及。

1.6.3 Modbus 的协议分类

把”帧类型”和”通信介质”组合起来,就得到了 Modbus 的完整分类。你的目录里列了 8 种:

  1. Modbus RTU(串口 + RTU 帧)
  2. Modbus RTU Over TCP(以太网 TCP + RTU 帧)
  3. Modbus RTU Over UDP(以太网 UDP + RTU 帧)
  4. Modbus ASCII(串口 + ASCII 帧)
  5. Modbus ASCII Over TCP(以太网 TCP + ASCII 帧)
  6. Modbus ASCII Over UDP(以太网 UDP + ASCII 帧)
  7. Modbus TCP(以太网 TCP + TCP 帧)
  8. Modbus UDP(以太网 UDP + TCP 帧,但用 UDP 传输)

解释一下”Over TCP / Over UDP”是什么意思:它的意思是”把本来用于串口的 RTU(或 ASCII)报文,原封不动地搬到以太网上去传输”。也就是说,报文内容还是 RTU 那一套(带 CRC),只是不再走串口线,而是通过 TCP 或 UDP 网络来收发。而”Modbus TCP”则是真正的网络版格式(去掉 CRC、加 MBAP 头)。

对初学者来说,最重要的是前两种:

  • Modbus RTU:串口通信的主力,最经典、最常用;
  • Modbus TCP:网络通信的主力,也是最常用的网络版。

先把这两个彻底搞懂,其余的”Over TCP / Over UDP”、”ASCII”之类,用到的时候再回头补即可。

1.6.4 手把手案例:完整拆解一条 Modbus RTU 报文

光讲理论不够,下面我们亲手拆一条真实的报文,把前面学到的”从站地址、功能码、地址、数据、校验”全部串起来。这一条报文是整个第一部分的”压轴”,读懂了它,你就真正入门了。

场景设定

现在有一台设备,它是”1 号从站”。它内部有一个保持寄存器,里面存了一个数值 42(比如代表当前温度是 42 度)。我们的电脑(主站)想知道这个值,于是发一条请求去读它。

假设我们要读的是”4 区第 1 个寄存器”(绝对地址 400001,相对地址 0)。

第一步:主站发出的请求报文

主站发出去的完整报文(用十六进制表示)是这样的:

1
01 03 00 00 00 01 84 0A

一共 8 个字节。我们一个字节一个字节地拆:

字节 数值 含义
第 1 个字节 01 从站地址,表示”我要问 1 号从站”
第 2 个字节 03 功能码,表示”读取保持寄存器”
第 3、4 个字节 00 00 起始地址(相对地址 0),即从第 1 个寄存器开始读
第 5、6 个字节 00 01 要读的数量,即读 1 个寄存器
第 7、8 个字节 84 0A CRC 校验码,用来检查报文有没有传错

看明白了吗?这条报文用大白话翻译过来就是:

“1 号从站,请把你保持寄存器里,从第 1 个开始、一共 1 个寄存器的值告诉我。”

(说明:CRC 校验码是设备或程序自动算出来的,你现在完全不用手动算它,只要知道最后两个字节是”校验码”这个身份就够了。等后面我们自己写串口助手时,再带你在代码里算 CRC。)

第二步:从站回应的报文

1 号从站收到请求后,回一条报文:

1
01 03 02 00 2A 39 9B

一共 7 个字节,继续拆:

字节 数值 含义
第 1 个字节 01 从站地址,表示”我是 1 号从站,我回话了”
第 2 个字节 03 功能码,表示”这是对读取寄存器的回应”
第 3 个字节 02 后面数据部分的字节数。1 个寄存器是 2 个字节,所以这里是 02
第 4、5 个字节 00 2A 真正的数据。00 2A 换算成十进制就是 42,也就是我们想要的那个值
第 6、7 个字节 39 9B CRC 校验码

用大白话翻译这条回应:

“我是 1 号从站,你要的那个寄存器(第 1 个)的值是 42。”

到这里,一次完整的”主站读寄存器”通信就结束了。主站拿到 00 2A,把它换算成十进制 42,显示在软件界面上,这就是你以后要在 C# 里实现的事情:发报文、收报文、解析出数据。

第三步:再看一条”写”的报文,加深印象

假设现在我们要让 1 号从站把那个寄存器改成 42(写单个寄存器,功能码 06),主站发的报文是:

1
01 06 00 00 00 2A 08 15

拆解如下:

字节 数值 含义
第 1 个字节 01 从站地址
第 2 个字节 06 功能码,表示”写单个寄存器”
第 3、4 个字节 00 00 要写的寄存器地址(相对地址 0,即第 1 个寄存器)
第 5、6 个字节 00 2A 要写入的值 42(十六进制 00 2A)
第 7、8 个字节 08 15 CRC 校验码

对比一下”读”(功能码 03)和”写”(功能码 06),你会发现结构很像,区别只是功能码不同、报文里带的”数据”含义不同:读的时候带的是”起始地址和数量”,写的时候带的是”地址和要写的值”。这种”套路一致、细节不同”的感觉,正是 Modbus 简单好懂的地方。


第一部分小结

到这里,第一部分(协议基础知识)就学完了。我们回顾一下你掌握了什么:

  1. Modbus 是 Modicon 公司 1979 年发明的免费工业通信协议,特点就是免费、简单、不挑传输介质;
  2. 通信分为主站(主动问)和从站(被动答)两种角色,一切对话都由主站发起;
  3. 数据存在四个存储区里:输出线圈、输入线圈、输入寄存器、保持寄存器,区分的依据是”位还是字”和”只读还是读写”;
  4. 主站对数据的操作,用功能码来表示,最常用的是 03(读保持寄存器)和 06(写单寄存器);
  5. Modbus 地址从 1 开始编号,报文里传的是”相对地址”,绝对地址是给人看的;
  6. Modbus 报文分 RTU、ASCII、TCP 三种帧,最常用的是 RTU(串口)和 TCP(网络);
  7. 一条完整报文由”从站地址 + 功能码 + 数据 + 校验”组成,你已经能手把手拆解”读”和”写”两条报文了。

下一部分,我们会进入真正的动手环节:装好调试软件,用 Modbus Poll 和 Modbus Slave 亲手做一次收发实验,亲眼看到上面讲的这些报文在电脑里跑起来。然后再一步步用 C# 写出我们自己的 Modbus 通信程序。

学习路上,最重要的不是一次记住所有东西,而是每一步都能看懂、能跑通。有任何卡住的地方,随时停下来问我,我会陪你慢慢啃。