haas506 2.0开发教程-高级组件库-modbus
1.Modbus slave仿真软件的使用
-
Modbus是一种串行通信协议,是Modicon公司(现在的施耐德电气 Schneider Electric)于1979年为使用可编程逻辑控制器(PLC)通信而发表。Modbus已经成为工业领域通信协议的业界标准(Defacto),并且现在是工业电子设备之间常用的连接方式。 -
modbus报文模型 -
Modbus Slave是Modbus子设备模拟工具,模拟设备发送串口信号。可以仿真32个从设备/地址域。每个接口都提供了对excel报表的OLE自动化支持。帮助Modbus通讯设备开发人员进行Modbus通讯协议的模拟和测试,用于模拟、测试、调试Modbus通讯设备。与Modbus Poll的用户界面相同,支持功能01, 02, 03, 04, 05, 06, 15, 16, 22 和23,监视串口数据。
(1)打开仿真软件 (2)点击setup进行slave definition ?在slave definition中设置Slave ID(modbus从机ID)、Function(功能)、Address(地址)、Quantity(寄存器个数)、数据显示的格式等。 ? ?(3)编辑寄存器的值 框选所有数据,选择Display - Unsigned ??双击当前值,跳出一个Edit Register编辑框,修改寄存器的值 全部修改后如下图所示: ????当前数据显示是无符号整型格式,若想修改数据的显示格式,可以点击软件窗口栏中的”Display"选择一个合适的数据格式。 例如选择“HEX"之后,数据显示如下图所示: (4)Connection连接配置 ??点击软件窗口栏中的Connection选项,进行连接配置。 ?配置项:Connection选择”Serial Port“,Port需要选择设备的RS485的串口端口号,例如当前设备的RS485的端口号为COM26(从我的电脑-设备管理器获取),那么Port就选择Port26。波特率选择9600(Modbus采用串口通信时的串口波特率,默认为 9600)、数据位选择"8 Data bits"、奇偶校验选择”None Parity-不校验"、停止位选择"1 stop bit"。 ?详细的配置项如下图所示:
设置完毕
2.案例
案例说明:
- 使用Modbus slave工具,进行读写串口数据功能测试
- 需要连接TTL与RS485串口,modbus使用RS485进行通信。
案例一
- 对保持寄存器(holdRegister)进行数据读取和数据写入
1、烧录代码
main.py
import modbus
import utime as time
time.sleep(5)
modbus.init('modbus')
readBuf=bytearray(20)
modbus.readHoldingRegisters(1,0,10,readBuf,1000)
print('read data from register:',readBuf)
time.sleep(5)
modbus.writeHoldingRegister(1,0,200,1000)
modbus.readHoldingRegisters(1,0,10,readBuf,1000)
print("read register again:",readBuf)
modbus.deinit()
board.json
{
"name": "haas506",
"version": "2.0.0",
"io": {
"serial1":{
"type":"UART",
"port":0,
"dataWidth":8,
"baudRate":115200,
"stopBits":1,
"flowControl":"disable",
"parity":"none"
},
"serial2":{
"type":"UART",
"port":1,
"dataWidth":8,
"baudRate":115200,
"stopBits":1,
"flowControl":"disable",
"parity":"none"
},
"modbus":{
"type":"MODBUS",
"mode":0,
"port":2,
"baudrate":9600,
"timeout":1000,
"parity":0
}
},
"debugLevel": "ERROR",
"repl":"enable",
"replPort":0
}
2、日志输出 打开串口助手,查看打印的日志信息
read data from register: bytearray(b'\x00\x00\xff\xff\x01\x00\xff\xff\x02\x00\xff\xff\x03\x00\xff\xff\x04\x00\xff\xff')
read register again: bytearray(b'\xc8\x00\xff\xff\x01\x00\xff\xff\x02\x00\xff\xff\x03\x00\xff\xff\x04\x00\xff\xff')
注意:每个寄存器包含高低2个字节,寄存器数据按照大端字节序排列,大端就是一个数据的低字节在高地址,高字节在低地址。例如地址为0的寄存器的数据是0x00C8,那么输出的时候,先输出C8然后输出00。
案例二
main.py
import modbus
import utime
utime.sleep(5)
modbus.init('modbus')
readBuf=bytearray(10)
modbus.readHoldingRegisters(1,0,5,readBuf,1000)
print('read data from register:',readBuf)
print("write data into register...")
writeBuf=bytearray([0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00])
ret=modbus.writeMultipleHoldingRegisters(1, 0, 5, writeBuf, 1000)
print("----ret=",ret)
modbus.readHoldingRegisters(1,0,5,readBuf,1000)
print("read register again:",readBuf)
modbus.deinit()
board.json
{
"name": "haas506",
"version": "2.0.0",
"io": {
"serial1":{
"type":"UART",
"port":0,
"dataWidth":8,
"baudRate":115200,
"stopBits":1,
"flowControl":"disable",
"parity":"none"
},
"serial2":{
"type":"UART",
"port":1,
"dataWidth":8,
"baudRate":115200,
"stopBits":1,
"flowControl":"disable",
"parity":"none"
},
"modbus":{
"type":"MODBUS",
"mode":0,
"port":2,
"baudrate":9600,
"timeout":1000,
"parity":0
}
},
"debugLevel": "ERROR",
"repl":"enable",
"replPort":0
}
日志
read data from register: bytearray(b'\x00\x00\xff\xff\x01\x00\xff\xff\x02\x00')
write data into register...
read register again: bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')
原始数据表
修改后的数据表
案例三
读取多个输入寄存器(InputRegisters)的值
在仿真软件中如下设置: (1)创建一张表
2)在slave definition中,选择Function中的 input Registers,注意当前设备的id是1。 (3)适当修改几个寄存器的值 main.py
import modbus as mb
import utime as time
def modbus_test():
readBuf = bytearray(10)
ret = mb.readInputRegisters(1, 0, 5, readBuf, 200)
print(ret)
print('readBuf:',readBuf)
if __name__ == '__main__':
mb.init('modbus')
while True:
time.sleep(1)
modbus_test()
board.json
{
"name": "haas506",
"version": "2.0.0",
"io": {
"serial1":{
"type":"UART",
"port":0,
"dataWidth":8,
"baudRate":115200,
"stopBits":1,
"flowControl":"disable",
"parity":"none"
},
"serial2":{
"type":"UART",
"port":1,
"dataWidth":8,
"baudRate":115200,
"stopBits":1,
"flowControl":"disable",
"parity":"none"
},
"modbus":{
"type":"MODBUS",
"mode":0,
"port":2,
"baudrate":9600,
"timeout":1000,
"parity":0
}
},
"debugLevel": "ERROR",
"repl":"enable",
"replPort":0
}
(4)日志 代码执行过程中会输出两个值,分别是readInputRegisters()函数的状态返回值和前5个寄存器中的值
(0, 10)
readBuf: bytearray(b'\x00\x00\x01\x00\x02\x00\x03\x00\x04\x00')
(0, 10)
readBuf: bytearray(b'\x00\x00\x01\x00\x02\x00\x03\x00\x04\x00')
(0, 10)
......
modbus.init(nodeName) - 初始化Modbus
函数功能:根据board.json中设备节点的配置初始化Modbus总线
参数说明:
参数 | 类型 | 必选参数? | 说明 |
---|
nodeName | string | 是 | board.json配置文件中Modbus设备节点的名称 |
board.json中的UART类型设备属性配置项说明如下:
属性字段 | 数据类型 | 属性值 | 必选项? | 字段说明 |
---|
type | string | MODBUS | 是 | 节点类型,表明当前节点为Modbus节点,固定设置为MODBUS | mode | int | 0、1 | 是 | Modbus物理通道类型,0表示串口,1表示TCP以太网。目前仅支持串口通道 | port | int | 0、1 等 | 否 | Modbus采用串口通信时的串口号 | baudrate | int | 9600、115200等 | 否 | Modbus采用串口通信时的串口波特率,默认为 9600 | timeout | int | 200, 1000等 | 否 | Modbus采用串口通信时的超时参数,单位是毫秒(ms),默认为200ms | parity | int | 0、1、2 | 否 | 奇偶校验设置,默认 0 |
返回值:打开Modbus设备成功返回0;打开UART设备失败返回失败错误码
modbus.deinit() - 关闭Modbus
函数功能:反初始化Modbus总线
注意事项:需确保要关闭的Modbus处于init状态
参数说明:无
返回值:反初始化Modbus设备成功返回0;反初始化Modbus设备失败返回失败错误码
UART.writeHoldingRegister(slave_addr, register_addr, register_value, timeout) - 写单个保持寄存器
函数功能:向从机写单个保持寄存器
注意事项:需确保此UART处于open状态
参数说明:
参数 | 类型 | 必选参数? | 说明 |
---|
slave_addr | int | 是 | 请求的从机地址,0代表广播 | register_addr | int | 是 | 写寄存器的地址 | register_value | int | 是 | 写寄存器的数据 | timeout | int | 是 | 请求超时时间,单位是毫秒(ms) |
返回值:返回一个tuple类型的4元组,元组中的条目格式为:
status | 请求状态,0表示成功,其他表示失败,具体含义参考 STATUS |
---|
resp_addr | 响应地址 | resp_value | 响应数据 | exception_code | 响应异常代码 |
modbus.writeMultipleHoldingRegisters(slave_addr, start_addr, reg_quantity, data, timeout) - 写多个保持寄存器
函数功能:向从机多个保持寄存器中写入数据
注意事项:需确保此Modbus处于init状态
参数说明:
参数 | 类型 | 必选参数? | 说明 |
---|
slave_addr | int | 是 | 请求的从机地址,0代表广播 | register_addr | int | 是 | 待写寄存器的起始地址 | reg_quantity | int | 是 | 待写寄存器的数量,表示操作多少个寄存器 | data | bytearray | 是 | 写寄存器的数据,每个寄存器包含高低两个字节,高位在前,低位在后 | timeout | int | 是 | 请求超时时间,单位是毫秒(ms) |
返回值:返回一个tuple类型的4元组,元组中的条目格式为:
status | 请求状态,0表示成功,其他表示失败,具体含义参考 STATUS |
---|
resp_addr | 响应地址 | resp_quantity | 真实完成寄存器操作的数量 | exception_code | 响应异常代码 |
modbus.writeCoil(slave_addr, coil_addr, coil_value, timeout) - 写单个线圈
函数功能:向从机某个线圈中写入数据
注意事项:需确保此Modbus处于init状态
参数说明:
参数 | 类型 | 必选参数? | 说明 |
---|
slave_addr | int | 是 | 请求的从机地址,0代表广播 | coil_addr | int | 是 | 写线圈的地址 | coil_value | int | 是 | 写线圈的数据 | timeout | int | 是 | 请求超时时间,单位是毫秒(ms) |
返回值:返回一个tuple类型的4元组,元组中的条目格式为:
status | 请求状态,0表示成功,其他表示失败,具体含义参考 STATUS |
---|
resp_addr | 响应地址 | resp_value | 响应数据 | exception_code | 响应异常代码 |
modbus.writeMultipleCoils(slave_addr, start_addr, reg_quantity, data, timeout) - 写多个线圈
函数功能:向从机多个线圈中写入数据
注意事项:需确保此Modbus处于init状态
参数说明:
参数 | 类型 | 必选参数? | 说明 |
---|
slave_addr | int | 是 | 请求的从机地址,0代表广播 | start_addr | int | 是 | 写线圈的地址 | reg_quantity | int | 是 | 待写寄存器的数量,表示操作多少个寄存器 | data | bytearray | 是 | 写寄存器的数据,每个寄存器包含高低两个字节,高位在前,低位在后 | timeout | int | 是 | 请求超时时间,单位是毫秒(ms) |
返回值:返回一个tuple类型的4元组,元组中的条目格式为:
status | 请求状态,0表示成功,其他表示失败,具体含义参考 STATUS |
---|
resp_addr | 响应地址 | resp_quantity | 真实完成寄存器操作的数量 | exception_code | 响应异常代码 |
modbus.readHoldingRegisters(slave_addr, start_addr, reg_quantity, data, timeout) - 读多个保持寄存器值
函数功能:向从机读取多个保持寄存器的值
注意事项:需确保此Modbus处于init状态
参数说明:
参数 | 类型 | 必选参数? | 说明 |
---|
slave_addr | int | 是 | 请求的从机地址,0代表广播 | start_addr | int | 是 | 待读寄存器的起始地址 | reg_quantity | int | 是 | 待读寄存器的数量,表示操作多少个寄存器 | data | bytearray | 是 | 读寄存器获得的数据,每个寄存器包含高低两个字节,高位在前,低位在后 | timeout | int | 是 | 请求超时时间,单位是毫秒(ms) |
返回值:返回一个tuple类型的2元组,元组中的条目格式为:
status | 请求状态,0表示成功,其他表示失败,具体含义参考 STATUS |
---|
respond_count | 读取到数据的字节数 |
modbus.readInputRegisters(slave_addr, start_addr, reg_quantity, data, timeout) - 读取多个输入寄存器值
函数功能:向从机读取多个输入寄存器的值
注意事项:需确保此Modbus处于init状态
参数说明:
参数 | 类型 | 必选参数? | 说明 |
---|
slave_addr | int | 是 | 请求的从机地址,0代表广播 | start_addr | int | 是 | 待读寄存器的起始地址 | reg_quantity | int | 是 | 待读寄存器的数量,表示操作多少个寄存器 | data | bytearray | 是 | 读寄存器获得的数据,每个寄存器包含高低两个字节,高位在前,低位在后 | timeout | int | 是 | 请求超时时间,单位是毫秒(ms) |
返回值:返回一个tuple类型的2元组,元组中的条目格式为:
status | 请求状态,0表示成功,其他表示失败,具体含义参考 STATUS |
---|
respond_count | 读取到数据的字节数 |
modbus.readInputRegisters(slave_addr, start_addr, reg_quantity, data, timeout) - 读取多个离散输入值
函数功能:向从机读取多个输入寄存器的值
注意事项:需确保此Modbus处于init状态
参数说明:
参数 | 类型 | 必选参数? | 说明 |
---|
slave_addr | int | 是 | 请求的从机地址,0代表广播 | start_addr | int | 是 | 待读寄存器的起始地址 | reg_quantity | int | 是 | 待读寄存器的数量,表示操作多少个寄存器 | data | bytearray | 是 | 读寄存器获得的数据,每个寄存器包含高低两个字节,高位在前,低位在后 | timeout | int | 是 | 请求超时时间,单位是毫秒(ms) |
返回值:返回一个tuple类型的2元组,元组中的条目格式为:
status | 请求状态,0表示成功,其他表示失败,具体含义参考 STATUS |
---|
respond_count | 读取到数据的字节数 |
modbus.readCoils(slave_addr, start_addr, reg_quantity, data, timeout) - 读取多个线圈值
函数功能:向从机读取多个线圈的值
注意事项:需确保此Modbus处于init状态
参数说明:
参数 | 类型 | 必选参数? | 说明 |
---|
slave_addr | int | 是 | 请求的从机地址,0代表广播 | start_addr | int | 是 | 待读寄存器的起始地址 | reg_quantity | int | 是 | 待读寄存器的数量,表示操作多少个寄存器 | data | bytearray | 是 | 读寄存器获得的数据,每个寄存器包含高低两个字节,高位在前,低位在后 | timeout | int | 是 | 请求超时时间,单位是毫秒(ms) |
返回值:返回一个tuple类型的2元组,元组中的条目格式为:
status | 请求状态,0表示成功,其他表示失败,具体含义参考 STATUS |
---|
respond_count | 读取到数据的字节数 |
modbus.recv() - 从机读取主机数据
函数功能:该函数仅供从机使用,用来接收主机发送的请求命令。
接收的超时参数由 modbus.init 初始化时指定的 timeout 决定,默认为200毫秒。
注意事项:需确保此Modbus处于init状态
参数说明:
参数 | 类型 | 必选参数? | 说明 |
---|
slave_addr | int | 是 | 从机地址 | data | bytearray | 是 | 响应数据,格式为: 响应代码 + 响应数据 | timeout | int | 是 | 请求超时时间,单位是毫秒(ms) |
返回值:返回一个tuple类型的2元组,元组中的条目格式为:
status | 请求状态,0表示成功,其他表示失败,具体含义参考 STATUS |
---|
length | 发送的响应帧的长度,包含CRC校验长度 |
send - 从机发行响应数据到主机
函数功能:该函数仅供从机使用,用于发送响应数据给主机。
接收的超时参数由 modbus.init 初始化时指定的 timeout 决定,默认为200毫秒。
注意事项:需确保此Modbus处于init状态
函数原型:modbus.send()
参数说明: 空
返回值:返回一个tuple类型的2元组,元组中的条目格式为:
status | 请求状态,0表示成功,其他表示失败,具体含义参考 STATUS |
---|
bytes | 接收到的数据,包含CRC校验数据 |
|