树莓派4B与智能插排通过RS485(modbus RTU协议)通信

这篇具有很好参考价值的文章主要介绍了树莓派4B与智能插排通过RS485(modbus RTU协议)通信。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目标:使用树莓派4B与CANHAT扩展板读取智能插排测量的各项数据(RS485+modbus RTU),获取的数据上传到Hyperledger Fabric框架。

之前学习过了modbus RTU协议,在智能涡轮流量计的实验中应用过一次,这次用这个带485模块的智能插座再复习一次~

实验材料:

树莓派4B/8G:

树莓派 modbus,树莓派,区块链,python,fabric,linux

 CANHAT扩展板:

树莓派 modbus,树莓派,区块链,python,fabric,linux

 USB-485转换器:

树莓派 modbus,树莓派,区块链,python,fabric,linux

 RS485机柜排插:

树莓派 modbus,树莓派,区块链,python,fabric,linux

 RJ45水晶头转8PIN端子:

树莓派 modbus,树莓派,区块链,python,fabric,linux

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

RS485 CAN HAT - Waveshare Wiki

一、PC端串口测试

还是先使用PC端的串口调试助手测试一下智能插座的通讯。先将设备正确接线:

树莓派 modbus,树莓派,区块链,python,fabric,linux

 这次的智能插排RS485模块接线口是水晶头而不是通常的AB端子,所以还需要一个水晶头转端子线,接线如上图的说明书所示。

调试前先看看设备的通信说明书:

树莓派 modbus,树莓派,区块链,python,fabric,linux

 可以看到一个寄存器同样也是表示2字节的数据,电量用两个寄存器表示也就是4个字节,其他数据应该都只占用一个寄存器。这次的说明书详细一些,还给出了数据转换公式。

具体各项数据存储的寄存器地址如下:

树莓派 modbus,树莓派,区块链,python,fabric,linux

 计算一下需要用到的modbus命令:

01 03 00 48 00 01 04 1C    查询电压值
01 03 00 49 00 01 55 DC    查询电流值
01 03 00 4A 00 01 A5 DC    查询有功功率
01 03 00 4B 00 02 B4 1D    查询有功总电能
01 03 00 4D 00 01 14 1D    查询功率因数
01 03 00 4E 00 02 A4 1C    查询二氧化碳排量

以查询有功总电能为例,串口调试助手发送命令后接收到如下数据:

树莓派 modbus,树莓派,区块链,python,fabric,linux

数据位为“00 00 01 23”,十进制数值为291,根据数据转换公式值=DATA/3200,算得有功总电能为0.09kWh,经验证数据无误:

树莓派 modbus,树莓派,区块链,python,fabric,linux

 二、树莓派与智能插排通信

python文件编写如下:

receive.py:

# -*- coding:utf-8 -*-
import RPi.GPIO as GPIO
import serial
 
EN_485 =  4
GPIO.setwarnings(False)
GPIO.setmode(GPIO.BCM)
GPIO.setup(EN_485,GPIO.OUT)
GPIO.output(EN_485,GPIO.LOW)
 
ser = serial.Serial("/dev/ttyAMA0",9600,timeout=1)  # open first serial port    
while 1:  
    Str = ser.readall()  
    if Str:  
        print (Str)
        string=Str.hex()
        print(string)
        #print(res)
        note=open('/home/pi/Desktop/hyperledger/multinodes-pi/data.txt',mode='w')
        note.write(string)
        note.close()
        #break
 

receive.py与上次实验有所区别,主要因为这次查询的数据较多,且每种数据储存方式不同,如电流电压等都储存在一个寄存器中,也就是说返回的数据位是2个字节,而电能与二氧化碳排量存储在两个寄存器中,所以返回的数据为4个字节,所以需要截取的数据位是不同的。除此以外相比于涡轮流量计查询到的数据,这次实验查询到的不同的值转换公式也不同,如有功功率就是返回的数据位转化成十进制后的值,单位为W;而有功总电能则是返回的数据转化为十进制后再除以3200,单位为kWh。所以我准备在receive接收返码时进行一次判断,因为当返回的数据位有2个字节时,返码总长度为7字节;返回数据位有4个字节时,返码总长度为9字节。所以通过接收到的数组长度就能确定需要截取的数据位的位置了,如果返码总长度为7字节,截取[6:10],总长度为9字节,则截取[6:14]。截取数据位之后将其转为十进制存入data.txt,操作data时我感觉用shell命令处理这么多浮点数的运算写起来比较麻烦,所以在shell脚本调用指定的send.py数据查询1s后,依据查询的数据类型在对应的send文件中将data.txt文件的数据进行换算再重新写入,最后data.txt中存的就是我需要的最终数据。

send.py

# -*- coding:utf-8 -*-
import RPi.GPIO as GPIO
import serial

EN_485 =  4
GPIO.setwarnings(False)
GPIO.setmode(GPIO.BCM)
GPIO.setup(EN_485,GPIO.OUT)
GPIO.output(EN_485,GPIO.HIGH)

t = serial.Serial("/dev/ttyAMA0",9600)    
print (t.portstr)    
strInput = '01 03 00 00 00 02 C4 0B'
str=bytes.fromhex(strInput)
print(str)
n = t.write(str)    
print (n)    

send文件通过修改strInput来发送不同的查询命令,将得到的结果存入data.txt并使用脚本读取。在send文件中还需要进行数据转换操作,不同数据转换公式不同,下面是电压voltage与总电能energy的查询文件:

voltage.py:

# -*- coding:utf-8 -*-
import RPi.GPIO as GPIO
import serial
import time

EN_485 =  4
GPIO.setwarnings(False)
GPIO.setmode(GPIO.BCM)
GPIO.setup(EN_485,GPIO.OUT)
GPIO.output(EN_485,GPIO.HIGH)

t = serial.Serial("/dev/ttyAMA0",9600)    
#print (t.portstr)    
strInput = '01 03 00 48 00 01 04 1C'
string=bytes.fromhex(strInput)
#print(string)
n = t.write(string)    
#print (n)
time.sleep(2)
f=open('/home/pi/Desktop/hyperledger/multinodes-pi/data.txt',mode='r')
data=f.readlines()
f.close()
res=int(data[0])
res=float(res)/100
f=open('/home/pi/Desktop/hyperledger/multinodes-pi/data.txt',mode='w')
f.write(str(res))
f.close()
time.sleep(1)


energy.py:

# -*- coding:utf-8 -*-
import RPi.GPIO as GPIO
import serial
import time

EN_485 =  4
GPIO.setwarnings(False)
GPIO.setmode(GPIO.BCM)
GPIO.setup(EN_485,GPIO.OUT)
GPIO.output(EN_485,GPIO.HIGH)

t = serial.Serial("/dev/ttyAMA0",9600)    
#print (t.portstr)    
strInput = '01 03 00 4B 00 02 B4 1D'
string=bytes.fromhex(strInput)
#print(string)
n = t.write(string)    
#print (n)
time.sleep(2)
f=open('/home/pi/Desktop/hyperledger/multinodes-pi/data.txt',mode='r')
data=f.readlines()
f.close()
res=int(data[0])
res=float(res)/3200
f=open('/home/pi/Desktop/hyperledger/multinodes-pi/data.txt',mode='w')
f.write(str(res))
f.close()
time.sleep(1)


相对应地,结合上次实验的涡轮流量计,对hyperledger fabric的链码也做了一些修改,预想的情景下一个树莓派采集一组流量计、智能插排、气量计的数据并将其上传到链上,为了方便区分多组仪表的数据,Key值再加入三位ID来表示这一组仪表的编号。如“2022-8-2 001 003”的Key值表示2022年8月2日这天采集到的ID为001的这组仪表的第3条数据。

修改后链码如下:

/*
SPDX-License-Identifier: Apache-2.0
*/

package main

import (
	"encoding/json"
	"fmt"

	"github.com/hyperledger/fabric-contract-api-go/contractapi"
)

type SmartContract struct {
	contractapi.Contract
}

type Data struct {
	Flow_now	string `json:"flow_now(L/H)"`
	Flow_total   	string `json:"flow_total(L)"`
	Voltage	string `json:"voltage(V)"`
	Current	string `json:"current(A)"`
	Power		string `json:"power(W)"`
	Energy		string `json:"energy(kWh)"`
	Factor		string `json:"factor"`
	Emissions	string `json:"emissions(Kg)"`
	Time		string `json:"time"`
}

type QueryResult struct {
	Key    string `json:"Key"`
	Record *Data
}

func (s *SmartContract) InitLedger(ctx contractapi.TransactionContextInterface) error {
	datas := []Data{
		Data{Flow_now: "0", Flow_total: "0", Voltage: "0", Current: "0", Power: "0", Energy: "0", Factor: "0", Emissions: "0", Time: "00:00"},
	}

	for data := range datas {
		dataAsBytes, _ := json.Marshal(data)
		err := ctx.GetStub().PutState("2022-07-20 000 000", dataAsBytes)

		if err != nil {
			return fmt.Errorf("Failed to put to world state. %s", err.Error())
		}
	}

	return nil
}

func (s *SmartContract) AddData(ctx contractapi.TransactionContextInterface, dataNumber string, flow_now string, flow_total string, voltage string, current string, power string, energy string, factor string, emissions string, time string) error {
	data := Data{
		Flow_now:	flow_now,
		Flow_total:   	flow_total,
		Voltage:	voltage,
		Current:	current,
		Power:		power,
		Energy:	energy,
		Factor:	factor,
		Emissions:	emissions,
		Time:		time,
	}

	dataAsBytes, _ := json.Marshal(data)

	return ctx.GetStub().PutState(dataNumber, dataAsBytes)
}

func (s *SmartContract) QueryData(ctx contractapi.TransactionContextInterface, dataNumber string) (*Data, error) {
	dataAsBytes, err := ctx.GetStub().GetState(dataNumber)

	if err != nil {
		return nil, fmt.Errorf("Failed to read from world state. %s", err.Error())
	}

	if dataAsBytes == nil {
		return nil, fmt.Errorf("%s does not exist", dataNumber)
	}

	data := new(Data)
	_ = json.Unmarshal(dataAsBytes, data)

	return data, nil
}

func (s *SmartContract) QueryAllDatas(ctx contractapi.TransactionContextInterface) ([]QueryResult, error) {
	startKey := ""
	endKey := ""

	resultsIterator, err := ctx.GetStub().GetStateByRange(startKey, endKey)

	if err != nil {
		return nil, err
	}
	defer resultsIterator.Close()

	results := []QueryResult{}

	for resultsIterator.HasNext() {
		queryResponse, err := resultsIterator.Next()

		if err != nil {
			return nil, err
		}

		data := new(Data)
		_ = json.Unmarshal(queryResponse.Value, data)

		queryResult := QueryResult{Key: queryResponse.Key, Record: data}
		results = append(results, queryResult)
	}

	return results, nil
}

func main() {

	chaincode, err := contractapi.NewChaincode(new(SmartContract))

	if err != nil {
		fmt.Printf("Error create test chaincode: %s", err.Error())
		return
	}

	if err := chaincode.Start(); err != nil {
		fmt.Printf("Error starting test chaincode: %s", err.Error())
	}
}

shell脚本:

#!/bin/bash
pre=$(date "+%Y-%m-%d")
num="1"
for i in {1..20}
do
	now=$(date "+%Y-%m-%d")
	if [ $pre != $now ]
	then
		num="1"
		pre=$now
	fi
	id=$num
	len=${#id}
	while [ $len -le 2 ]
	do
		id="0"$id
		let len+=1
	done
	let num+=1
	time=$(date "+%H:%M")
	res=$now" 001 "$id
	sudo python /home/pi/RS485_CAN_HAT_Code/485/python/voltage.py
	echo " " >> data.txt
	while read rows
	do
		voltage=$rows
		break
	done < data.txt
	sudo python /home/pi/RS485_CAN_HAT_Code/485/python/current.py
	echo " " >> data.txt
	while read rows
	do
		current=$rows
		break
	done < data.txt
	sudo python /home/pi/RS485_CAN_HAT_Code/485/python/power.py
	echo " " >> data.txt
	while read rows
	do
		power=$rows
		break
	done < data.txt
	sudo python /home/pi/RS485_CAN_HAT_Code/485/python/energy.py
	echo " " >> data.txt
	while read rows
	do
		energy=$rows
		break
	done < data.txt
	sudo python /home/pi/RS485_CAN_HAT_Code/485/python/factor.py
	echo " " >> data.txt
	while read rows
	do
		factor=$rows
		break
	done < data.txt
	sudo python /home/pi/RS485_CAN_HAT_Code/485/python/emissions.py
	echo " " >> data.txt
	while read rows
	do
		emissions=$rows
		break
	done < data.txt
	echo "这是第"$i"次查询到并添加的数据:"
	echo "flow_now(L/H):"$n" flow_total(L):"$t" voltage(V):"$voltage" current(A):"$current" power(W):"$power" energy(kWh):"$energy" factor:"$factor" emissions(Kg):"$emissions" time:"$time
	n=0
	t=0
	cmd="'{\"Args\":[\"AddData\",\"$res\",\"$n\",\"$t\",\"$voltage\",\"$current\",\"$power\",\"$energy\",\"$factor\",\"$emissions\",\"$time\"]}'"
	echo "Add命令:"$cmd
	echo "#!/bin/bash
peer chaincode invoke -o orderer.example.com:7050 --tls true --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C mychannel -n test --peerAddresses peer0.org1.example.com:7051 --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt --peerAddresses peer0.org2.example.com:7051 --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt -c "$cmd "
exit"> add.sh 
 docker cp add.sh cli:/opt/gopath/src/github.com/hyperledger/fabric/peer/
 docker exec -it cli bash add.sh
	sleep 42
#break
done

脚本运行结果:

树莓派 modbus,树莓派,区块链,python,fabric,linux

Org1查询结果:

树莓派 modbus,树莓派,区块链,python,fabric,linux

 ~~

 文章来源地址https://www.toymoban.com/news/detail-791419.html

到了这里,关于树莓派4B与智能插排通过RS485(modbus RTU协议)通信的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包赞助服务器费用

相关文章

  • 【正点原子STM32】RS485串行通信标准(串口基础协议 和 MODBUS协议、总线连接、通信电路、通信波形图、RS485相关HAL库驱动、RS485配置步骤、)

    【正点原子STM32】RS485串行通信标准(串口基础协议 和 MODBUS协议、总线连接、通信电路、通信波形图、RS485相关HAL库驱动、RS485配置步骤、)

    一、RS485介绍 二、RS485相关HAL库驱动介绍 三、RS485配置步骤 四、编程实战 五、总结 串口、UART、TTL、RS232、RS422和RS485之间的关系可以如此理解: 串口 :是一个广义术语,通常指的是采用串行通信协议的接口,它可以包括多种具体的物理接口标准和逻辑电平标准。 UART (通用

    2024年04月13日
    浏览(13)
  • STM32实现基于RS485的简单的Modbus协议

    STM32实现基于RS485的简单的Modbus协议

    我这里用STM32实现,其实可以搬移到其他MCU,之前有项目使用STM32实现Modbus协议 这个场景比较正常,很多时候都能碰到 这里主要是Modbus和变频器通信 最常见的是使用Modbus实现传感器数据的采集,我记得之前用过一些传感器都是Modbus协议 这就需要MCU实现Modbus协议,不过实际使

    2024年02月08日
    浏览(13)
  • 搬运机器人RFID传感器CNS-RFID-01|1S的RS485(MODBUS|HS协议)通讯连接方法

    搬运机器人RFID传感器CNS-RFID-01|1S的RS485(MODBUS|HS协议)通讯连接方法

    搬运机器人RFID传感器CNS-RFID-01|1S支持RS485通信,可支持RS485(MODBUS RTU)协议、RS485-HS协议,广泛应用于物流仓储,立库 AGV|无人叉车|搬送机器人等领域,常用定位、驻车等,本篇重点介绍CNS-RFID-01|1S RFID传感器的RS485通信连接方法。 CNS-RFID-01|1S RFID传感器 1、RS485连接方法 用线缆

    2024年02月04日
    浏览(9)
  • ESP32 使用RS485模块实现Modbus通信(二)

    ESP32 使用RS485模块实现Modbus通信(二)

    MODBUS是一种广泛使用的工业通信协议,它允许通过串行线路在不同设备之间进行通信和数据交换。RS485模块是一个在ESP32上实现MODBUS协议的硬件。在本教程中,我们将使用RS485模块在ESP32开发板上创建一个MODBUS主机和从机设备,并实现与MODBUS主机的通信。 多个Modbus(Server)从机设备

    2024年01月20日
    浏览(13)
  • 【MCAL_UART】-1.2-图文详解RS232,RS485和MODBUS的关系

    【MCAL_UART】-1.2-图文详解RS232,RS485和MODBUS的关系

    目录 1 UART,RS232和RS485通信拓扑 2 什么是RS232 2.1 RS232标准的演变 2.2 RS232标准讲了哪些 2.2.1 RS232通信的电平 2.2.2 RS232通信的带宽 2.2.3 RS232通信距离 2.2.4 RS232通信的机械接口 3 什么是RS485 3.1 RS485标准的演变 3.2 RS485标准讲了哪些 3.2.1 RS485通信的电平 3.2.2 RS485通信的带宽 3.2.2 RS485通信

    2024年02月05日
    浏览(14)
  • Profibus-DP转modbus RTU网关modbus rtu协议

    Profibus-DP转modbus RTU网关modbus rtu协议

    捷米JM-DPM-RTU网关在Profibus总线侧实现主站功能,在Modbus串口侧实现从站功能。可将ProfibusDP协议的设备(如:E+H流量计、倍福编码器等)接入到Modbus网络中;通过增加DP/PA耦合器,也可将Profibus PA从站接入Modbus网络。在Modbus串口侧提供RS485和RS232两种电平接口。 捷米JM-DPM-RTU网关

    2024年02月10日
    浏览(9)
  • STM32CUBUMX配置RS485 modbus STM32(从机)亲测可用

    STM32CUBUMX配置RS485 modbus STM32(从机)亲测可用

    ———————————————————————————————————— ⏩ 大家好哇!我是小光,嵌入式爱好者,一个想要成为系统架构师的大三学生。 ⏩最近在开发一个STM32H723ZGT6的板子,使用STM32CUBEMX做了很多驱动,包括ADC、UART、RS485、EEPROM(IIC)、FLASH(SPI)、mod

    2024年02月14日
    浏览(13)
  • C# ModBus协议(RTU )详细指南

    C# ModBus协议(RTU )详细指南

    ModBus协议:官方的解释是Modbus协议是一种通信协议,用于在自动化设备之间进行数据传输。它最初是由Modicon公司于1979年开发的,现在已成为工业界的一种通用协议。Modbus协议有多种变体,包括 Modbus-RTU、Modbus-TCP和Modbus-ASCII 等,其中Modbus-RTU是最常用的变体之一。Modbus协议基于

    2024年02月04日
    浏览(8)
  • STM32开发(六)STM32F103 通信 —— RS485 Modbus通信编程详解

    STM32开发(六)STM32F103 通信 —— RS485 Modbus通信编程详解

    👈《上一篇》  🏡《主目录》  👉《下一篇》 了解 RS485 Modbus协议技术 。本实验是基于STM32F103开发 实现 通过RS-485实现modbus协议。 准备好了吗?开始我的show time。 1、硬件开发准备 主控:STM32F103ZET6 RS485收发器:SP3485P 2、软件开发准备 软件开发使用虚拟机 + VScode + STM32Cub

    2024年02月03日
    浏览(10)
  • MODBUS RTU协议原理及功能码解析

    MODBUS RTU协议原理及功能码解析

    目录                         第一部分 MODBUS RTU协议原理 1.1 简介 1.2 RTU传输模式 1.3 MODBUS报文帧 1.4 CRC校验                 第二部分 MODBUS RTU模式下功能码解析 2.1 Modbus-RTU协议简介 2.2 部分功能码名词解释 2.3 部分功能码解析 01功能码 –读线圈状态 0

    2024年02月02日
    浏览(14)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包