14、监测数据采集物联网应用开发步骤(10)

news2024/9/20 18:37:32
  1. 监测数据采集物联网应用开发步骤(9.2)

Modbus rtu协议开发

本章节在《监测数据采集物联网应用开发步骤(7)》基础上实现可参考《...开发步骤(7)》调试工具,本章节代码需要调用modbus_tk组件阅读本章节前建议baidu熟悉modbus rtu协议内容

组件安装modbus_tk

pip3 install modbus_tk

验证是否安装成功,python中运行下列代码无异常则安装成功:

import modbus_tk

新建modbus协议管理类com.zxy.comport.ComModBus.py

#! python3
# -*- coding: utf-8 -
'''
Created on 2020年05月10日
@author: zxyong 13738196011
'''
import time,struct
from com.zxy.common import Com_Para
from com.zxy.common.Com_Fun import Com_Fun
from com.zxy.z_debug import z_debug
import modbus_tk.defines as cst
import modbus_tk.modbus_rtu as modbus_rtu

#监测数据采集物联网应用--modbus协议管理类
class ComModBus(z_debug):
    
    def __init__(self):
        pass
        
    @staticmethod
    def get_objAryRtuMaster(inputComPort):        
        master = Com_Fun.GetHashTableNone(Com_Para.objAryRtuMaster, inputComPort)
        if master is None:
            com_at = Com_Fun.GetHashTableNone(Com_Para.htComPort, inputComPort)
            if com_at is not None:
                master = modbus_rtu.RtuMaster(com_at.attSerial)           
                # 设定串口为从站
                master.set_timeout(5.0)
                master.set_verbose(True)
                Com_Fun.SetHashTable(Com_Para.objAryRtuMaster, inputComPort, master)
        return master
    
    #字符串转16进制字节并+crc16校验,传入参数无crc校验
    @staticmethod
    def get_data_com_nocrc(inputComPort, CmdStr):  
        temReturn = None       
        try:  
            com_at = Com_Fun.GetHashTable(Com_Para.htComPort, inputComPort)  
            inputByte = bytes().fromhex(CmdStr)
            inputByte = inputByte + ComModBus._getCrc16(inputByte)
            if com_at.WritePortData(inputByte) > 0:
                temReturn = com_at.attReturnValue                    
                com_at.attReturnValue = None
        except Exception as e:
            temReturn = None
        return temReturn
    
    #字符串转字节发送,ascii发送
    @staticmethod
    def get_data_com_ascii(inputComPort, CmdStr):  
        temReturn = None       
        try:  
            com_at = Com_Fun.GetHashTable(Com_Para.htComPort, inputComPort)
            inputByte = bytes(CmdStr, encoding="utf8")
            if com_at.WritePortDataImmed(inputByte) > 0:
                temReturn = com_at.attReturnValue                    
                com_at.attReturnValue = None
        except Exception as e:
            temReturn = None
        return temReturn
    
    #字符串转16进制字节发送
    @staticmethod
    def get_data_com_hex(inputComPort, CmdStr):     
        temReturn = None    
        try:
            com_at = Com_Fun.GetHashTable(Com_Para.htComPort, inputComPort)  
            inputByte = bytes().fromhex(CmdStr)
            if com_at.WritePortData(inputByte) > 0:
                comValue = com_at.attReturnValue
                if comValue is None:
                    return None
                temReturn = comValue
                com_at.attReturnValue = None
        except Exception as e:
            temReturn = None
        return temReturn
    
    #字节发送
    @staticmethod
    def get_data_com_byte(inputComPort, inputByte):    
        temReturn = None     
        try:
            com_at = Com_Fun.GetHashTable(Com_Para.htComPort, inputComPort)  
            if com_at.WritePortData(inputByte) > 0:
                comValue = com_at.attReturnValue
                if comValue is None:
                    return None
                temReturn = comValue
                com_at.attReturnValue = None
        except Exception as e:
            temReturn = None
        return temReturn
    
    #Modbus 04功能码发送
    @staticmethod
    def get_data_rtu_04(inputComPort, inputModbusAddr, inputModbusBegin, inputModbusLength):
        red = []
        try:
            master = ComModBus.get_objAryRtuMaster(inputComPort)
            if master is not None:
                red = master.execute(int(inputModbusAddr), cst.READ_INPUT_REGISTERS, int(inputModbusBegin), int(inputModbusLength))  # 这里可以修改需要读取的功能码             
                time.sleep(0.1)                
            if isinstance(red, list) or isinstance(red, tuple): 
                return red
            else:
                return [""]
        except Exception as e:
            return [""]
    
    #Modbus 03功能码发送 
    @staticmethod
    def get_data_rtu_03(inputComPort, inputModbusAddr, inputModbusBegin, inputModbusLength):
        read = []
        try:
            master = ComModBus.get_objAryRtuMaster(inputComPort)
            if master is not None:
                read = master.execute(inputModbusAddr, cst.READ_HOLDING_REGISTERS, inputModbusBegin, inputModbusLength)  # 这里可以修改需要读取的功能码             
                time.sleep(0.1)                
            if isinstance(read, list) or isinstance(read, tuple): 
                return read
            else:
                return [""]
        except Exception as e:
            return [""]
    
    #Modbus 写寄存器数据
    @staticmethod
    def set_data_rtu(inputComPort, inputModbusAddr, inputModbusBegin, inputValue):
        read = []
        try:
            master = ComModBus.get_objAryRtuMaster(inputComPort)
            if master is not None:
                # 这里可以修改需要读取的功能码 
                if isinstance(inputValue, list) or isinstance(read, tuple):
                    read = master.execute(inputModbusAddr, cst.WRITE_MULTIPLE_REGISTERS, inputModbusBegin, output_value=inputValue) 
                else:
                    read = master.execute(inputModbusAddr, cst.WRITE_SINGLE_REGISTER, inputModbusBegin, output_value=inputValue)               
            if isinstance(read, list) or isinstance(read, tuple): 
                return read
            else:
                return [""]
        except Exception as e:
            return [""]
        
    @staticmethod
    def set_data_rtu2(inputComPort, inputModbusAddr, inputModbusBegin, inputValue):
        read = []
        try:
            master = ComModBus.get_objAryRtuMaster(inputComPort)
            if master is not None:
                # 这里可以修改需要读取的功能码 
                if isinstance(inputValue, list) or isinstance(read, tuple):
                    read = master.execute(inputModbusAddr, cst.ANALOG_INPUTS, inputModbusBegin, output_value=inputValue) 
                else:
                    read = master.execute(inputModbusAddr, cst.ANALOG_INPUTS, inputModbusBegin, output_value=inputValue)               
            if isinstance(read, list) or isinstance(read, tuple): 
                return read
            else:
                return [""]
        except Exception as e:
            return [""]
        
    @staticmethod
    def _getCrc16(RtuStr):
        b = 0xA001
        # 16位寄存器
        a = 0xFFFF
        for byte in RtuStr:
            # 1、把数据帧中的第一个8位字节与CRC寄存器中的低字节进行异或运算
            a = a ^ byte
            for i in range(8):
                # 3、如果最低位为1:将CRC寄存器与一个预设的固定值(0A001H)进行异或运算
                if a & 0x0001:
                    a = a >> 1
                    a = a ^ b 
                # 2、将CRC寄存器向右移一位,最高位填以0,最低位移出并检测
                else:
                    a = a >> 1
        aa = '0' * (6 - len(hex(a))) + hex(a)[2:]
        # 获取低和高位
        lo, hh = int(aa[:2], 16), int(aa[2:], 16)
        hexbytes = bytes([hh, lo])
        return hexbytes
           
    #高低位 reverse: true高位在前 false低位在前
    @staticmethod
    def ReadFloat(n1, n2, reverse=False):    
        n = '%04x' % n1
        m = '%04x' % n2
        if reverse:
            v = n + m
        else:
            v = m + n
        y_bytes = bytes.fromhex(v)
        y = struct.unpack('!f', y_bytes)[0]
        y = round(y, 6)
        return y
    
    @staticmethod
    def WriteFloat(value, reverse=False):
        y_bytes = struct.pack('!f', value)
        y_hex = ''.join(['%02x' % i for i in y_bytes])
        n, m = y_hex[:-4], y_hex[-4:]
        n, m = int(n, 16), int(m, 16)
        if reverse:
            v = [n, m]
        else:
            v = [m, n]
        return v
    
    @staticmethod
    def ReadDint(n1,m1, reverse=False):
        n ='%04x' % n1
        m = '%04x' % m1
        if reverse:
            v = n + m
        else:
            v = m + n
        y_bytes = bytes.fromhex(v)
        y = struct.unpack('!i', y_bytes)[0]
        return y
    
    @staticmethod
    def WriteDint(value, reverse=False):
        y_bytes = struct.pack('!i', value)
        y_hex = ''.join(['%02x' % i for i in y_bytes])
        n, m = y_hex[:-4], y_hex[-4:]
        n, m = int(n, 16), int(m, 16)
        if reverse:
            v = [n, m]
        else:
            v = [m, n]
        return v

modbus rtu测试案例MonitorDataCmd.py主文件中编写:

from com.zxy.comport.ComModBus import ComModBus

在    if __name__ == '__main__':下添加

        #串口配置参数
        Com_Para.ComPortList = "COM2,9600,8,0,A;COM4,9600,8,2,B"
        #串口连接初始化
        Init_Page.Start_ComPort()
        #Modbus-rtu协议功能测试
        temA01modbus = ComModBus()
        #利用modbus_tk组件获取数据,参数:COM索引,modbus站地址,modbus起始位,modbus长度
        read = temA01modbus.get_data_rtu_03("A",1,0,10)
        print("获取10进制原始返回值=>"+str(read))
        modValue = []
        iIndex = 0.0
        n1 = 0
        n2 = 0
        for temSV in read:
            if iIndex % 2 != 0:
                n2 = int(temSV)
                #16进制单精转浮点
                temMV = temA01modbus.ReadFloat(n1,n2,True)
                modValue.append(temMV)
            else:
                n1 = int(temSV)
            iIndex = iIndex + 1
        print("获取读到并解析的寄存器浮点数=>"+str(modValue))
        
        #利用modbus指令协议直接通过com口读取数据
        temCmd = "010300A1000A942F"
        bhex = temA01modbus.get_data_com_hex("A",temCmd)
        read = str(binascii.b2a_hex(bhex).decode(Com_Para.U_CODE)).upper()
        print("获取16进制返回值=>"+str(read))

运行测试结果如下图:

测试案例中例举了2种方法都可以读到数据,任取其一即可。

针对        

#利用modbus指令协议直接通过com口读取数据

      temCmd = "010300A1000A942F"

指令解释如下:

01 站地址

03 功能码

00A1 寄存器开始地址(16进制)

000A  读取数据长度10个(16进制转10进制)

942F CRC校验码

获取16进制返回值=>010314429DA8F643060A3D420070A44343000043554CCD49A8返回值解释如下:

01 站地址

03 功能码

14 数据长度20(16进制转10进制)

429DA8F643060A3D420070A44343000043554CCD 数据值16进制

49A8 CRC校验码

429DA8F643060A3D420070A44343000043554CCD 数据值解析要依据相关对方开发说明文档,假设该数据为寄存器浮点数则按如下解析:

429D A8F6 ==>10进制浮点数 78.83

4306 0A3D ==>10进制浮点数 134.039

4200 70A4 ==>10进制浮点数 32.11

4343 0000 ==>10进制浮点数 195

4355 4CCD ==>10进制浮点数 213.300

可以利用该工具计算IEEE 754浮点数十六进制相互转换(32位,四字节,单精度)

在线进制转换-IEE754浮点数16进制转换

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/948475.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【同步异步可并发日志系统】设计及实现

1. 项⽬介绍2. 开发环境3. 项目核⼼技术4. 环境搭建5. ⽇志系统介绍5.1 为什么需要⽇志系统5.2⽇志系统技术实现5.2.1 同步写⽇志5.2.2 异步写⽇志 6. ⽇志系统框架设计7. 代码设计7.1 实⽤类设计7.2 ⽇志等级类设计7.3 ⽇志消息类设计7.4 ⽇志格式化输出设计思想7.4.1FormatIt…

OpenLayers7官方文档翻译,OpenLayers7中文文档,OpenLayers快速入门

快速入门 这个入门文档向您展示如何放一张地图在web网页上。 开发设置使用 NodeJS(至少需要Nodejs 14 或更高版本),并要求安装 git。 设置新项目 开始使用OpenLayers构建项目的最简单方法是运行:npm create ol-app npm create…

中大许少辉博士后畅销榜《乡村振兴战略下传统村落文化旅游设计》自由营 ​​​

中大许少辉博士后畅销榜《乡村振兴战略下传统村落文化旅游设计》自由营 ​​​

Visual Studio(2022)生成链接过程的.map映射文件以及.map映射文件的内容说明

微软的官方说明 /MAP(生成映射文件) | Microsoft Learn 设置步骤 1. 右键项目属性, 连接器 -> 常规 -> 启用增量链接,设置为否。如下图: 2. 连接器 -> 调试 生成调试信息 设置为 生成调试信息 (/DEBUG) 生成程序数据库…

这一天,中国企业一同吹响数字化集结号

买一双袜子平均只要3天就可以收到货。 点一份外卖最快20分钟就可以送达。 消费互联网十年轰轰烈烈的发展,带来了全国商品的大流通,极大丰富了我们的物质消费生活,也为传统线下商家带来成百上千倍的增长。 消费互联网的流量鼎盛期过后&#xf…

无入侵接口文档smart-doc

Smart-doc优点&#xff1a; 1.非侵入式生成接口文档 2.减少接口文档的手动更新麻烦&保证了接口文档和代码的一致 3.随时可生成最新的接口文档 4.保持团队代码风格一致:smart-doc支持javadoc&#xff0c;必须按照这个才能生成有注释的接口文档 最终效果 1.导入依赖 <pl…

ssm+vue人力资源管理系统源码和论文

ssmvue人力资源管理系统源码和论文098 开发工具&#xff1a;idea 数据库mysql5.7 数据库链接工具&#xff1a;navcat,小海豚等 技术&#xff1a;ssm 系统目标 本系统主要目标是对大中型公司所设计&#xff0c;是对人力资源的科学化的管理&#xff0c;使信息存储达到精确…

2024年java面试(四)--spring篇

文章目录 1.BeanFactory 和 FactoryBean 的区别2.BeanFactory和ApplicationContext有什么区别?3.RequestBody、RequestParam、ResponseBody4.cookie和session的区别5.Servlet的生命周期6.Jsp和Servlet的区别7.SpringMvc执行流程8.RequestMapping是怎么使用9.如果一个接口有多个…

Android 蓝牙开发( 二 )

前言 上一篇文章给大家分享了Android蓝牙的基础知识和基础用法&#xff0c;不过上一篇都是一些零散碎片化的程序&#xff0c;这一篇给大家分享Android蓝牙开发实战项目的初步使用 效果演示 : Android蓝牙搜索&#xff0c;配对&#xff0c;连接&#xff0c;通信 Android蓝牙实…

数据包的处理流程

一个数据包从发送到接收都经历了那些过程 1.启动应用程序新建邮件&#xff0c;将收件人邮箱和邮件内容填写好&#xff0c;应用程序进行编码处理。&#xff08;应用层&#xff09; 2.应用在发送邮件那一刻建立TCP连接&#xff08;三次握手&#xff09;&#xff0c;将数据交给传…

在Nodejs中使用JWT进行鉴权

什么是 JSON Web Token&#xff08;JWT&#xff09;&#xff1f; JSON Web Token&#xff08;JWT&#xff09;是一种用于在web上传递信息的标准&#xff0c;它以JSON格式表示信息&#xff0c;通常用于身份验证和授权。 JWT由三个部分组成&#xff1a;Header&#xff08;头部&…

五、MySQL(DML)如何连接到DataGrip?并显示所有数据库?

前提&#xff1a;已经配置好DataGrip&#xff0c;并创建好一个项目&#xff1a; 1、选择数据库&#xff1a; 点击左上角加号&#xff0c;再选择数据源&#xff0c;选择MySQL数据源&#xff1a; 2、填写信息&#xff1a; 用户栏填写&#xff1a;root 密码填写&#xff1a;你…

算法设计 || 第9题:0-1背包问题动态规划(手写例题+源代码)

&#xff08;一&#xff09;背包问题知识点&#xff1a; &#xff08;二&#xff09;经典测试题&#xff1a; 已知n8种&#xff0c;每种一件。背包最大负载M110。 重量w和价值v如下表&#xff0c;怎样装价值最大?贪心算法 求X[N]最优解&#xff0c;写出求解过程;强化为0/1背包…

基于clip驱动的器官分割和肿瘤检测通用模型

论文&#xff1a;https://arxiv.org/abs/2301.00785 我看这篇主要是看看MRI的多模态融合方法的&#xff0c;所以会略一些东西&#xff0c;感兴趣细节的就翻原文好嘞 摘要 越来越多的公共数据集在自动器官分割和肿瘤检测方面显示出显著的影响。然而&#xff0c;由于每个数据集…

冠达管理:股票减持是什么意思?2023减持新规?

在a股商场上&#xff0c;大股东一般会进行大宗买卖、减持来影响股价&#xff0c;那么&#xff0c;股票减持是什么意思&#xff1f;2023减持新规&#xff1f;下面冠达管理为我们准备了相关内容&#xff0c;以供参阅。 ​ 股票减持是指上市公司持股比例较高的股东出售所持股份以…

ARM-M0 + 24bit 高精度ADC,采样率4KSPS,国产新品,传感器首选

ARM-M0内核MCU 内置24bit ADC &#xff0c;采样率4KSPS flash 64KB&#xff0c;SRAM 32KB 适用于传感器&#xff0c;电子秤&#xff0c;体脂秤等等

【爬虫】5.6 Selenium等待HTML元素

任务目标 在浏览器加载网页的过程中&#xff0c;网页的有些元素时常会有延迟的现象&#xff0c;在HTML元素还没有准备好的情况下去操作这个HTML元素必然会出现错误&#xff0c;这个时候Selenium需要等待HTML元素。例如&#xff1a;上节实例中出现的select的下拉框元素&#xff…

htmx-使HTML更强大

‍本文作者是360奇舞团开发工程师 htmx 让我们先来看一段俳句: javascript fatigue: longing for a hypertext already in hand 这个俳句很有意思&#xff0c;是开源项目htmx文档中写的&#xff0c;意思是说&#xff0c;我们已经有了超文本&#xff0c;为什么还要去使用javascr…

1、Spring是什么?

Spring 是一款主流的 Java EE 轻量级开源框架 。 框架 你可以理解为是一个程序的半成品&#xff0c;它帮我们实现了一部分功能&#xff0c;用这个框架我们可以减少代码的实现和功能的开发。 开源 也就是说&#xff0c;它开放源代码。通过源代码&#xff0c;你可以看到它是如何…