MThings、网络调试助手、Python与RS485温湿度传感器进行ModbusRTU通信(卓岚RS485单串口服务器)

一、目标

使用电脑上的MThings(摩尔信使:Modbus通信助手)、网络调试助手(NetAssist)、Python代码分别实现对连接在卓岚串口服务器上的RS485温湿度传感器的温湿度读取。

二、准备工作

2.1 硬件

1.导线;

2.网线;

3.电脑;

4.开关电源(220V交流 转 24V直流);

5.卓岚RS485单串口服务器(ZLAN5143D);

f39965f98ce24ea0ab203b61c5dbda04.png

6.温湿度传感器(5V-36V);

5523e7c545aa47219c377380d0ba6662.png

输入寄存器功能定义
协议地址PLC地址功能描述
0000H30001温度值
单位:℃
解析方法:固定1位小数点
(1)正温度:寄存器数据<10000
例:寄存器值为250,实际湿度值: 250x0.1=25℃
(2)负温度:寄存器数据>=10000
例:寄存器值为10250
实际湿度值: -1*(10250 -10000) *0.1=-25℃
0001H30002湿度值.
单位:%RH
解析方法:固定1位小数点
例:寄存器值为500,实际湿度值: 500*0.1=50 (%RH)
0002H30003温度值
单位:℃
解析方法:32 位浮点数,大端模式
0003H30004
0004H30005湿度值
单位:%RH
解析方法:32 位浮点数,大端模式
0005H30006
保持寄存器功能定义
协议地址PLC地址功能描述
0000H30001温度值
单位:℃
解析方法:固定1位小数点
(1)正温度:寄存器数据<10000
例:寄存器值为250,实际湿度值: 250x0.1=25℃
(2)负温度:寄存器数据>=10000
例:寄存器值为10250
实际湿度值: -1*(10250 -10000) *0.1=-25℃
0001H30002湿度值.
单位:%RH
解析方法:固定1位小数点
例:寄存器值为500,实际湿度值: 500*0.1=50 (%RH)
0002H30003温度值
单位:℃
解析方法:32 位浮点数,大端模式
0003H30004
0004H30005湿度值
单位:%RH
解析方法:32 位浮点数,大端模式
0005H30006
000AH40011RS485总线地址/站号(1 ~255)。
出厂默认:1
注:此参数掉电保存,修改后重新上电即可生效
000BH400120:4800
1:9600 (出厂默认)
2:14400
3:19200
4:38400
5:56000
6:57600
7:115200
注:此参数掉电保存,修改后重新.上电即可生效

2.2 软件

1.ZLVirCom563(卓岚RS485单串口服务器设备管理工具);

2.MThings(摩尔信使:Modbus通信助手);

3.NetAssist(网络调试助手)

4.配置好Python的VScode,并且安装好第三方库:socket、struct、crcmod

三、接线图

74bb8ea743924f259c364a9f2f28a05c.png

四、通信参数配置

4.1 电脑通信参数配置

1.确保网线将电脑和卓岚单串口服务器接好(串口服务器上指示灯Link为绿色或者蓝色)

2.打开“网络和Internet”设置——高级网络设置——更改适配器选项——找到“以太网”图标,右键属性;

162367fb397046d0aebb2f7cd2f1143c.png

3.选择“Internet 协议版本4(TCP/IPv4)”;

82c7504c3c004798821d7d8b6f3122b1.png

4.点选“使用下面的IP地址”——输入IP地址和子网掩码(注意:IP地址必须和串口服务器的地址在同一个网段下。即192.168.1是一样的,后面的字段不一样)——点击“确定”——完成电脑的以太网IP设置;

5cb5025e74e841539a88f11f15a9e960.png

4.2 卓岚RS485单串口服务器通信参数配置

1.电脑打开“ZLVirCom5.63.exe”软件;

adcc9ff5883249eea43e3e5e3673d3d9.png

2.点击“设备管理”——“自动搜索”——搜索得到串口服务器设备;

e677307a0e7944d9aba89cef12f18e63.png

 3.点击“编辑设备”——修改IP地址(这里设置192.168.1.10,端口4196,需要与电脑配置的IP在同一个网段下,否则通信不上)——修改波特率为9600(温湿度传感器的默认波特率就是9600)——其他默认即可——点击“修改设置”;

f6965c86a0154fc6b5439824a5dd4f0f.png

 五、MThings操作

5.1 通信配置

1.打开MThings调试软件——点击右上角的通道管理;

bd29a0142a1f4c4ba5b00b409151945d.png

2. 进入通道界面管理的小窗口后,点击新增网络连接;

483126e350f44ce9bcc5785be5401326.png

3.链接模式选择“TCP客户端”;传输协议选择“MODBUS-RTU”(表面上使用TCP通信,但其通信的报文是是MODBUS-RTU的);目标域名/IP和目标端口填写“IP192.168.1.10 端口4196”(四、通信参数配置——4.2卓岚RS485单串口服务器通信参数配置——3);填写完基本信息后点击确定;检查链接是否添加成功;

4a6fc0cfe3594449ad96748d2d027701.png

91451e4b913f4dedb7d14be03181bbc4.png

4.回到MThings主界面——点击左上角“+”符号——进入“添加设备”小窗口——通道选择我们上一步创建的网络链接“NET001”——设备类型“模拟主机”(因为卓岚模块是属于从机)——点击“添加”;

5ffd26625f1a49e1a9bdfa6a6893fa93.png

26a17c598a9f47f5a8bd76140de28904.png

5.上一步添加成功之后,再进入到“通道管理”里面可发现“NET001”的状态已变成了绿色的“已连接”,就表示MThings调试软件已经与卓岚串口服务器连接上了,接下来就创建数据表,并进行通信了;

78424bfab73448acb2f73b37bb19d962.png

6.回到MTings主界面,然后点击界面上方的“数据”——进入到“数据”选项卡后——点击上方的“+”符号添加数据行;

6a95fc6609574891a309c875ab159b32.png

d6edb8d811a24a3c90c7f8017af57bba.png

7.温湿度值都存储于输入寄存器(保持寄存器)中,地址0存储温度值,地址1存储湿度值,我们可以先创建这4个数据行,2个输入寄存器的温度和湿度行,2个保持寄存器的温度和湿度行;

我们还可以添加两个输入寄存器起始地址为0的数据行、两个保持寄存器起始地址为0的数据行,然后寄存器数量我们可以设置为2,意思是温湿度两个值一起读过来变成32位整数,自己可以选择性试一试。

温湿度传感器的出厂设置的寄存器在保持寄存器,起始地址10。

温湿度传感器的波特率设置的寄存器在保持寄存器,起始地址11。

9e35df7b03ca49d288669c2f5566039b.png

dfaa41d52c154348b0c8b181cef122e5.png

5.2 读取温湿度值(ModbusRTU读数据)

5.1步骤完成之后,我们就可以使用MThinngs书写数据,并观察其报文格式(后面可以使用网络调试助手来验证),首先将右上方的“报文”勾选上。

5.2.1 读取温度值(读输入寄存器,起始地址0,数量1)

e1453de6ff294fa19fe47b0817d5fb8f.png

客户端(电脑)发送:01 04 00 00 00 01 31 CA

01从站地址1,一般默认都是1,1个字节
04功能码,读输入寄存器的功能码是04,1个字节
00 00起始地址0,2个字节
00 01读取的寄存器数量1个,2个字节
31 CACRC校验码,2个字节

服务器(温湿度传感器)响应:01 04 02 01 1C B9 69

01从站地址1,一般默认都是1,1个字节
04功能码,读输入寄存器的功能码是04,1个字节
02数据长度:2个字节
01 1C16进制温度值,转换成10进制是284,2个字节
B9 69CRC校验码,2个字节

 5.2.2 读取湿度值(读输入寄存器,起始地址1,数量1)

f809a8257c944f339bfb6f52c6bd0c88.png

客户端(电脑)发送:01 04 00 01 00 01 60 0A

01从站地址1,一般默认都是1,1个字节
04功能码,读输入寄存器的功能码是04,1个字节
00 01起始地址1,2个字节
00 01读取的寄存器数量1个,2个字节
60 0ACRC校验码,2个字节

服务器(温湿度传感器)响应:01 04 02 02 C3 F8 01

01从站地址1,一般默认都是1,1个字节
04功能码,读输入寄存器的功能码是04,1个字节
02数据长度:2个字节
02 C316进制湿度值,转换成10进制是707,2个字节
F8 01CRC校验码,2个字节

 5.2.3 读取温湿度值(读输入寄存器,起始地址0,数量2)

04c50f6a7a7d4ba58100440b7a191ff6.png

客户端(电脑)发送:01 04 00 00 00 02 71 CB

01从站地址1,一般默认都是1,1个字节
04功能码,读输入寄存器的功能码是04,1个字节
00 00起始地址0,2个字节
00 02读取的寄存器数量2个,2个字节
71 CBCRC校验码,2个字节

服务器(温湿度传感器)响应:01 04 04 01 1C 02 C3 7A 8F

01从站地址1,一般默认都是1,1个字节
04功能码,读输入寄存器的功能码是04,1个字节
04数据长度:4个字节
01 1C16进制温度值,转换成10进制是284,2个字节(地址为0的输入寄存器值)
02 C316进制湿度值,转换成10进制是707,2个字节(地址为1的输入寄存器值)
7A 8FCRC校验码,2个字节

 5.2.4 读取温度值(读保持寄存器,起始地址0,数量1)

485e015e08be4e76bf181af71ae99f6a.png

客户端(电脑)发送:01 03 00 00 00 01 84 0A

01从站地址1,一般默认都是1,1个字节
03功能码,读保持寄存器的功能码是03,1个字节
00 00起始地址0,2个字节
00 01读取的寄存器数量1个,2个字节
84 0ACRC校验码,2个字节

服务器(温湿度传感器)响应:01 03 02 01 1C B8 1D

01从站地址1,一般默认都是1,1个字节
03功能码,读输入寄存器的功能码是03,1个字节
02数据长度:2个字节
01 1C16进制温度值,转换成10进制是284,2个字节
B8 1DCRC校验码,2个字节

  5.2.5 读取湿度值(读保持寄存器,起始地址1,数量1)

005ec7d86f124b51bcb54028d4da2dc4.png

客户端(电脑)发送:01 03 00 01 00 01 D5 CA

01从站地址1,一般默认都是1,1个字节
03功能码,读保持寄存器的功能码是03,1个字节
00 01起始地址1,2个字节
00 01读取的寄存器数量1个,2个字节
D5 CACRC校验码,2个字节

服务器(温湿度传感器)响应:01 03 02 02 C3 F9 75

01从站地址1,一般默认都是1,1个字节
03功能码,读保持寄存器的功能码是03,1个字节
02数据长度:2个字节
02 C316进制湿度值,转换成10进制是707,2个字节
F9 75CRC校验码,2个字节

  5.2.6 读取温湿度值(读保持寄存器,起始地址0,数量2)

3647f84809444531b7707bc72e9c60f4.png

客户端(电脑)发送:01 03 00 00 00 02 C4 0B

01从站地址1,一般默认都是1,1个字节
03功能码,读保持寄存器的功能码是03,1个字节
00 00起始地址0,2个字节
00 02读取的寄存器数量2个,2个字节
C4 0BCRC校验码,2个字节

服务器(温湿度传感器)响应:01 03 04 01 1C 02 C3 7B 38

01从站地址1,一般默认都是1,1个字节
03功能码,读保持寄存器的功能码是03,1个字节
04数据长度:4个字节
01 1C16进制温度值,转换成10进制是284,2个字节(地址为0的保持寄存器值)
02 C316进制湿度值,转换成10进制是707,2个字节(地址为1的保持寄存器值)
7B 38CRC校验码,2个字节

5.3 设置温湿度传感器出厂设置与波特率(ModbusRTU写数据)

5.3.1 恢复出厂设置

8079e13830ae40e6972c92891a1511f3.png

客户端(电脑)发送:01 06 00 0A 00 01 68 08

01从站地址1,一般默认都是1,1个字节
06功能码,写保持寄存器的功能码是06,1个字节
00 0A起始地址10,2个字节(十六进制A就是十进制10)
00 01写入保持寄存器的数值1,2个字节
68 08CRC校验码,2个字节

服务器(温湿度传感器)响应:01 06 00 0A 00 01 68 08

01从站地址1,一般默认都是1,1个字节
06功能码,写保持寄存器的功能码是06,1个字节
00 0A起始地址10,2个字节
00 01写入保持寄存器成功的数值1,2个字节
68 08CRC校验码,2个字节

5.3.2 设置波特率

ae71f1feb12042109086479de57f74b7.png

客户端(电脑)发送:01 06 00 0B 00 01 39 C8

01从站地址1,一般默认都是1,1个字节
06功能码,写保持寄存器的功能码是06,1个字节
00 0B起始地址11,2个字节(十六进制B就是十进制11)
00 01写入保持寄存器的数值1,2个字节
39 C8CRC校验码,2个字节

服务器(温湿度传感器)响应:01 06 00 0B 00 01 39 C8

01从站地址1,一般默认都是1,1个字节
06功能码,写保持寄存器的功能码是06,1个字节
00 0B起始地址11,2个字节(十六进制B就是十进制11)
00 01写入保持寄存器成功的数值1,2个字节
39 C8CRC校验码,2个字节

 六、网络调试助手操作

通过以上MThings操作温湿度传感器的步骤可以发现,每读写一次数据,我们的客户端电脑就会向温湿度传感器发送一串十六进制数据,温湿度传感器作为响应也会发送一串十六进制数据给电脑。使用MThings软件我们只要关心我们需要读写的寄存器地址、数量以及我们要写入的数值,而报文怎么编写不是我们需要关心的。

但如果我们打算使用网络TCP的形式去进行通信的话,那么我们需要就需要知道ModbusRTU的报文是如何编写的,并且知道报文如何解析。

1.打开网络调试助手(NetAssist.exe),按下列步骤完成操作。

4e9a5256a2c74bfc95b75e9c830046ca.png

客户端(电脑)发送:01 04 00 00 00 01 31 CA

01从站地址1,一般默认都是1,1个字节
04功能码,读输入寄存器的功能码是04,1个字节
00 00起始地址0,2个字节
00 01读取的寄存器数量1个,2个字节
31 CACRC校验码,2个字节

服务器(温湿度传感器)响应:01 04 02 01 1C B9 69

01从站地址1,一般默认都是1,1个字节
04功能码,读输入寄存器的功能码是04,1个字节
02数据长度:2个字节
01 1C16进制温度值,转换成10进制是284,2个字节
B9 69CRC校验码,2个字节

2.这里只展示了读取温湿度传感器的温度值(输入寄存器地址0,读取数量1个),如果想要读取湿度值,或者想要将某个值写入指定的保持寄存器中,我们可以根据上面的ModbusRTU报文格式,自己定一条写保持寄存器的报文,并发送给ModbusRTU设备即可,并学会解析ModbusRTU报文格式,知道数据值存放在什么地方,并转换为我们能看懂的10进制。

七、Python操作

如果我们想要用这个温湿度传感器做更多的事情,最简单的比如说,我想每隔一段时间采集一次温湿度值,并记录在excel表中。

那么以上两款调试助手均不能做到,可以使用任意一种编程语言来实现。这里使用的是Python编程语言,虽然Python可以安装第三方库pymodbus实现modbus通信,但是这个库使用ModbusTCP通信时,其通信协议只能是ModbusTCP,而不能选择ModbusRTU协议。

所以使用Python时,我们需要使用的第三方库是socket,然后在TCP网络通信的基础上以ModbusRTU为通信报文,也就是需要自己写程序解析读取报文,还有生成报文,其中包含了CRC校验码的生成。

7.1 第三方库的安装

如果没有安装第三方库的话,请按照以下方式进行安装,我这里使用pip指令进行安装,win+R键打开运行窗口,输入cmd,回车打开命令行窗口,第三方库可以在里面安装,以下安装指令都在cmd窗口中执行:

1.使用pip指令安装socket库,用于网络通信:

pip install socket

2.使用pip指令安装struct库,用于解析十六进制报文,并生成报文:

pip install struct

 3.使用pip指令安装crcmod库,用于生成CRC校验码:

pip install crcmod

 7.2 编写Modbus通信代码

以下是实例代码:

import socket,struct,crcmod


'''
struct打包解包格式:
x:跳过一个字节
b:有符号字节
B:无符号字节
h:有符号短整数(2字节)
H:无符号短整数(2字节)
i:有符号整数(4字节)
I:无符号整数(4字节)
f:单精度浮点数(4字节)
d:双精度浮点数(8字节)
'''

#CRC-MODBUS校验码计算
def crc16(data):   #参数data是十六进制数据
    crc16 = crcmod.mkCrcFun(0x18005, rev=True, initCrc=0xFFFF, xorOut=0x0000) #固定参数
    crc = crc16(data) 
    return struct.pack('H',crc) #得到的校验码(转换成无符号短整形2个字节的十六进制数)


#关于TCP通信,走ModbusRTU协议的类
class ModbusTcpRtuClinet():
    #初始化函数
    def __init__(self,IP,port):
        dest_address = (IP, port)                                               #TCP通信所需要的远程IP与端口
        # 创建一个TCP socket对象,创建UDP套接字
        #socket.AF_INET     IPv4
        #socket.AF_INET6    IPv6
        #socket.SOCK_STREAM TCP协议
        #socket.SOCK_DGRAM  UDP协议
        self.client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)  #选择IPv4模式、TCP通信协议
        self.client_socket.connect(dest_address)                                #连接到TCP客户端
    #读多个输入寄存器
    #address:读取输入寄存器的起始地址
    #count:读取输入寄存器的个数
    #unit:从站地址(默认为1)
    def read_input_registers(self,address,count,unit=1):
        #向从站发出读数据请求
        send_data_byte = struct.pack('>B',unit) + struct.pack('>B',3) + struct.pack('>H',address) + struct.pack('>H',count)
        send_data_byte += crc16(send_data_byte)                                  #将读输入寄存器输入的报文加上CRC校验码
        self.client_socket.send(send_data_byte)                                  #发送这一串16进制的读输入寄存器报文
        #接收从站数据
        receive_data_byte = self.client_socket.recv(1024)                        #接收数据,一次读取1024个字节         #接收RTU从站响应的报文(高字节在后,低字节在前)
        data_len = struct.unpack('>xxB%sxx'%(count*"xx"),receive_data_byte)[0]   #解析读取的寄存器数据总长度(单位:字节)
        unpack_format = '>BBB%sH'%(int(data_len/2)*'h')                          #2个字节一个h,短整型
        return list(struct.unpack(unpack_format,receive_data_byte)[3:-1])        #解析数据最终将我们要的寄存器数据提取出来
    #读多个保持寄存器
    #address:读取输入寄存器的起始地址
    #count:读取输入寄存器的个数
    #unit:从站地址(默认为1)
    def read_holding_registers(self,address,count,unit=1):
        #向从站发出读数据请求
        send_data_byte = struct.pack('>B',unit) + struct.pack('>B',3) + struct.pack('>H',address) + struct.pack('>H',count)
        send_data_byte += crc16(send_data_byte)                                  #将读保持寄存器输入的报文加上CRC校验码
        self.client_socket.send(send_data_byte)                                  #发送这一串16进制的读保持寄存器报文
        #接收从站数据
        receive_data_byte = self.client_socket.recv(1024)                        #接收数据,一次读取1024个字节                #接收RTU从站响应的报文(高字节在后,低字节在前)
        data_len = struct.unpack('>xxB%sxx'%(count*"xx"),receive_data_byte)[0]   #解析读取的寄存器数据总长度(单位:字节)
        unpack_format = '>BBB%sH'%(int(data_len/2)*'h')                          #2个字节一个h,短整型
        return list(struct.unpack(unpack_format,receive_data_byte)[3:-1])        #解析数据最终将我们要的寄存器数据提取出来
    #写单个保持寄存器
    def write_holding_register(self,address,value,unit=1):
        #向从站发出读数据请求
        send_data_byte = struct.pack('>B',unit) + struct.pack('>B',6) + struct.pack('>H',address) + struct.pack('>h',value)
        send_data_byte += crc16(send_data_byte)                            #将读保持寄存器输入的报文加上CRC校验码
        self.client_socket.send(send_data_byte)                            #发送这一串16进制的读保持寄存器报文
        #接收从站数据
        receive_data_byte = self.client_socket.recv(1024)                  #接收数据,一次读取1024个字节                #接收RTU从站响应的报文(高字节在后,低字节在前)
        if receive_data_byte == send_data_byte:                            #如果接受到的数据跟发送出去的报文数据一样,则说明保持寄存器写入成功
            return True                                                    #保持寄存器写入成功返回True
        else:
            return False                                                   #保持寄存器写入失败返回False
    #关闭客户端
    def close(self):
        self.client_socket.close()  #关闭客户端



#开始通信读写数据
client = ModbusTcpRtuClinet("192.168.1.10", 4196)                                                  #连接到设备,填写IP和端口
print("温度(输入寄存器,地址0,数量1):",client.read_input_registers(0,1))                          #读输入寄存器地址0,数量1
print("湿度(输入寄存器,地址1,数量1):",client.read_input_registers(1,1))                          #读输入寄存器地址1,数量1
print("温湿度(输入寄存器,地址0,数量2):",client.read_input_registers(0,2))                        #读输入寄存器地址0,数量2
print("温度(保持寄存器,地址0,数量1):",client.read_holding_registers(0,1))                        #读保持寄存器地址0,数量1
print("湿度(保持寄存器,地址1,数量1):",client.read_holding_registers(1,1))                        #读保持寄存器地址1,数量1
print("温湿度(保持寄存器,地址0,数量2):",client.read_holding_registers(0,2))                      #读保持寄存器地址0,数量2
print("恢复出厂设置(保持寄存器,地址10,写入数值1):",client.write_holding_register(10,1))             #写保持寄存器地址10,值为1,恢复出厂设置
print("波特率是否设置成功(保持寄存器,地址11,写入数值1):",client.write_holding_register(11,1))      #写保持寄存器地址11,值为1,修改温湿度传感器波特率,修改成功返回True,失败返回False
client.close()                                                                                     #关闭客户端

 运行结果:

e986f8876ed744f68045a998e3fc9310.jpeg

 从终端运行的结果可以看见,已经成功读取和写入寄存器值,读取到的寄存器值存储在python列表中,也就是存储在中括号中。目前获取到的温湿度值还需要除以10,得到的才是真正的温湿度值。写入寄存器成功返回True,写入失败返回False。

 八、结论

本篇文章主要讲述了通过MThings、网络调试助手、编写Python脚本来实现TCP上的ModbusRTU协议通信,比较特殊的地方是使用了以太网转RS485模块。除了这些还有各种各样的方式可以实现,其核心只要在于ModbusRTU通信的报文发送和接收。如果没有使用串口服务器的话,可以使用Mthings、串口调试助手、Python中的pymodbus第三方库来实现。以此简单的温湿度传感器为例,希望能为大家提供有价值的参考和帮助。如有问题可进行评论或者私信我,看到后我会第一时间回复大家。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值