树莓派4B与气体质量流量计通过RS485(modbus RTU协议)通信

目标:使用树莓派4B与CAN_HAT扩展板读取气体质量流量计的各项数据。

实验材料:树莓派4B,CAN_HAT扩展板,USB485转换器,MEMS气体质量流量计

 树莓派相关库与例程在上次实验已经安装过了,步骤可参照官网:

RS485 CAN HAT - Waveshare Wiki

一、PC端串口测试

先用PC端测试一下通讯,产品说明书如下:

 需要的数据有当前流量和当前总流量,复习一下之前学过的modbus协议,命令结构如下:

帧结构 = 地址 + 功能码 + 数据 + 校验

这个流量计的默认地址为255,也就是地址码为“FF”;查询功能码为“03”;以查询当前流量为例,存储当前流量值的寄存器地址为0x0002~0x0003,所以起始地址码为“00 02”;该值占用两个寄存器,所以偏移量为“00 02”;CRC算法得出其校验位数值,为“70 15”。

最终得出查询当前流量值命令为:

FF 03 00 02 00 02 70 15

 PC端发送该命令:

 返码中的数据位为“00 00 00 00”,表示当前流量值为0,获得的值除以1000后单位为SPLM,表示常温常压状态下的标准公升每分钟(L/min)。

同理得到查询累计流量值命令:

FF 03 00 04 00 03 51 D4

 PC端发送命令:

 返码中数据位占6个字节,因为总流量数据由3个寄存器存储,数据位为“00 00 00 00 00 04”,总流量值为4,获得的值除以1000后单位为NCM,也就是立方米,所以该值表示的是0.004立方米。

二、树莓派与流量计通信

由于之前实验中控制RS485收发的python文件封装性比较差,所以我自己修改了一下,现在有以下几个文件:

Open_serial.py:

# -*- coding:utf-8 -*-
import RPi.GPIO as GPIO
import serial
import time
class open_serial:
    def __init__(self,EN_485=4,name="/dev/ttyAMA0",baud=9600):
        self.__EN_485=EN_485
        self.__name=name
        self.__baud=baud
        GPIO.setwarnings(False)
        GPIO.setmode(GPIO.BCM)
        GPIO.setup(self.__EN_485,GPIO.OUT)
        GPIO.output(self.__EN_485,GPIO.HIGH)
        self.ser = serial.Serial(self.__name,self.__baud,timeout=1)
    def get_serial(self):
        print("Serial Number:",self.__EN_485,",Serial Name:",self.__name,",Baud Rate:",self.__baud,"\n")
        

这个文件控制串口的开启,串口号、串口名以及波特率、超时等在这里可以修改。

Receive_data.py:

# -*- coding:utf-8 -*-
import sys
sys.path.append(r'/home/pi/RS485_CAN_HAT_Code/RS485/python')
from Open_serial import open_serial

class receive_data:
    def __init__(self,EN_485=4,name="/dev/ttyAMA0",baud=9600):
        self.__os=open_serial(EN_485,name,baud)
        self.__ser=self.__os.ser
    def get_data(self):
        #while 1:  
            Str = self.__ser.readall()
            if Str:
                self.res=Str.hex()
                #print(self.res)
                if len(self.res) == 14:
                    self.__data=self.res[6:10]
                elif len(self.res) == 18:
                    self.__data=self.res[6:14]
                elif len(self.res) == 22:
                    self.__data=self.res[6:18]
                else:
                    print("Error!")
                self.__data=int(self.__data,16)
                print("Received Data is:",self.__data)
                return self.__data
                
        

这里用相应的串口接收数据并截取数据位,只要是RS485通讯都可以通过这个方法截取出数据位,然后转化为十进制,返回这个十进制的结果。

Send_command.py:

# -*- coding:utf-8 -*-
import sys
sys.path.append(r'/home/pi/RS485_CAN_HAT_Code/RS485/python')
from Open_serial import open_serial

class send_command:
    def __init__(self,EN_485=4,name="/dev/ttyAMA0",baud=9600):
        self.__os=open_serial(EN_485,name,baud)
        self.__ser=self.__os.ser
        #self.__os.get_serial()
    def send(self,strInput):
        self.__strInput=strInput
        str=bytes.fromhex(self.__strInput)
        self.__ser.write(str)
        print("Send Successfully!")

#s=send_command()
#s.send("01 03 00 4B 00 02 B4 1D")

使用相应串口发送指定的命令。

Run.py:

# -*- coding:utf-8 -*-
import sys
import time
sys.path.append(r'/home/pi/RS485_CAN_HAT_Code/RS485/python')
from Send_command import send_command
from Receive_data import receive_data

class run:
    r=receive_data()
    #result=t0.get_result()
    #print(result)
    s1=send_command()
    s1.send("FF 03 00 02 00 02 70 15")
    result1=r.get_data()
    time.sleep(5)
    s1.send("FF 03 00 04 00 03 51 D4")
    result2=r.get_data()
    print("result1:",float(result1)/1000,"\nresult2:",float(result2)/1000)

入口函数,相当于C++的main函数,模拟用户的操作,这里先是实例化receive_data对象和send_command对象,然后调用send发送查询命令,调用get_data获取接受到的数据,然后进行单位换算之后输出。

改完之后有点面向对象的样子了,但是封装性还是不够好,比如单位换算这样的操作应该由一个专门的类来完成,但我还没想好怎么写~所以这算是初代版本吧~

运行结果:

 与仪表显示无差别:

猜你喜欢

转载自blog.csdn.net/qq_43824745/article/details/126391725