MODBUS_RTU协议:是指国际上通用的 MODBUS_RTU议。以后简称MODBUS协议。详见《MODBUS协议中文版》官方文档。
JM_MOD协议:是指完全在遵循MODBUS_RTU 协议的规则下,为了适应某些捷麦公司的设备和应用场景对MODBUS_RTU协议做了更细致定义的协议。 支持JM_MOD协议的设备或软件接口可与任何标准MODBUS主机或设备直接通信。
JM_BUS协议:是指基于JM_MOD协议,为了 适应远程测控一个站点的各种数据一次采集的特性做了相应改动的协议。此协议不遵循MODBUS_RTU, 不能与标准MODBUS主机或设备直接通信。详见《JMBUS协议说明》。
本协议适用于JM公司所有标明“支持MODBUS协议”的硬件设 备和应用软件。例如T40S无线PLC、KZ04扩展模块、远程通PC组态和远程通手机组态等。
JM_MOD的数据通信指令为标准的MODBUS_RTU协议,以下为 MODBUS的基本协议规范。
图1. 通用的MODBUS帧
图2:MODBUS事务处理(无差错)
图3:MODBUS事务处理(异常响应)
下文中,讲接收数据并处理响应的“服务器”称之 为“MODBUS从机”。
JM_MOD 使用一个‘big-Endian’ 表示地址和数据项。这意 味着当发射多个字节时,首先发送最高有效位。例如:
寄存器大小 | 值 | |
16-比特 | 0x1234 | 发送的第一字节为0x12然后0x34 |
同样的道理,如果传送实数数据时,首先发送最高有效位, 最后发送最低位(组态软件中的HV1 HV2 HV3 HV4)。
特例:起始地址为330001和430001的浮点型数据内容是小端模式,组态软件中的HV4 HV3 HV2 HV1。
JM_MOD以一系列具有不同特征的数据模型为基础。几个基本数据模型为:
基本类型 | 对象类型 | 属性 | 内容 | 常用符号 |
离散量输入 | 单个bit | 只读 | I/O 系统提供数据 | DI、I*.* |
线圈 | 单个bit | 读写 | 通过应用程序改变数据 | DO、Q*.* |
整数输入存储区 | 16bit | 只读 | I/O 系统提供数据 | -- |
字节输入存储区 | 8bit | 只读 | I/O 系统提供数据 | -- |
实数输入存储区 | 32bit | 只读 | I/O 系统提供数据 | AI |
整数保持存储区 | 16bit | 读写 | 通过应用程序改变数据 | -- |
字节保持存储区 | 8bit | 读写 | 通过应用程序改变数据 | V |
实数保持存储区 | 32bit | 读写 | 通过应用程序改变数据 | AQ |
由于MODBUS协议中没有所有的字节和实数的定义,而只有一个笼统的“04输入寄存器和03/06/10保持寄存器”的说法。在JM_MOD协议中需要在借用MODBUS协议中的偏移地址的最高位的值和命令码来区分设备中的不同存储区,详见下一章节。
定义汇总,字节和实数部分本文说明,离散和整数部分在“上篇”中说明。
存储区名称 | 意义 | 功能码 | 地址(标准表示) | 数据类型 | 传输形式 |
离散输入 | 读离散输入 | 02 | 0 (10001) | bit | bit |
离散输出 | 读离散输出 | 01 | 0 (00001) | bit | bit |
写单个离散输出 | 05 | 0 (00001) | bit | bit | |
写多个离散输出 | 0x0F | 0 (00001) | bit | bit | |
字节输入 | 读字节输入 | 04 | 10000 (310001) | 16bit | 16bit |
字节输出 | 读字节输出 | 03 | 10000 (410001) | 16bit | 16bit |
写单个字节输出 | 06 | 10000 (410001) | 16bit | 16bit | |
写多个字节输出 | 0x10 | 10000 (410001) | 16bit | 16bit | |
整数输入 | 读整数输入 | 04 | 0 (30001) | 8bit | 16bit |
整数输出 | 读整数输出 | 03 | 0 (30001) | 8bit | 16bit |
写单个整数输出 | 06 | 0 (30001) | 8bit | 16bit | |
写多个整数输出 | 0x10 | 0 (30001) | 8bit | 16bit | |
实数输入 | 读实数输入 | 04 | 30000 (330001) | 32bit | 16bit |
实数输出 | 读实数输出 | 03 | 30000 (430001) | 32bit | 16bit |
写单个实数输出 | 06 | 30000 (430001) | 32bit | 16bit | |
写多个实数输出 | 0x10 | 30000 (430001) | 32bit | 16bit |
这个功能代码是用来读MODBUS从机相邻的字节(8bit)输入 存储区单元。请求协议数据单元详细说明了寄存器的起始地址和读出数量。每个存储区单元占1个字 节。正常的响应会返回功能代码,读出的寄存器的数量及内容。
字节输入存储区的开始偏移地址:10000 (1388H)
请求协议数据单元
功能代码 | 1字节 | 04H |
起始地址 | 2字节 | 2710H到7530H |
*寄存器个数 (字节存储区2倍) | 2字节 | 0001H-007DH |
*寄存器个数:由于字节输入存储区单元占1个字节,而标准 MODBUS协议中读输入寄存器采用2个字节,因此此处的寄存器个数是指是读取了两倍的字节寄存器数 量。例如在协议中寄存器个数为2,表示要读取4个字节存储区单元。
响应协议数据单元
功能代码 | 1字节 | 04H |
字节数 | 1 个字节 | *N |
寄存器的内容 | *N 个字节 |
*N=输入字节寄存器的数量
注意:由于每个字节存储区单元占用一个字节,而MODBUS读输入寄存器是两个字节,因此,每一个 偏移地址对应着两个字节存储区单元,由于字节存储区的开始偏移地址是从10000(2710H)开始的, 因此偏移地址10000就是字节存储区的1和2,偏移地址N就是字节存储区(N-10000)*2+1和字节存储区 (N-10000)*2+2。从这个定于可以看出,一次至少可读取两个字节存储区单元。
下例是从字节输入存储区3开始读4个存储区单元,读取的内 容为00 0A和01 02。
请求 | 响应 | ||
字段名称 | (Hex) | 字段名称 | (Hex) |
功能 | 04 | 功能 | 04 |
起始地址高位 | 27 | 字节数 | 04 |
起始地址低位 | 11 | 单元3 | 00 |
寄存器个数高位 | 00 | 单元4 | 0A |
寄存器个数低位 | 02 | 单元5 | 01 |
单元6 | 02 |
这个功能代码是用来读MODBUS从机相邻的字节(8bit)输出 存储区单元。请求协议数据单元详细说明了寄存器的起始地址和读出数量。每个存储区单元占1个字 节。正常的响应会返回功能代码,读出的寄存器的数量及内容。
字节输出存储区的开始偏移地址:10000 (2710H)
请求协议数据单元
功能代码 | 1字节 | 03H |
起始地址 | 2字节 | 2710H到7530H |
*寄存器个数 (字节存储区2倍) | 2字节 | 0001H-007DH |
*寄存器个数:由于字节输出存储区单元占1个字节,而标准 MODBUS协议中读输出寄存器采用2个字节,因此此处的寄存器个数是指是读取了两倍的字节寄存器数 量。例如在协议中寄存器个数为2,表示要读取4个字节存储区单元。
响应协议数据单元
功能代码 | 1字节 | 03H |
字节数 | 1 个字节 | *N |
寄存器的内容 | *N 个字节 |
*N=输出字节寄存器的数量
注意:由于每个字节存储区单元占用一个字节,而MODBUS读输出寄存器是两个字节,因此,每一个 偏移地址对应着两个字节存储区单元,由于字节存储区的开始偏移地址是从10000(2710H)开始的, 因此偏移地址10000就是字节存储区的1和2,偏移地址N就是字节存储区(N-10000)*2+1和字节存储区 (N-10000)*2+2。从这个定义可以看出,一次至少可读取两个字节存储区单元。
下例是从字节输出存储区3开始读4个存储区单元,读取的内 容为00 0A和01 02。
请求 | 响应 | ||
字段名称 | (Hex) | 字段名称 | (Hex) |
功能 | 03 | 功能 | 03 |
起始地址高位 | 27 | 字节数 | 04 |
起始地址低位 | 11 | 单元3 | 00 |
寄存器个数高位 | 00 | 单元4 | 0A |
寄存器个数低位 | 02 | 单元5 | 01 |
单元6 | 02 |
这个功能代码是用来写MODBUS从机两个字节(8bit)输出存 储区单元。请求协议数据单元详细说明了寄存器的起始地址、数值。每个存储区单元占1个字节。正 常的响应会返回功能代码、起始地址和寄存器数值。
*两个字节输出存储单元:由于字节输出存储区单元占1个字 节,而标准MODBUS协议中写输出寄存器采用2个字节。所以对于MOD-BUS06指令为写单个寄存器,到这 里就成了写两个字节输出寄存器。
字节输出存储区的开始偏移地址:10000(2710H)
请求协议数据单元
功能代码 | 1字节 | 06H |
起始地址 | 2字节 | 2710H到7530H |
数据 | 2字节 | 0-FFFFH值 |
响应协议数据单元
功能代码 | 1字节 | 06H |
起始地址 | 2字节 | 2710H到7530H |
数据 | 2字节 | 0-FFFFH值 |
注意:由于每个整数存储区单元占用两个字节,而MODBUS读输出寄存器也是两个字节,因此,每一 个偏移地址正好一一对应着每个整数存储区单元,由于整数存储区的开始偏移地址是从0000H开始的 ,因此偏移地址00就是整数存储区单元1,偏移地址N就是整数存储区单元N+1。
下面这个例子是写从字节输出寄存器3开始的内容为00、 03 :
请求 | 响应 | ||
字段名称 | (Hex) | 字段名称 | (Hex) |
功能 | 06 | 功能 | 06 |
起始地址高位 | 27 | 起始地址高位 | 13 |
起始地址低位 | 11 | 起始地址低位 | 89 |
寄存器值高位 | 00 | 寄存器值高位 | 00 |
寄存器值低位 | 03 | 寄存器值低位 | 03 |
这个功能代码是用来写MODBUS从机相邻的字节(8bit)输出 存储区单元。请求协议数据单元详细说明了寄存器的起始地址、数量和内容。每个存储区单元占1个 字节。正常的响应会返回功能代码和起始地址。
字节输出存储区的开始偏移地址:10000 (2710H)
请求协议数据单元
功能代码 | 1字节 | 10H |
起始地址 | 2字节 | 2710H到7530H |
寄存器个数 (字节存储区2倍) | 2字节 | 0001H-007DH |
字节数 | 1字节 | *N |
数据 | *N | 值 |
*N=输出字节寄存器的数量
响应协议数据单元
功能代码 | 1字节 | 10H |
起始地址 | 2字节 | 2710H到7530H |
寄存器个数 | 2字节 | 0001H-007DH |
注意:由于字节寄存器占用一个字节,而MODBUS写输出寄存器是两个字节,因此,每一个偏移地址 对应着两个字节寄存器,由于整数存储区的开始偏移地址区从10000(2710H)开始的,因此偏移地址 10000就是字节寄存器1和2,偏移地址N就是字节存储区(N-10000)*2+1和字节存储区(N-10000)*2+2。 从这个定于可以看出,写字节输出存储区一次至少写两个。
下面这个例子是写从字节输出寄存器3开始的内容为00、 0A 、01和 02到存储区中:
请求 | 响应 | ||
字段名称 | (Hex) | 字段名称 | (Hex) |
功能 | 10 | 功能 | 10 |
起始地址高位 | 27 | 起始地址高位 | 00 |
起始地址低位 | 11 | 起始地址低位 | 01 |
寄存器个数高位 | 00 | 寄存器个数高位 | 00 |
寄存器个数低位 | 02 | 寄存器个数低位 | 02 |
字节数 | 04 | ||
单元3 | 00 | ||
单元4 | 0A | ||
单元5 | 01 | ||
单元6 | 02 |
这个功能代码是用来读MODBUS从机相邻的实数(32bit)输入 存储区单元。请求协议数据单元详细说明了寄存器的起始地址和读出数量。每个寄存器为4个字节。 正常的响应会返回功能代码,读出的寄存器的数量及内容。
实数输入存储区的开始偏移地址:30000 (7530H)
请求协议数据单元
功能代码 | 1字节 | 04H |
起始地址 | 2字节 | 7530H到9C40H |
*寄存器个数 (实数存储区单元个数1/2) | *2字节 | 0001H-007DH |
*寄存器个数:由于每个实数输入存储区单元占4个字节,而 标准MODBUS协议中读输入寄存器采用2个字节,因此此处的每一个寄存器个数是指是读取半个实数存 储区单元的数量。例如在协议中寄存器个数为2,表示要读取1个实数存储区单元。
响应协议数据单元
功能代码 | 1字节 | 04H |
字节数 | 1 个字节 | *N ×4 |
寄存器的内容 | *N×4 个字节 |
*N=输入实数寄存器的数量
注意:由于每个实数储存单元占用4个字节,而MODBUS读输入寄存器是两个字节,因此,每两个偏 移地址对应着一个实数存储区单元,由于实数存储区的开始偏移地址从30000(7530H)开始的,因此 偏移地址30000和30001就是实数存储区0,偏移地址N(N为偶数)就是实数存储区(N-30000)/2+1。从 这个定于可以看出,读实数输入存储区必须是从偏移地址是偶数位置开始的(0,2,4,6…)。
下例是从实数输入存储区单元2开始读1个单元,值内容为 3.14(C3 F5 48 40) ( 40 48 F5 C3)
请求 | 响应 | ||
字段名称 | (Hex) | 字段名称 | (Hex) |
功能 | 04 | 功能 | 04 |
起始地址高位 | 75 | 字节数 | 04 |
起始地址低位 | 34 | 单元2-1/4 | C3 |
寄存器个数高位 | 00 | 单元2-2/4 | F5 |
寄存器个数低位 | 02 | 单元2-3/4 | 48 |
单元2-4/4 | 40 |
这个功能代码是用来读MODBUS从机相邻的实数(32bit)输出 存储区单元。请求协议数据单元详细说明了寄存器的起始地址和读出数量。每个寄存器为4个字节。 正常的响应会返回功能代码,读出的寄存器的数量及内容。
实数输出存储区的开始偏移地址:30000 (7530H)
请求协议数据单元
功能代码 | 1字节 | 03H |
起始地址 | 2字节 | 7530H到9C40H |
*寄存器个数 (实数存储单元个数1/2) | *2字节 | 0001H-007DH |
*寄存器个数:由于每个实数输出存储区单元占4个字节,而 标准MODBUS协议中读输出寄存器采用2个字节,因此此处的每一个寄存器个数是指是读取半个实数存 储区单元的数量。例如在协议中寄存器个数为2,表示要读取1个实数存储区单元。
响应协议数据单元
功能代码 | 1字节 | 03H |
字节数 | 1 个字节 | *N ×4 |
寄存器的内容 | *NX4个字节 |
*N=输出实数寄存器的数量
注意:由于每个实数储存单元占用4个字节,而MODBUS读输出寄存器是两个字节,因此,每两个偏 移地址对应着一个实数存储区单元,由于实数存储区的开始偏移地址从30000(7530H)开始的,因此 偏移地址30000和30001就是实数存储区0,偏移地址N(N为偶数)就是实数存储区(N-30000)/2+1。从 这个定于可以看出,读实数输出存储区必须是从偏移地址是偶数位置开始的(0,2,4,6…)。
下例是从实数输出存储区单元2开始读1个单元,值内容为 3.14(C3 F5 48 40)
请求 | 响应 | ||
字段名称 | (Hex) | 字段名称 | (Hex) |
功能 | 03 | 功能 | 03 |
起始地址高位 | 75 | 字节数 | 04 |
起始地址低位 | 34 | 单元2-1/4 | C3 |
寄存器个数高位 | 00 | 单元2-2/4 | F5 |
寄存器个数低位 | 02 | 单元2-3/4 | 48 |
单元2-4/4 | 40 |
这个功能代码是用来写MODBUS从机相邻的实数(32bit)输出 存储区单元。请求协议数据单元详细说明了寄存器的起始地址、数量和内容。每个寄存器为4个字节 。正常的响应会返回功能代码和起始地址。
实数输出存储区的开始偏移地址:30000 (7530H)
请求协议数据单元
功能代码 | 1字节 | 10H |
起始地址 | 2字节 | 7530H到9C40H |
寄存器个数 (实数存储单元个数1/2) | 2字节 | 0001H-007DH |
字节数 | 1字节 | *N×4 |
数据 | *N | 值 |
*寄存器个数:由于每个实数输出存储区单元占4个字节,而 标准MODBUS协议中写输出寄存器采用2个字节,因此此处的每一个寄存器个数是指是写半个实数存储 区单元的数量。例如在协议中寄存器个数为2,表示要写1个实数存储区单元。
响应协议数据单元
功能代码 | 1字节 | 10H |
起始地址 | 2字节 | 7530H到9C40H |
寄存器个数 | 2字节 | 0001H-007DH |
注意:由于每个实数储存单元占用4个字节,而MODBUS写输出寄存器是两个字节,因此,每两个偏 移地址对应着一个实数存储区单元,由于实数存储区的开始偏移地址从30000(7530H)开始的,因此 偏移地址30000和30001就是实数存储区0,偏移地址N(N为偶数)就是实数存储区(N-30000)/2+1。从 这个定于可以看出,读实数输出存储区必须是从偏移地址是偶数位置开始的(0,2,4,6…)。
下例是写内容为3.14(C3 F5 48 40)到实数输出存储区单元 2开始的存储区中:
请求 | 响应 | ||
字段名称 | (Hex) | 字段名称 | (Hex) |
功能 | 10 | 功能 | 10 |
起始地址高位 | 75 | 起始地址高位 | 75 |
起始地址低位 | 32 | 起始地址低位 | 32 |
寄存器个数高位 | 00 | 寄存器个数高位 | 00 |
寄存器个数低位 | 02 | 寄存器个数低位 | 02 |
字节数 | 04 | ||
数据值VOD2高字节 | C3 | ||
数据值VOD2低字节 | F5 | ||
数据值VOD3高字节 | 48 | ||
数据值VOD3低字节 | 40 |