全场景——(四)Modbus 通讯协议

一、学习Modbus的快速方法

1.1 寄存器速记

作为初学者,阅读Modbus协议时会发现它的概念别扭、重复、不易区分,比如线圈状态(Coil Status)、离散输入状态(Discrete Input Status)、保持寄存器(Holding Register)、输入寄存器(Input Register)。

回到事情的本质,在工业控制PLC领域,涉及数字信号的输入、输出,模拟信号的输入、输出,如下图所示:

在这里插入图片描述

对于软件开发而言:

  • 想得到按键输入状态时,读取到的是一位数据;
  • 想控制LED时,需要输出一位数据,想读取LED当前状态时,也可以读取到一位数据
  • 想读取模拟信号时,读取到的是多位数据,比如16位数据
  • 想输出模拟信号时,写入的是多位数据,比如16位数据;也可以读取“模拟量输出”的当前值。

在上图中,“数字量输入DI”是只读的,“数字量输出DO”是可读可写的,“模拟量输入AI”是只读的,“模拟量输出AO”是可读可写的。

上图里的“模拟量输入AI”、“模拟量输出AO”都表示“多位数值”,这些“多位数值”无需局限于只表示“模拟量”,也可以表示“多位数字量”。把AI、AO的含义扩展后,如下图所示:

在这里插入图片描述

对于软件开发而言:

  • 想得到按键输入状态时,读取到的是一位数据;
  • 想控制LED时,需要输出一位数据,想读取LED当前状态时,也可以读取到一位数据
  • 想读取参数时,读取到的“输入寄存器”,得到多位数据,比如16位数据
  • 想设置参数时,写的是“保存寄存器”,写入的是多位数据,比如16位数据;也可以读“保存寄存器”

在电子系统里,无论是单bit的数值、多bit的数值,都是保存在寄存器里。根据上图,这些寄存器可以分为4类:

寄存器种类说明与PLC类比举例说明
线圈状态(Coil Status)输出端口。可设定端口输出状态,也可以读取该位的输出状态。可分为两种不同的执行状态,列如保持型或边沿触发型DO(数字量输出)电磁阀输出、MOSFEF输出、LED显示等
离散输入状态(Discrete Input Status)输入端口。通过外部设定改变输入状态,可读但不可以写DI(数字量输入)拨码开关、接近开关等
保持寄存器(Holding Register)输出参数或保持参数,控制器运行时被设定的某些参数,可读可写AO(模拟量输出)模拟量输出设定值,PID运行参数,变量阀输出大小,传感器报警上限下限
输入寄存器(Input Register)输入参数。控制器运行时从外部设备获得的参数,但可读不可写AI(模拟量输入)模拟量输入

在Modbus中,多位操作时都是16位(2bytes)的,总结如下:

  • bit操作涉及的寄存器有2类:线圈状态(可读可写)、离散输入状态(只读)
  • 16bit操作的寄存器有2类:保存寄存器(可读可写)、输入寄存器(只读)

一个设备里,可能有多个“线圈状态”、多个“离散输入状态”、多个“保存寄存器”、多个“输入寄存器”。怎么分辨某类寄存器中的某一个?它们有“寄存器地址”,如下图所示:

寄存器种类PLC寄存器地址范围Modbus寄存器地址范围简称读写状态
线圈状态00001~099990000H~FFFFH0x可读可写
离散输入状态10001~199990000H~FFFFH1x只读
保持寄存器40001~499990000H~FFFFH4x可读可写
输入寄存器30001~399990000H~FFFFH3x只读

在上表中,“线圈状态”的寄存器N、“离散输入状态”的寄存器N,是两个不同的寄存器。

简单记忆方法:“

  • 偶数类的寄存器”是可读可写的,比如“0x”和“4x”;
  • “奇数类的寄存器”是只读的,比如“1x”和“3x”;
  • “0x”和“1x”是bit寄存器;
  • “3x”和“4x”是16bit寄存器。

1.2 协议速记

Modbus是一主多从的协议,如下图所示:

在这里插入图片描述

主控发出的数据里,必定含有如下信息:

  • 设备地址:你要访问从设备1,还是访问从设备2(从设备识别到设备地址与自身地址匹配才会去处理主设备中的数据包)
  • 访问哪类寄存器,是读还是写:这被称为功能码(比如读取离散输入寄存器)
  • 起始寄存器地址、寄存器数量:这在数据里定义(与功能码相关:拿上面为例 这里就需要说明读取哪个离散输入寄存器 要读取一个还是多个)
  • 为了保证数据传输的可靠,还附带有CRC检验码

以Modbus RTU协议为例,主控发出的数据包格式如下:

在这里插入图片描述

功能代码有哪些?常用的功能码如下:

  • 读线圈状态(01)
  • 读离散输入状态(02)
  • 写单个线圈(05)、写多个线圈(15)
  • 读保持寄存器(03)
  • 读输入寄存器(04)
  • 写单个保存寄存器(06)、写多个保存寄存器(16)

数据的格式,由功能代码确定。以“读线圈状态”为例,主控发出的请求、从设备返回的响应包,或者从设备返回的错误包,格式如下:

在这里插入图片描述

Fuction code 中的 0x01 表示读线圈。寄存器起始地址(“Starting Address”)是16位的,先传输高字节,再传输低字节。线圈数量(“Quantiti of coils”)也是16位的,先传输高字节,再传输低字节

响应包回复多少个数据呢(上图中N为多少)?N = Quantiti of coils / 8,如果余数不等于0,则N再加1。比如Quantiti of coils=9,则返回2个字节

在《Modbus_Application_Protocol_V1_1b3.pdf》中,列出了如下功能表。根据次表,在结合《5.5 Moubus功能码详解》的示例,就可以对Modbus RTU协议有很好的理解了。

在这里插入图片描述

二、初识Modbus

2.1 背景

Modbus诞生于1979年莫迪康(Modicon)公司,后来被施耐德电气公司收购。Modbus提供通用语言用于彼此通信的设备和设备,是全球第一个真正用于工业现场的总线协议。Modbus已经成为工业领域通信协议的业界标准,并且现在是工业电子设备之间常用的连接方式。Modbus作为目前工业领域应用最广泛的协议,之后为了更好地普及和推动Modbus基于以太网 (TCP/IP) 的分布式应用,施耐德公司已将Modbus协议的所有权移交给IDA (Interface for Distributed Automation,分布式自动化接口)组织,并成立了Modbus-IDA组织,此组织的成立和发展进一步推动了Modbus协议的广泛应用。

在这里插入图片描述

2.2 什么是Modbus?

2.2.1 Modbus简介

Modbus协议是一种已广泛应用于当今工业控制领域的通用通讯协议。通过此协议,控制器相互之间、或控制器经由网络(如以太网)可以和其它设备之间进行通信。Modbus协议使用的是主从通讯技术,即由主设备主动查询和操作从设备一般将主控设备方所使用的协议称为Modbus Master,从设备方使用的协议称为Modbus Slave。典型的主设备包括工控机和工业控制器等;典型的从设备如PLC可编程控制器等。有了它,不同厂商生产的控制设备就可以连接成工业网络,进行集中监控。Modbus协议定义了一个控制器能够认识和使用的消息结构,而不管它们是经过何种网络进行通信的;而且描述了控制器请求访问其他设备的过程,如何应答来自其他设备的请求,以及怎样侦测错误并记录,并制定了统一的消息域的结构和内容。 当在Modbus网络上通信时,Modbus协议决定了每个控制器必须要知道它们的设备地址,识别按地址发来的消息决定要产生何种行为。如果需要回应,则控制器将生成反馈信息并通过Modbus协议发送。

Modbus通讯物理接口可以选用串口(包括RS232、RS485和RS422等),也可以选择以太网口。其通信遵循以下的过程:

  • 主设备向从设备发送请求
  • 从设备分析并处理主设备的请求,然后向主设备发送结果
  • 如果出现任何差错,从设备将返回一个异常功能码

此协议定义了一个控制器能认识使用的消息结构,而不管它们是经过何种网络进行通信的。它描述了一控制器请求访问其它设备的过程,如何回应来自其它设备的请求,以及怎样侦测错误并记录。它制定了消息域格局和内容的公共格式

当在Modbus网络上通信时,此协议决定了每个控制器须要知道它们的设备地址,识别按地址发来的消息,决定要产生何种行动。如果需要回应,控制器将生成反馈信息并用Modbus协议发出。在其它网络上,包含了Modbus协议的消息转换为在此网络上使用的帧或包结构。这种转换也扩展了根据具体的网络解决节地址、路由路径及错误检测的方法。

Modbus的工作方式是请求/应答,每次通讯都是主站先发送指令,可以是广播,或是向特定从站的单播;从站响应指令,并按要求应答,或者报告异常当主站不发送请求时,从站不会自己发出数据,从站和从站之间不能直接通讯。

MODBUS 是一种应用层消息传递协议,位于 OSI 模型的第 7 层。它提供连接在不同类型总线或网络上的设备之间的客户端/服务器通信。

Modbus通信栈如下:

在这里插入图片描述

2.2.2 Modbus特点

Modbus通信协议具有以下几个特点:

  • Modbus协议标准开放、公开发表且无版税要求。用户可以免费获取并使用Modbus协议,不需要交纳许可证费,也不会侵犯知识产权。
  • Modbus协议支持多种电气接口,如RS232、RS485、TCP/IP等,还可以在各种介质上传输,如双绞线、光纤、红外、无线。
  • Modbus协议消息帧格式简单、紧凑、通俗易懂。用户理解和使用简单,厂商容易开发和集成,方便形成工业控制网络。
  • 可靠性: Modbus 是最古老的工业自动化通信协议。它使用和编程简单,因此学习曲线较低。
  • 遗留基础设施:许多制造商在早期自动化方面投入了大量资金。Modbus 对于配置、DLR、节点、子站和其他基础设施非常友好,这些基础设施可能会被新的或更先进的协议所淘汰。
  • 快速部署: Modbus 可以轻松、立即集成到 SCADA和其他控制系统中
  • 灵活性: Modbus 已适应新兴技术。例如,Modbus TCP 可以通过话配器进行转换,以与LAN 和远程控制系统集成。它还可以利用基于网络和基于云的平台。
  • 简单性:由于通信简单,因此可以轻松扩展到新技术。例如,Modbus TCP/P 由于指令集简单,部署速度很快。它还可以与以太网配合使用,无需添加芯片或板。

2.2.3 Modbus常用术语

名词意义
Master主(站) 设备
Slave从 (站) 设备
Client客户端
Server服务器端
ADU应用数据单元(Application Data Unit)
PDU协议数据单元 (Protocol Data Unit)
MSB最高有效位(Most Significant Bit)
LSB最低有效位 (Least Significant Bit)
MBAPModbus应用协议(Modbus Application Protocol)
PLC可编程逻辑控制器(Programmable Logic Controller)

2.2.4 Modbus事务处理

Modbus协议允许在各种网终体系结构内进行简单通信,每种设备 (包括PLC、HMI、控制面板、驱动程序、动作控制、输入/输出设备) 都能使用Modbus协议启动远程操作。在基于串行链路和以太网 (TCP/IP)的Modbus上可以进行相互通信。一些网关允许在几种使用MODBUS协议的总线或网络之间进行通讯。

MOUBUS网络体系结构的实例:

在这里插入图片描述

Modbus是一个请求、应答协议,并且提供统一的功能码用于数据传输服务。Modbus功能码是Modbus请求/应答PDU (Protocol Data Unit,协议数据单元)的元素之一,所谓的PDU其实就是Modbus协议定义的一个与基础通信层无关的简单协议数据单元。特定总线或网络上的Modbus协议映射能够在ADU (Application Data UInit ,应用数据单元)上引入一些附加域,从而实现完整而准确的数据传输。

为了寻求一种简洁的通信格式,Modbus协议定义了PDU模型,即功能码+数据的格式,而为了适应多种传输模式,又在PDU的基础上增加了必要的前缀 (如地址域)和后缀(如差错校验) ,形成了ADU模型(见下图)。

通用MODBUS帧如下:

在这里插入图片描述

Modbus事务处理过程:

  • 主机设备 (或客户端)创建Modbus应用数据单元形成查询报文,其中功能码标识了向从机设备 (或服务器端)指示将要执行的操作。其中功能码占用1字节,有效的码字范围是十进制1 ~ 255 (其中128 ~255为异常响应保留) 。查询报文创建完毕,主机设备 (或客户端) 向从机设备 (或服务器端)发送报文,从机设备 (或服务器端)接收报文后根据功能码做出相应的动作,并将响应报文返回给主机设备 (或客户端),如图下所示:

    MouBus事务处理(无异常)

在这里插入图片描述

  • 如果在一个正确接收的Modbus ADU中不出现与请求Modbus功能有关的差错,那么从机设备 (或服务器端) 将返回正常的响应报文。如果出现与请求Modbus功能有关的差错,那么响应报文的功能码域将包括一个异常码,主机设备(或客户端)能够根据异常码确定下一步执行的操作;对于异常响应,服务器返回一个与原始功能码等同的码,设置该原始功能码的最高有效位为逻辑1,用于通知主设备(客户端)。如下图所示:

    MouBus事务处理(异常响应)

在这里插入图片描述

三、Modbus软件与使用

3.1 Modbus软件简介

为了更好的学习和理解Modbus,这里推出三个软件Modbus Poll(主站设备)、Modbus Slave(从站设备)和虚拟串口软件,借助三款设备我们可以在PC上做一些基础实验,更加直观地观察通信数据,加深我们的理解,我们将它称为Modbus学习必备三件套,这是一个很好的入门方法。

3.2 Modbus Poll(主站设备)

3.2.1 Modbus Poll简介

Modbus Poll是Modbus主站设备仿真器,用于测试和调试Modbus从设备便于观察Modbus通信过程中的各种报文数据。该软件支持ModbusRTU、ASCII、TCP/IP。用来帮助开发人员测试Modbus从设备,或者其它Modbus协议的测试和仿真。它支持多文档接口,即,可以同时监视多个从设备/数据域。每个窗口简单地设定从设备ID,功能,地址,大小和轮询间隔。你可以从任意一个窗口读写寄存器和线圈。如果你想改变一个单独的寄存器,简单地双击这个值即可。或者你可以改变多个寄存器/线圈值。提供数据的多种格式方式,比如浮点、双精度、长整型(可以字节序列交换)。该软件支持Modbus RTU、ASCII、TCP/IP等协议模式。

Modbus Poll支持下列协议模式:

Modbus RTUModbus RTU Over TCP/IP
Modbus ASCIIModbus ASCI Over TCP/IP
Modbus TCP/IPModbus RTU Over UDP/IP
Modbus UDP/IPModbus ASCII Over UDP/IP

3.2.2 Modbus Poll 使用

点击链接获取软件,按照提示安装即可;链接:

https://pan.baidu.com/s/1SpTRz6Z1XlkoCZjDozwqog 提取码:timc

下载完界面如下:

在这里插入图片描述

状态栏:

  • Tx = 0表示向主站发送数据帧次数,图中为0次;
  • Err = 0表示通讯错误次数,图中为0次;
  • ID = 1表示模拟的Modbus子设备的设备地址,图中地址为1;
  • F = 03表示所使用的Modbus功能码,图中为03功能码;
  • SR = 1000ms表示发送周期,1S一次。
  • 红字部分,表示当前的错误状态,“No Connection”表示未连接状态。

建立连接:

点击Connection->Connect进入配置页面,选择我们想要的连接,选择我们虚拟出来的串口,选择模式,例如:我们选择串口的连接方式,选则RTU模式,对应我们的Modbus RTU协议;接下来在设置波特率、比特位、校验位、停止位,如下图所示:

在这里插入图片描述

设置参数:点击Setup->Read/Write Definition进入配置页面,配置从机地址、功能码、地址类型、寄存器地址、访问数量、轮询时间,具体配置如下图:

在这里插入图片描述

3.3 Modbus Slave(从站设备)

3.3.1 Modbus Slave简介

Modbus从设备仿真器,可以仿真32个从设备/地址域。每个接口都提供了对EXCEL报表的OLE自动化支持。主要用来模拟Modbus从站设备,接收主站的命令包,回送数据包。帮助Modbus通讯设备开发人员进行Modbus通讯协议的模拟和测试,用于模拟、测试、调试Modbus通讯设备,便于观察Modbus通信过程中的各种报文数据;可以32个窗口中模拟多达32个Modbus子设备。与Modbus Poll的用户界面相同,支持功能01, 02, 03, 04, 05, 06, 15, 16, 22和23,监视串口数据。

Modbus Slave支持下列协议模式:

Modbus RTUModbus RTU Over TCP/IP
Modbus ASCIIModbus ASCI Over TCP/IP
Modbus TCP/IPModbus RTU Over UDP/IP
Modbus UDP/IPModbus ASCII Over UDP/IP

3.3.2 Modbus Slave使用

获取软件链接同上,下载完后主页面如图所示:

在这里插入图片描述

建立连接:

点击Connection->Connect进入配置页面,选择我们想要的连接,选择我们虚拟出来的串口,选择模式,接下来在设置波特率、比特位、校验位、停止位,如下图所示:

在这里插入图片描述

设置参数:点击Setup->Read/Write Definition进入配置页面,配置从机地址、功能码、地址类型、寄存器地址、访问数量,具体配置如下图:

在这里插入图片描述

这里有两点需要我们注意一下:

  • 一是:Function列表框选择功能中的0x~4x,表示的是存储区0区、1区、3区、4区
    • 输出线圈
    • 输入线圈
    • 保持寄存器
    • 输入寄存器

在这里插入图片描述

Modbus协议规定了4个存储区 分别是0、1、3、4区 其中0区和4区是可读可写,1区和3区是只读。

区号名称读写地址范围
0区输出线圈可读可写布尔量00001-09999
1区输入线圈只读布尔量10001-19999
3区输入寄存器只读寄存器30001-39999
4区保持寄存器可读可写寄存器40001-49999
  • 二是:Address项,这里需要特别强调一下,Address表示Modbus寄存器地址,其取值范围与设备寄存器地址存在映射关系,如下表所示:
Device addressModbus addressDescriptionFunctionR/W
1…10000address - 1Coils(outputs)01Read/Write
10001…20000address - 10001Discrete Inputs02Read
40001…50000address - 40001Holding Registers03Read/Write
30001…40000address - 30001Input Registers04Read

这里我们只简单介绍下地址和存储区,下面我们会详细展开。

3.4 虚拟串口软件

3.4.1 软件简介

虚拟串口工具,可以创建2个互联的串口,如下图所示:

在这里插入图片描述

比如Modbus Poll工具使用COM1发送数据给COM2,Modbus Slave从COM2读到数据。使用虚拟串口,就可以不使用开发板也可以体验Modbus Poll、Modbus Slave。

打开下图红框内软件:

在这里插入图片描述

3.4.2 虚拟串口的使用

安装后运行虚拟串口程序“Virtual Serial Port Tools”,点击免费版本,安装下图创建2个串口:
在这里插入图片描述

在这里插入图片描述

打开设备管理器,可以看到如下串口:

在这里插入图片描述

3.5 Modbus Poll 与 Modbus Slave互联/通

下面我们进行Modbus Poll 与 Modbus Slave互联互通实验,通过形象直观的方式展示Modbus数据流,根据前面的设定我们已将知道了如何运用Modbus学习必备三件套,下面我们就通过三件套来进行实验,首先打开VSPD虚拟串口软件,设置虚拟串口,我这里就以上面设订COM1,COM2为例,接下来我们再来配置我们的Modbus Poll 与 Modbus Slave;

我们首先打开Modbus Slave端,设置连接,连接方式我们选择Serial Port串口连接,选择我们设置的串口COM1,模式选择RTU模式,如下图所示:

  • Modbus Slave连接设定

在这里插入图片描述

在设置参数,从机地址我们设定1(你也可以自己随意设定),Function项我们选择03 Holding Register(4x),地址类型我们选择DEC(十进制格式),Address首地址我们设置为0,访问寄存器数量设置为10,如下图所示:

  • Modbus Slave参数设定

在这里插入图片描述

接下来我们再来设置Modbus Poll端,设置方法也是和Modbus Slave端一一对应的,连接设定,参数设定,如下图所示:

  • Modbus Poll连接设定

在这里插入图片描述

注意这里串口要选择我们设定的COM20,其它串口参数必须一一对应。

  • Modbus Poll参数设定

在这里插入图片描述

设置好后,我们主设备和从设备分别连接了我们设置的COM1,COM2,这样我们便可观察当前寄存器的读取情况。

我们双击Modbus Poll(主设备端)地址中的0值,便可打开值设置窗口如下图所示:

在这里插入图片描述

修改值为66,点击Send打开Modbus Slave(从设备端)便可发现也做出了改变,如下图所示:

在这里插入图片描述

我们还可以打开Modbus Poll,点击Display,选择Commuaction,查看发送的报文:

在这里插入图片描述

TX是我们主站发送的报文,RX是从站返回的报文。

Modbus通信协议 摘 要:工业控制已从单机控制走向集中监控、集散控制,如今已进入网络时代,工业控制器连网也为网络管理提供了方便。Modbus就是工业控制器的网络协议中的一种。关键词:Modbus协议;串行通信;LRC校验;CRC校验;RS-232C 一、Modbus 协议简介 Modbus 协议是应用于电子控制器上的一种通用语言。通过此协议,控制器相互之间、控制器经由网络(例如以太网)和其它设备之间可以通信。它已经成为一通用工业标准。有了它,不同厂商生产的控制设备可以连成工业网络,进行集中监控。 此协议定义了一个控制器能认识使用的消息结构,而不管它们是经过何种网络进行通信的。它描述了一控制器请求访问其它设备的过程,如果回应来自其它设备的请求,以及怎样侦测错误并记录。它制定了消息域格局和内容的公共格式。 当在一Modbus网络上通信时,此协议决定了每个控制器须要知道它们的设备地址,识别按地址发来的消息,决定要产生何种行动。如果需要回应,控制器将生成反馈信息并用Modbus协议发出。在其它网络上,包含了Modbus协议的消息转换为在此网络上使用的帧或包结构。这种转换也扩展了根据具体的网络解决节地址、路由路径及错误检测的方法。 1、在Modbus网络上转输 标准的Modbus口是使用一RS-232C兼容串行接口,它定义了连接口的针脚、电缆、信号位、传输波特率、奇偶校验。控制器能直接或经由Modem组网。 控制器通信使用主—从技术,即仅一设备(主设备)能初始化传输(查询)。其它设备(从设备)根据主设备查询提供的数据作出相应反应。典型的主设备:主机和可编程仪表。典型的从设备:可编程控制器。 主设备可单独和从设备通信,也能以广播方式和所有从设备通信。如果单独通信,从设备返回一消息作为回应,如果是以广播方式查询的,则不作任何回应。Modbus协议建立了主设备查询的格式:设备(或广播)地址、功能代码、所有要发送的数据、一错误检测域。 从设备回应消息也由Modbus协议构成,包括确认要行动的域、任何要返回的数据、和一错误检测域。如果在消息接收过程中发生一错误,或从设备不能执行其命令,从设备将建立一错误消息并把它作为回应发送出去。 2、在其它类型网络上转输 在其它网络上,控制器使用对等技术通信,故任何控制都能初始和其它控制器的通信。这样在单独的通信过程中,控制器既可作为主设备也可作为从设备。提供的多个内部通道可允许同时发生的传输进程。 在消息位,Modbus协议仍提供了主—从原则,尽管网络通信方法是“对等”。如果一控制器发送一消息,它只是作为主设备,并期望从从设备得到回应。同样,当控制器接收到一消息,它将建立一从设备回应格式并返回给发送的控制器。 3、查询—回应周期 (1)查询 查询消息中的功能代码告之被选中的从设备要执行何种功能。数据段包含了从设备要执行功能的任何附加信息。例如功能代码03是要求从设备读保持寄存器并返回它们的内容。数据段必须包含要告之从设备的信息:从何寄存器开始读及要读的寄存器数量。错误检测域为从设备提供了一种验证消息内容是否正确的方法。 (2)回应 如果从设备产生一正常的回应,在回应消息中的功能代码是在查询消息中的功能代码的回应。数据段包括了从设备收集的数据:象寄存器值或状态。如果有错误发生,功能代码将被修改以用于指出回应消息是错误的,同时数据段包含了描述此错误信息的代码。错误检测域允许主设备确认消息内容是否可用。 二、两种传输方式 控制器能设置为两种传输模式(ASCII或RTU)中的任何一种在标准的Modbus网络通信。用户选择想要的模式,包括串口通信参数(波特率、校验方式等),在配置每个控制器的时候,在一个Modbus网络上的所有设备都必须选择相同的传输模式和串口参数。 ASCII模式 : 地址 功能代码 数据数量 数据1 ... 数据n LRC高字节 LRC低字节 回车 换行 RTU模式 地址 功能代码 数据数量 数据1 ... 数据n CRC高字节 CRC低字节 所选的ASCII或RTU方式仅适用于标准的Modbus网络,它定义了在这些网络上连续传输的消息段的每一位,以及决定怎样将信息打包成消息域和如何解码。 在其它网络上(象MAP和Modbus Plus)Modbus消息被转成与串行传输无关的帧。 1、ASCII模式 当控制器设为在Modbus网络上以ASCII(美国标准信息交换代码)模式通信,在消息中的每个8Bit字节都作为两个ASCII字符发送。这种方式的主要优点是字符发送的时间间隔可达到1秒而不产生错误。 代码系统 • 十六进制,ASCII字符0...9,A...F • 消息中的每个ASCII字符都是一个十六进制字符组成 每个字节的位 • 1个起始位 • 7个数据位,最小的有效位先发送 • 1个奇偶校验位,无校验则无 • 1个停止位(有校验时),2个Bit(无校验时) 错误检测域 • LRC(纵向冗长检测) 2、RTU模式 当控制器设为在Modbus网络上以RTU(远程终端单元)模式通信,在消息中的每个8Bit字节包含两个4Bit的十六进制字符。这种方式的主要优点是:在同样的波特率下,可比ASCII方式传送更多的数据。 代码系统 • 8位二进制,十六进制数0...9,A...F • 消息中的每个8位域都是一个两个十六进制字符组成 每个字节的位 • 1个起始位 • 8个数据位,最小的有效位先发送 • 1个奇偶校验位,无校验则无 • 1个停止位(有校验时),2个Bit(无校验时) 错误检测域 • CRC(循环冗长检测) 三、Modbus消息帧 两种传输模式中(ASCII或RTU),传输设备以将Modbus消息转为有起点和终点的帧,这就允许接收的设备在消息起始处开始工作,读地址分配信息,判断哪一个设备被选中(广播方式则传给所有设备),判知何时信息已完成。部分的消息也能侦测到并且错误能设置为返回结果。 1、ASCII帧 使用ASCII模式,消息以冒号(:)字符(ASCII码 3AH)开始,以回车换行符结束(ASCII码 0DH,0AH)。 其它域可以使用的传输字符是十六进制的0...9,A...F。网络上的设备不断侦测“:”字符,当有一个冒号接收到时,每个设备都解码下个域(地址域)来判断是否发给自己的。 消息中字符间发送的时间间隔最长不能超过1秒,否则接收的设备将认为传输错误。一个典型消息帧如下所示: 图2 ASCII消息帧 2、RTU帧 使用RTU模式,消息发送至少要以3.5个字符时间的停顿间隔开始。在网络波特率下多样的字符时间,这是最容易实现的(如下图的T1-T2-T3-T4所示)。传输的第一个域是设备地址。可以使用的传输字符是十六进制的0...9,A...F。网络设备不断侦测网络总线,包括停顿间隔时间内。当第一个域(地址域)接收到,每个设备都进行解码以判断是否发往自己的。在最后一个传输字符之后,一个至少3.5个字符时间的停顿标定了消息的结束。一个新的消息可在此停顿后开始。 整个消息帧必须作为一连续的流转输。如果在帧完成之前有超过1.5个字符时间的停顿时间,接收设备将刷新不完整的消息并假定下一字节是一个新消息的地址域。同样地,如果一个新消息在小于3.5个字符时间内接着前个消息开始,接收的设备将认为它是前一消息的延续。这将导致一个错误,因为在最后的CRC域的值不可能是正确的。一典型的消息帧如下所示: 图3 RTU消息帧 3、地址域 消息帧的地址域包含两个字符(ASCII)或8Bit(RTU)。可能的从设备地址是0...247 (十进制)。单个设备的地址范围是1...247。主设备通过将要联络的从设备的地址放入消息中的地址域来选通从设备。当从设备发送回应消息时,它把自己的地址放入回应的地址域中,以便主设备知道是哪一个设备作出回应。 地址0是用作广播地址,以使所有的从设备都能认识。当Modbus协议用于更高水准的网络,广播可能不允许或以其它方式代替。 4、如何处理功能域 消息帧中的功能代码域包含了两个字符(ASCII)或8Bits(RTU)。可能的代码范围是十进制的1...255。当然,有些代码是适用于所有控制器,有此是应用于某种控制器,还有些保留以备后用。 当消息从主设备发往从设备时,功能代码域将告之从设备需要执行哪些行为。例如去读取输入的开关状态,读一组寄存器的数据内容,读从设备的诊断状态,允许调入、记录、校验在从设备中的程序等。 当从设备回应时,它使用功能代码域来指示是正常回应(无误)还是有某种错误发生(称作异议回应)。对正常回应,从设备仅回应相应的功能代码。对异议回应,从设备返回一等同于正常代码的代码,但最重要的位置为逻辑1。 例如:一从主设备发往从设备的消息要求读一组保持寄存器,将产生如下功能代码: 0 0 0 0 0 0 1 1 (十六进制03H) 对正常回应,从设备仅回应同样的功能代码。对异议回应,它返回: 1 0 0 0 0 0 1 1 (十六进制83H) 除功能代码因异议错误作了修改外,从设备将一独特的代码放到回应消息的数据域中,这能告诉主设备发生了什么错误。 主设备应用程序得到异议的回应后,典型的处理过程是重发消息,或者诊断发给从设备的消息并报告给操作员。 5、数据域 数据域是由两个十六进制数集合构成的,范围00...FF。根据网络传输模式,这可以是由一对ASCII字符组成或由一RTU字符组成。 从主设备发给从设备消息的数据域包含附加的信息:从设备必须用于进行执行由功能代码所定义的所为。这包括了象不连续的寄存器地址,要处理项的数目,域中实际数据字节数。 例如,如果主设备需要从设备读取一组保持寄存器(功能代码03),数据域指定了起始寄存器以及要读的寄存器数量。如果主设备写一组从设备的寄存器(功能代码10十六进制),数据域则指明了要写的起始寄存器以及要写的寄存器数量,数据域的数据字节数,要写入寄存器的数据。 如果没有错误发生,从从设备返回的数据域包含请求的数据。如果有错误发生,此域包含一异议代码,主设备应用程序可以用来判断采取下一步行动。 在某种消息中数据域可以是不存在的(0长度)。例如,主设备要求从设备回应通信事件记录(功能代码0B十六进制),从设备不需任何附加的信息。 6、错误检测域 标准的Modbus网络有两种错误检测方法。错误检测域的内容视所选的检测方法而定。 ASCII 当选用ASCII模式作字符帧,错误检测域包含两个ASCII字符。这是使用LRC(纵向冗长检测)方法对消息内容计算得出的,不包括开始的冒号符及回车换行符。LRC字符附加在回车换行符前面。 RTU 当选用RTU模式作字符帧,错误检测域包含一16Bits值(用两个8位的字符来实现)。错误检测域的内容是通过对消息内容进行循环冗长检测方法得出的。CRC域附加在消息的最后,添加时先是低字节然后是高字节。故CRC的高位字节是发送消息的最后一个字节。 7、字符的连续传输 当消息在标准的Modbus系列网络传输时,每个字符或字节以如下方式发送(从左到右): 最低有效位...最高有效位 使用ASCII字符帧时,位的序列是: 图4. 位顺序(ASCII) 图4. 位顺序(RTU) 、错误检测方法 标准的Modbus串行网络采用两种错误检测方法。奇偶校验对每个字符都可用,帧检测(LRC或CRC)应用于整个消息。它们都是在消息发送前由主设备产生的,从设备在接收过程中检测每个字符和整个消息帧。 用户要给主设备配置一预先定义的超时时间间隔,这个时间间隔要足够长,以使任何从设备都能作为正常反应。如果从设备测到一传输错误,消息将不会接收,也不会向主设备作出回应。这样超时事件将触发主设备来处理错误。发往不存在的从设备的地址也会产生超时。 1、奇偶校验 用户可以配置控制器是奇或偶校验,或无校验。这将决定了每个字符中的奇偶校验位是如何设置的。 如果指定了奇或偶校验,“1”的位数将算到每个字符的位数中(ASCII模式7个数据位,RTU中8个数据位)。例如RTU字符帧中包含以下8个数据位: 1 1 0 0 0 1 0 1 整个“1”的数目是4个。如果便用了偶校验,帧的奇偶校验位将是0,便得整个“1”的个数仍是4个。如果便用了奇校验,帧的奇偶校验位将是1,便得整个“1”的个数是5个。 如果没有指定奇偶校验位,传输时就没有校验位,也不进行校验检测。代替一附加的停止位填充至要传输的字符帧中。 2、LRC检测 使用ASCII模式,消息包括了一基于LRC方法的错误检测域。LRC域检测了消息域中除开始的冒号及结束的回车换行号外的内容。 LRC域是一个包含一个8位二进制值的字节。LRC值由传输设备来计算并放到消息帧中,接收设备在接收消息的过程中计算LRC,并将它和接收到消息中LRC域中的值比较,如果两值不等,说明有错误。 LRC方法是将消息中的8Bit的字节连续累加,丢弃了进位。 LRC简单函数如下: static unsigned char LRC(auchMsg,usDataLen) unsigned char *auchMsg ; /* 要进行计算的消息 */ unsigned short usDataLen ; /* LRC 要处理的字节的数量*/ { unsigned char uchLRC = 0 ; /* LRC 字节初始化 */ while (usDataLen--) /* 传送消息 */ uchLRC += *auchMsg++ ; /* 累加*/ return ((unsigned char)(-((char_uchLRC))) ; } 3、CRC检测 使用RTU模式,消息包括了一基于CRC方法的错误检测域。CRC域检测了整个消息的内容。 CRC域是两个字节,包含一16位的二进制值。它由传输设备计算后加入到消息中。接收设备重新计算收到消息的CRC,并与接收到的CRC域中的值比较,如果两值不同,则有误。 CRC是先调入一值是全“1”的16位寄存器,然后调用一过程将消息中连续的8位字节各当前寄存器中的值进行处理。仅每个字符中的8Bit数据对CRC有效,起始位和停止位以及奇偶校验位均无效。 CRC产生过程中,每个8位字符都单独和寄存器内容相或(OR),结果向最低有效位方向移动,最高有效位以0填充。LSB被提取出来检测,如果LSB为1,寄存器单独和预置的值或一下,如果LSB为0,则不进行。整个过程要重复8次。在最后一位(第8位)完成后,下一个8位字节又单独和寄存器的当前值相或。最终寄存器中的值,是消息中所有的字节都执行之后的CRC值。 CRC添加到消息中时,低字节先加入,然后高字节。 CRC简单函数如下: unsigned short CRC16(puchMsg, usDataLen) unsigned char *puchMsg ; /* 要进行CRC校验的消息 */ unsigned short usDataLen ; /* 消息中字节数 */ { unsigned char uchCRCHi = 0xFF ; /* 高CRC字节初始化 */ unsigned char uchCRCLo = 0xFF ; /* 低CRC 字节初始化 */ unsigned uIndex ; /* CRC循环中的索引 */ while (usDataLen--) /* 传输消息缓冲区 */ { uIndex = uchCRCHi ^ *puchMsgg++ ; /* 计算CRC */ uchCRCHi = uchCRCLo ^ auchCRCHi[uIndex} ; uchCRCLo = auchCRCLo[uIndex] ; } return (uchCRCHi << 8 | uchCRCLo) ; } /* CRC 高位字节值表 */ static unsigned char auchCRCHi[] = { 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40 } ; /* CRC低位字节值表*/ static char auchCRCLo[] = { 0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06, 0x07, 0xC7, 0x05, 0xC5, 0xC4, 0x04, 0xCC, 0x0C, 0x0D, 0xCD, 0x0F, 0xCF, 0xCE, 0x0E, 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09, 0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9, 0x1B, 0xDB, 0xDA, 0x1A, 0x1E, 0xDE, 0xDF, 0x1F, 0xDD, 0x1D, 0x1C, 0xDC, 0x14, 0xD4, 0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3, 0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3, 0xF2, 0x32, 0x36, 0xF6, 0xF7, 0x37, 0xF5, 0x35, 0x34, 0xF4, 0x3C, 0xFC, 0xFD, 0x3D, 0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A, 0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38, 0x28, 0xE8, 0xE9, 0x29, 0xEB, 0x2B, 0x2A, 0xEA, 0xEE, 0x2E, 0x2F, 0xEF, 0x2D, 0xED, 0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26, 0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60, 0x61, 0xA1, 0x63, 0xA3, 0xA2, 0x62, 0x66, 0xA6, 0xA7, 0x67, 0xA5, 0x65, 0x64, 0xA4, 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F, 0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB, 0x69, 0xA9, 0xA8, 0x68, 0x78, 0xB8, 0xB9, 0x79, 0xBB, 0x7B, 0x7A, 0xBA, 0xBE, 0x7E, 0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5, 0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71, 0x70, 0xB0, 0x50, 0x90, 0x91, 0x51, 0x93, 0x53, 0x52, 0x92, 0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C, 0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E, 0x5A, 0x9A, 0x9B, 0x5B, 0x99, 0x59, 0x58, 0x98, 0x88, 0x48, 0x49, 0x89, 0x4B, 0x8B, 0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C, 0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42, 0x43, 0x83, 0x41, 0x81, 0x80, 0x40 } ;  ModBus网络是一个工业通信系统,由带智能终端的可编程序控制器和计算机通过公用线路或局部专用线路连接而成。其系统结构既包括硬件、亦包括软件。它可应用于各种数据采集和过程监控。下表1是ModBus的功能码定义。 表1 ModBus功能码 ModBus网络只是一个主机,所有通信都由他发出。网络可支持247个之多的远程从属控制器,但实际所支持的从机数要由所用通信设备决定。采用这个系统,各PC可以和中心主机交换信息而不影响各PC执行本身的控制任务。表2是ModBus各功能码对应的数据类型。 表2 ModBus功能码与数据类型对应表 (1)ModBus的传输方式 在ModBus系统中有2种传输模式可选择。这2种传输模式与从机PC通信的能力是同等的。选择时应视所用ModBus主机而定,每个ModBus系统只能使用一种模式,不允许2种模式混用。一种模式是ASCII(美国信息交换码),另一种模式是RTU(远程终端设备)这两种模式的定义见表3 ASCII可打印字符便于故障检测,而且对于用高级语言(如Fortan)编程的主计算机及主PC很适宜。RTU则适用于机器语言编程的计算机和PC主机。 用RTU模式传输的数据是8位二进制字符。如欲转换为ASCII模式,则每个RTU字符首先应分为高位和低位两部分,这两部分各含4位,然后转换成十六进制等量值。用以构成报文的ASCII字符都是十六进制字符。ASCII模式使用的字符虽是RTU模式的两倍,但ASCII数据的译玛和处理更为容易一些,此外,用RTU模式时报文字符必须以连续数据流的形式传送,用ASCII模式,字符之间可产生长达1s的间隔,以适应速度较快的机器。 表4给出了以RTU方式读取整数据的例子 以RTU方式读取整数据的例子 十六进制数4124表示的十进制整数为16676,错误校验值要根据传输方式而定。 (2)ModBus的数据校验方式 CRC-16(循环冗余错误校验) CRC-16错误校验程序如下:报文(此处只涉及数据位,不指起始位、停止位和任选的奇偶校验位)被看作是一个连续的二进制,其最高有效位(MSB)首选发送。报文先与X↑16相乘(左移16位),然后看X↑16+X↑15+X↑2+1除,X↑16+X↑15+X↑2+1可以表示为二进制数11000000000000101。整数商位忽略不记,16位余数加入该报文(MSB先发送),成为2个CRC校验字节。余数中的1全部初始化,以免所有的零成为一条报文被接收。经上述处理而含有CRC字节的报文,若无错误,到接收设备后再被同一多项式(X↑16+X↑15+X↑2+1)除,会得到一个零余数(接收设备核验这个CRC字节,并将其与被传送的CRC比较)。全部运算以2为模(无进位)。 习惯于成串发送数据的设备会首选送出字符的最右位(LSB-最低有效位)。而在生成CRC情况下,发送首位应是被除数的最高有效位MSB。由于在运算中不用进位,为便于操作起见,计算CRC时设MSB在最右位。生成多项式的位序也必须反过来,以保持一致。多项式的MSB略去不记,因其只对商有影响而不影响余数。 生成CRC-16校验字节的步骤如下: ①装如一个16位寄存器,所有数位均为1。 ②该16位寄存器的高位字节与开始8位字节进行“异或”运算。运算结果放入这个16位寄存器。 ③把这个16寄存器向右移一位。 ④若向右(标记位)移出的数位是1,则生成多项式1010000000000001和这个寄存器进行“异或”运算;若向右移出的数位是0,则返回③。 ⑤重复③和④,直至移出8位。 ⑥另外8位与该十六位寄存器进行“异或”运算。 ⑦重复③~⑥,直至该报文所有字节均与16位寄存器进行“异或”运算,并移位8次。 ⑧这个16位寄存器的内容即2字节CRC错误校验,被加到报文的最高有效位。 另外,在某些非ModBus通信协议中也经常使用CRC16作为校验手段,而且产生了一些CRC16的变种,他们是使用CRC16多项式X↑16+X↑15+X↑2+1,单首次装入的16位寄存器为0000;使用CRC16的反序X↑16+X↑14+X↑1+1,首次装入寄存器值为0000或FFFFH。 LRC(纵向冗余错误校验) LRC错误校验用于ASCII模式。这个错误校验是一个8位二进制数,可作为2个ASCII十六进制字节传送。把十六进制字符转换成二进制,加上无循环进位的二进制字符和二进制补码结果生成LRC错误校验(参见图)。这个LRC在接收设备进行核验,并与被传送的LRC进行比较,冒号(:)、回车符号(CR)、换行字符(LF)和置入的其他任何非ASCII十六进制字符在运算时忽略不计。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值