初步学习通讯协议之modbus
学习协议需要学习进制转换,下面是在线转换的网址,可以辅助学习:
二进制十进制八进制十六进制在线转换
ASCII编码转换
学习可以看下
- Modbus 通信协议详解(学习一下modbus的理论知识)
- MODBUS协议最简单又是最直白的解释
- modbus协议中的线圈、寄存器等的解释(方便学习理解协议功能码)
modus-rtu协议功能码说明
格式:
一整个指令称为ADU(应用数据单元)
功能码+数据称之为PDU(协议数据单元)
地址域 | 功能码 | 数据 | 差错校验 |
---|---|---|---|
一个字节 | 一个字节 | 若干个 | 两个字节 |
0x01: 读线圈寄存器
发送:地址域(1字节),功能码(1字节),起始地址(2字节),线圈数量(2字节),校验位(2字节)
接收:地址域(1字节),功能码(1字节),字节数N(1字节),线圈状态(N字节),校验位(2字节)
错误:地址域(1字节),功能码(1字节),错误代码(1字节)(01/02/03/04)
N=输入点个数/8,如果余数不为0,则N=N+1
例如:
读取36个线圈的状态
发送:
地址域(1字节) | 功能码(1字节) | 起始地址(2字节) | 线圈数量(2字节) | 校验位(2字节) |
---|---|---|---|---|
01 | 01 | 00 00 | 00 24 | FD CD |
注:十六进制,36十六进制为24
返回:
地址域(1字节) | 功能码(1字节) | 字节数N(1字节) | 线圈状态1(1字节) | 线圈状态2(1字节) | 线圈状态3(1字节) | 线圈状态4(1字节) | 线圈状态5(1字节) | 校验位(2字节) |
---|---|---|---|---|---|---|---|---|
01 | 01 | 05 | 0F | 03 | 80 | 01 | 01 | FD CD |
05=36/8 — 4余4,余数不为0,n=n+1,4+1=5 | 0F十六进制转二进制00 00 11 11 ,则八个线圈的状态出来了。 | 不够8位,字节高位填充为0,00 00 00 01,前四位为不够八位填充的0 |
0x02: 读离散输入寄存器
发送:地址域(1字节),功能码(1字节),起始地址(2字节),输入点数量N(2字节),校验位(2字节)
接收:地址域(1字节),功能码(1字节),字节数N(1字节),输入点状态(N字节),校验位(2字节)
错误:地址域(1字节),功能码(1字节),错误代码(1字节)(01/02/03/04)
N=输入点个数/8,如果余数不为0,则N=N+1
线圈的状态是用bit来表示的,查询的线圈数量要小于8的最小倍数。
如果查询线圈的个数,对8取余不等于零,则返回的字节数为对8整除+1.
(和读取线圈状态类似,不举例说明了)
0x03: 读保持寄存器
发送:地址域(1字节),功能码(1字节),起始地址(2字节),寄存器数量N(2字节),校验位(2字节)
接收:地址域(1字节),功能码(1字节),字节数N2(1字节),寄存器值(N2字节),校验位(2字节)
错误:地址域(1字节),功能码(1字节),错误代码(1字节)(01/02/03/04)
N= 寄存器数量
例如:
读取3个保持寄存器
发送:
地址域(1字节) | 功能码(1字节) | 起始地址(2字节) | 寄存器数量(2字节) | 校验位(2字节) |
---|---|---|---|---|
01 | 03 | 00 00 | 00 03 | FD CD |
注:十六进制,3十六进制为3
返回:
地址域(1字节) | 功能码(1字节) | 字节数N*2(1字节) | data1(2字节) | data2(2字节) | data3(2字节) | 校验位(2字节) |
---|---|---|---|---|---|---|
01 | 03 | 06 | 00 01 | 00 01 | 00 01 | FD CD |
每个寄存器的值由2个byte组成 |
0x04: 读输入寄存器
发送:功能码(1字节),起始地址(2字节),寄存器数量(2字节)
接收:功能码(1字节),字节数N2(1字节),寄出去你值(N2字节)
错误:功能码(1字节),错误代码(1字节)(01/02/03/04)
(和读取保持寄存器类似,不举例说明了)
0x05: 写单个线圈寄存器
发送:功能码(1字节),线圈地址(2字节),写入值(2字节)
接收:功能码(1字节),线圈地址(2字节),写入值(2字节)
错误:功能码(1字节),错误代码(1字节)(01/02/03/04)
写单个线圈寄存器。FF00H值请求线圈处于ON状态,0000H值请求线圈处于OFF状态。05H指令设置单个线圈的状态,15H指令可以设置多个线圈的状态,两个指令虽然都设定线圈的ON/OFF状态,但是ON/OFF的表达方式却不同。
例如:
发送:
地址域(1字节) | 功能码(1字节) | 线圈地址(2字节) | 写入状态(2字节) | 校验位(2字节) |
---|---|---|---|---|
01 | 05 | 00 00 | FF 00 | FD CD |
*注:FF00是设置线圈状态为ON
返回:
地址域(1字节) | 功能码(1字节) | 线圈地址(2字节) | 写入状态(2字节) | 校验位(2字节) |
---|---|---|---|---|
01 | 05 | 00 00 | FF 00 | FD CD |
0x06: 写单个保持寄存器
发送:功能码(1字节),寄存器地址(2字节),写入值(2字节)
接收:功能码(1字节),寄存器地址(2字节),写入值(2字节)
错误:功能码(1字节),错误代码(1字节)(01/02/03/04)
(和05写单一寄存器类似)
0x0f: 写多个线圈寄存器
发送:功能码(1字节),起始地址(2字节),写入线圈个数N(2字节),写入字节数N(1字节),写入值(N字节)
接收:功能码(1字节),起始地址(2字节),写入线圈个数(2字节)
错误:功能码(1字节),错误代码(1字节)(01/02/03/04)
- N= 写入线圈的个数/8,如果余数不为0,则N= N+1
- 写多个线圈寄存器。若数据区的某位值为“1”表示被请求的相应线圈状态为ON,若某位值为“0”,则为状态为OFF。
- 线圈的个数来判断写入的字节数,每个线圈的状态使用bit位来表示。
0x10: 写多个保持寄存器
发送:功能码(1字节),起始地址(2字节),写入寄存器个数N(2字节),写入字节数N2(1字节),写入值(N2字节)
接收:功能码(1字节),起始地址(2字节),写入寄存器个数(2字节)
错误:功能码(1字节),错误代码(1字节)(01/02/03/04)
- N = 写入寄存器的个数