树莓派4B、Python与三相四线多功能电力仪表通过RS485(modbus RTU协议)收发数据

树莓派4B+Python与三相四线多功能电力仪表通过RS485(modbus RTU协议)接口发送和接收数据

请耐心把下面的警告⚠️看完
开始之前需要注意以下点:一、那就是安全,生命为本,安全第一。因为需要接触220V民用电或380V工业/商业用电,操作不当会有触电的危险,为避免可能发生的人身触电伤亡事故。二、需要在监护人的监护下进行操作,电缆线接入220V或380V电源前需先停上一级电源并做好个人防护措施(穿绝缘靴、戴绝缘手套)。三、需要一些电工的基础知识,能看懂三相多功能电力仪表的接线方法。四、如果没有做任何防护和没有电工基础知识,请勿进行以下操作。如果执意要在没有任何保护措施和没有监护人员监督的情况下操作,发生触电伤亡事故的,本人概不负责!!!


利用树莓派4B+作为主站(Master)读取从站(Slave)三相多功能电力仪表中的实时电压值

首先来看一下结果:


A相电压: 239.12 V
B相电压: 239.11 V
C相电压: 239.13 V
这里读取的是相电压的值,要读取线电压值的方法会在下面有简单的介绍

这里涉及到内容和方法不多呢也不少,先要了解一下Modbus RTU协议,根据这个协议来编写程序。关于这个协议不懂的可以问百度,满天下都是,这里就不在多说了。

准备材料:1、树莓派4B+ 2、RS485_CAN_HAT树莓派扩展板 3、三相多功能电力仪表(RS485 Modbus-RTU) 4、USB TO RS485 5、7寸IPS触摸屏HDMI 6、各式导线若干

树莓派4B+
树莓派4B+

RS485_CAN_HAT树莓派扩展板
RS485_CAN_HAT树莓派扩展板

三相多功能电力仪表(RS485 Modbus-RTU)
三相多功能电力仪表(RS485 Modbus-RTU
USB TO RS485
在这里插入图片描述

7寸IPS触摸屏 HDMI
在这里插入图片描述
使用各式导线把这些东西连接起来,需要注意的是RS485_CAN_HAT树莓派扩展板中的A和B接口的连接,一定要对应通讯设备的A和B,也就是A接A,B接B。
先用USB TO RS485与电脑连接做通讯测试,直接插在电脑的USB口上,等电脑识别。一般都会成功的!然后再将USB TO RS485与树莓派扩展板RS485_CAN_HAT上的A、B两个接口连接。
树莓派和电脑中使用的Python版本都是3.7.6的,可以使用更高的版本,试过·不支持
树莓派电脑中安装个Python库:modbus_tk库,打开命令行输入:

pip3 install modbus_tk

也用到其他的库:serial、struct、time,这些库系统自带,如果没有的可以用pip3命令重新装一遍,就可以了

RS485_CAN_HAT树莓派扩展板相关库的安装:按照顺序一步一步的来

参照官网
https://www.waveshare.net/wiki/RS485_CAN_HAT

电脑端串口测试使用的软件:(串口调试助手)
更改:串口和波特率选项,其他的默认就可以
更改:串口和波特率选项,其他的默认就可以,串口选择USB TO RS485(usbserial)各电脑不一样酌情选择正确的串口就可以,波特率选择9600要和树莓派、电表一致否则无法通讯,如果有效验位可以选择和电表对应的效验位(奇、偶、无),需要循环发送数据的勾选(启动循环发送),需要自动换行勾选(尾部自动带上)其他选项默认。

RS485通讯测试:
树莓派打开命令行,输入:

cd ../../RS485_CAN_HAT_Code/485/python/

先运行接收:

sudo python reveive.py
#可以不用关闭窗口

再运行发送:

sudo python send.py
#新建一个窗口

在发送的窗口中随便发送一些字符(发送不了中文),只要电脑端的串口调试助手软件中的接收窗口中能够看到刚刚从树莓派中输入的字符串,证明通讯成功了。也可以从串口调试助手软件的发送框中随便输入些字符串,点击发送。
如果发送和失败:按照RS485_CAN_HAT官网中的介绍最底部有解决的办法
https://www.waveshare.net/wiki/RS485_CAN_HAT

再下一步就是树莓派与三相多功能电力仪表的通讯:

三相多功能电力仪表的接线:参照说明书,说明书在这里是很有用的,不要随便遗弃。选择合适的电缆接线,一般可以选用废旧电气中的电缆线。先使用220V民用电测试(注意安全),UA,UB,UC指的是三相电压的输入信号UN接零线,L,N指的是电表的电源零线和火线,可以将UA,UB,UC端子并联起来就像下面?这样。就当是输入三相电了~~~

接线

通电后观察电表是否工作正常
电表通电后
一切都检查好,连接好后,就可以写程序了
写程序之前要先想好最终的目的是什么,这个很重要,我以使用电脑读取A、B、C三相电压值并打印输出为例

#引入库
import serial
import modbus_tk.modbus_rtu as rtu 
import modbus_tk.defines as cst  
import modbus_tk
#import RPi.GPIO as GPIO#树莓派引脚库
import struct
import time
#设置串口
port = "/dev/tty.usbserial-G0KB8NH"
# port = "/dev/ttyS0"#树莓派串口
ser = serial.Serial(port=port,
                    baudrate=9600,
                    bytesize=8,
                    parity="N",
                    stopbits=1)
                    
                    
#先判断串口是否处于打开状态
if ser.isOpen():
        print("串口开启")
#设置电脑端为主机(Master)
master = rtu.RtuMaster(ser)
master.set_timeout(1.0)
master.set_verbose(True)

设置好这些就可以读取电压值了

read_values = master.execute(1,cst.HOLDING_REGISTERS,0x39,6)
#这里需要解释一下:master.execute((1代表从机(slave)的地址),
#(cst.HOLDING_REGISTERS代表读取),
#(0x39这个是十六进制的数,转换成十进制是57也就是存储电压值的寄存器的起始地址),
#(6代表读取6个寄存器的值,为什么要读取6个寄存器,是因为每两个寄存器存储一个电压值)

先把得到的值打印输出一下,看看是不是我们想要的:

 print(read_values)

打印输出的值:
(17264, 20120, 17264, 20775, 17264, 19071)
这样的数据不是我们想要的,只知道是十进制的数据,没一组数据都用“,”分开,一共是6组数据,这个是我们想要的6个寄存器的数据,每两个寄存器储存一相电压值,这里的6组数据刚好是我们想要的3相电压值
继续在print()里添加内容,看看是什么样类型的数据

print(read_values,type(read_values)

打印输出的信息:
(17264, 23593, 17264, 24510, 17264, 22479)
<class ‘tuple’> 元组类型,知道是元组类型的数据就可以通过下标取值,下标索引是从0开始的而不是1
继续打印输出

print(read_values,type(read_values),read_values[0],read_values[1],read_values[2],read_values[3],read_values[4],read_values[5])

打印输出的信息:
(17263, 53477, 17263, 54264, 17263, 52101)
<class ‘tuple’>
17263 53477 17263 54264 17263 52101

由于电表的寄存器是以十六进制进行储存数据,而modbus_tk库里会自动帮我们转换成十进制的数据,这些十进制的数据都是以元组的形式读取出来的,那么就要合并转换成十六进制的,每两组进行合并然后转换

A_register_address_57_58 = str(hex(read_values[0]).replace("0x","")) + str(hex(read_values[1]).replace("0x",""))
B_register_address_59_60 = str(hex(read_values[2]).replace("0x","")) + str(hex(read_values[3]).replace("0x",""))
C_register_address_61_62 = str(hex(read_values[4]).replace("0x","")) + str(hex(read_values[5]).replace("0x",""))
#这里就很明白了,解释一下吧
#就是将下标索引第0位也是第一位的数值转换成十六进制后强制转换成字符串类型与后方第1位也是第二位转换后的字符串进行拼接,得到一个十六进制的值,这个值就是单相电压的值是以十六进制表示的
#以此类推A相,B相,C相的电压值就都拿到了,但还需要一次转换,毕竟十六进制的值也是看不懂的

再次打印输出:

print(A_register_address_57_58,B_register_address_59_60,C_register_address_61_62)

打印输出的信息:

4370476d 437049fc 4370420c

下一步就是将这三组十六进制再次转换成浮点类型,这里的浮点类型遵循的标准是IEEE754国际工业电气标准(具体详情:请见说明书)。那有的人就要问了,为什么不直接把得到的6组十进制的数拼接了以后转换成浮点类型呢,这不更省事么。我可能也是太笨了,目前没有找到方法,只能一步一步的解决问题。

A_float = struct.unpack('>f',bytes.fromhex(A_register_address_57_58))[0]
B_float = struct.unpack('>f',bytes.fromhex(B_register_address_59_60))[0]
C_float = struct.unpack('>f',bytes.fromhex(C_register_address_61_62))[0]

输出浮点类型的数据我们就能看懂了,但是输出的数据太过精确了,我只要小数点后两位就够了,再一次上程序

A_2f_float = '%.2f'%A_float
B_2f_float = '%.2f'%B_float
C_2f_float = '%.2f'%C_float

打印输出:print语句自己就随便写吧,也很简单
(17264, 30999, 17264, 31850, 17264, 29753)
<class ‘tuple’>
17264 30999 17264 31850 17264 29753

43707917 43707c6a 43707439

A相电压: 240.47 V
B相电压: 240.49 V
C相电压: 240.45 V

到这里就算是基本完成了最初的目的,需要读取380V的工业或商业用电的电压、电流、有功功率等数据的只需要按照电力仪表后方的接线图接线,更改程序中的master.execute(1,cst.HOLDING_REGISTERS,0x39(可更改),6(可更改))寄存器的起始地址和寄存器的个数就可以了。至于多长时间自动读取一次数据,需要导入time库,使用time.sleep()方法配合while循环进行读取。
树莓派读取数据时更改串口为/dev/ttyS0,还需要设置扩展板引脚,程序都是一样的

MODE =0 
 if MODE == 1:
     EN_485 = 4
     GPIO.setmode(GPIO.BCM)#设置树莓派引脚模式为BCM编码模式
     GPIO.setup(EN_485,GPIO.OUT)#设置引脚为输出模式
     GPIO.output(EN_485,GPIO.HIGH)#设置引脚为高电平输出
port = /dev/ttyS0

能力一般,水平有限。文章内容仅供参考
最后还是那句话,安全第一,不要因为一时兴起就去干一些危险的事情,危险是不可控的,还望自重。


版权声明:本文为weixin_45664315原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。