modbus_tcp的实现 through python.

news2025/2/3 5:45:29

0.引言

当前科技似乎处于加速发展期,各个模块都在快速迭代,迭代的速度会让既有的一些经验产生问题,在用python实现modbus_tcp协议时,网上流传的一些代码中import语句会出现问题。导致pymodbus模块用起来很不好用。

这个原因出在一个子模块的命名上。

pymodbus为了区分同步和异步操作,使用了sync和async作为一整个子模块的分支节点名。然后因为asyn是python的关键字,然后呢,python发现了类似的问题,在3.7附近的某个版本,把这个问题改掉了。但是 pymodbus自己同样做了规避。它也改了,直接取消了这两个分支节点。将代码上移。然后既有的一些代码就都会在import阶段就会报错。

用于物联网的数据传输的这些协议,是协议设计的范本。建议通读相关的原始协议细节。吃透。

1. 示例:写寄存器区域0x10指令的实现

correct code after Dec12,2023

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import sys
import struct
from pymodbus.client import ModbusTcpClient

# modbus_tcp 0x10 cmd
def gpModbusTcpWriteRegisters(SERVER_HOST, SERVER_PORT, base_addr, u16arrayInBigEndiant):
    # Create a Modbus TCP client
    client = ModbusTcpClient(SERVER_HOST, SERVER_PORT)

    # Connect to the Modbus TCP server
    client.connect()

    # Write to a range of holding registers 
    slave_address = 1
    response = client.write_registers(base_addr, u16arrayInBigEndiant, slave_address)
    if response.isError():
        print('Write error:', response)
    else:
        print('Write successful')

    # Disconnect from the Modbus TCP server
    client.close()

#sample frame and comments
'''
frame of 0x10 write holding registers:(write to 0x1000, 40 registers = 80Bytes)
去:
00 01 00 00 00 57 01 10 10 00 00 28 50 3F 99 99 9A BF 99 99 9A 3F 99 99 9A BF 99 99 9A 3F 99 99 9A BF 99 99 9A 3F 99 99 9A BF 99 99 9A 3F 99 99 9A BF 99 99 9A 3F 99 99 9A BF 99 99 9A 3F 99 99 9A BF 99 99 9A 3F 99 99 9A BF 99 99 9A 3F 99 99 9A BF 99 99 9A 3F 99 99 9A BF 99 99 9A 
回:
00 01 00 00 00 06 01 10 10 00 00 28 
            ~~~~~ 06字节(这是协议载荷)
                              ~~~~~ 0x28=40个寄存器(这是协议载荷)

去帧注释:
00 01:事务标识符(Transaction Identifier),用于标识通信的不同事务。
00 00:协议标识符(Protocol Identifier),用于指定使用的 Modbus 协议。
00 57:消息长度(Length),表示请求帧中除了事务标识符和协议标识符之外的字节数。即前六字节后的所有字节和。
01:单元标识符(Unit Identifier),用于指定 Modbus 设备的地址。
10:功能码(Function Code),表示该请求是写多个保持寄存器的请求。
10 00:起始地址(Starting Address),指定要写入的保持寄存器的起始地址。
00 28:寄存器数量(Quantity of Registers),指定要写入的连续保持寄存器的数量。
50:后续数据长度(Byte Count),表示紧随该字节之后的写入数据的字节数。(注意:0x50+0x07=0x57=消息长度(Length))
3F 99:写入数据,表示要写入的第一个保持寄存器的值。3F 99 99 9A = float(1.2)
99 9A:写入数据,表示要写入的第二个保持寄存器的值。
BF 99:写入数据,表示要写入的第三个保持寄存器的值。BF 99 99 9A = float(-1.2)
99 9A:写入数据,表示要写入的第四个保持寄存器的值。
....

注1:modbus_tcp无需校验,因为tcp协议会保证正确性。所以尾部没有追加的校验位。
注2:modbus_tcp没有加密和登陆机制,最简单的实现,可以使用向特定寄存器位置写入Magic Word实现,英文似乎称之为Kick off。
注3:计数器:
     (byte.offset04) 00 57 是字节。(它是帧载荷)
     (byte.offset10) 00 28 是寄存器。(这是协议载荷)
     (byte.offset12) 50 是字节。(这是帧载荷)
    
'''

上面是当前有效的命令0x10,区段寄存器写入的代码。其他依此类推。

Modbus协议遵从大端模式,如果自己整理寄存器数据,建议设置为大端模式,避免不必要的三方调试开销:

def floatArray2U16Array(float_array):
    byte_array = bytes([b for f in float_array for b in bytearray(struct.pack('>f', f))])
    u16_array = [int.from_bytes(byte_array[i:i+2], 'big', signed=False) for i in range(0, len(byte_array), 2)]
    return u16_array

因为Modbus每个寄存器是16位,上面将floatArray转为能够供WriteRegisters使用的ushort数组的过程。其他的数据格式以此类推。

2.0x03 读寄存器区域(写寄存器区域0x10的逆操作)

frame of 0x03帧 及其回应帧
去:00 01 00 00 00 06 01 03 00 00 00 14 
注3:去帧的的计数器 
     (byte.offset04) 00 06 是字节。(它是帧载荷)
     (byte.offset10) 00 14 是寄存器数量: = 20(0x0014 = 20)个寄存器,(这是协议载荷)

回:00 01 00 00 00 2B 01 03 28 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
注4:回帧的计数器都是字节:
      (byte.offset04)00 2B 是字节;(它是帧载荷)
      (byte.offset08)28 也是字节,(它是帧载荷)

附录A 故障纠错

Modbus调试过程中最容易出现问题有这么几个:

  • 各种计数值的单位,是字节还是寄存器数量。
  • 是否加校验位。
  • 设备id.

A1可直接用于调试的测帧

 A1.1 图例和数据识读

00 57,这是字节尺寸,同一个帧的字节尺寸要彼此匹配。

10 00,这是寄存器地址,可能涉及回应帧之间的匹配。

00 28,这是寄存器数量,可能涉及回应帧字节尺寸和寄存器数量之间的匹配;当前帧字节尺寸的匹配。

  • 字节顺序Offset 04的两个字节,= 整个数据帧长度-6.即帧头6字节以后的所有字节数量。它只和当前待发送的数据帧尺寸有关。
  • 在命令帧之后,真正的寄存器数据之前,还有一个字节长度。这个长度仅仅与数据区段的字节长度有关。仅仅与当前帧有关。

A1.2 0x10 区段寄存器写

  1. 去:
    00 01 00 00 00 57 01 10 10 00 00 28 50 3F 99 99 9A BF 99 99 9A 3F 99 99 9A BF 99 99 9A 3F 99 99 9A BF 99 99 9A 3F 99 99 9A BF 99 99 9A 3F 99 99 9A BF 99 99 9A 3F 99 99 9A BF 99 99 9A 3F 99 99 9A BF 99 99 9A 3F 99 99 9A BF 99 99 9A 3F 99 99 9A BF 99 99 9A 3F 99 99 9A BF 99 99 9A 
  2. 回:
    00 01 00 00 00 06 01 10 10 00 00 28 

A1.3 0x03 区段寄存器读

  1. 去:
    00 01 00 00 00 06 01 03 00 00 00 14
  2. 回:
    00 01 00 00 00 2B 01 03 28 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 

附录B 一个测试用的modbus_tcp服务器

pymodbus目前似乎在尝试把服务器功能再次封装。而不是通过直接封装在pymodbus里的StartAsyncTcpServer来实现。当前的doc甚至把这些函数的传入参数隐藏了起来。

注意:pyModbusTCP是一个独立的组件。

#!/usr/bin/env python3

"""
Modbus/TCP server
~~~~~~~~~~~~~~~~~

Run this as root to listen on TCP privileged ports (<= 1024).

Add "--host 0.0.0.0" to listen on all available IPv4 addresses of the host.
$ sudo ./server.py --host 0.0.0.0
"""

import argparse
import logging
from pyModbusTCP.server import ModbusServer


# init logging
logging.basicConfig()
# parse args
parser = argparse.ArgumentParser()
parser.add_argument('-H', '--host', type=str, default='localhost', help='Host (default: localhost)')
parser.add_argument('-p', '--port', type=int, default=502, help='TCP port (default: 502)')
parser.add_argument('-d', '--debug', action='store_true', help='set debug mode')
args = parser.parse_args()
# logging setup
if args.debug:
    logging.getLogger('pyModbusTCP.server').setLevel(logging.DEBUG)
# start modbus server
server = ModbusServer(host=args.host, port=args.port)
server.start()

附录C python相关的组件安装指令:

这里有一个用于组件升级的语法,还有一个用于组件安装的语法。国内访问国外原始的python组件库速度会太慢。这里实际引用的是国内镜像站。另外,使用python打头的语法,可以控制当前设备上具体的python示例(你的机器上可能安装有多个Python版本),你可以把最前面的python替换为某个特定目录下的python.exe的全路径。

python -m pip install --upgrade pip --timeout 200 -i http://mirrors.aliyun.com/pypi/simple/  --trusted-host mirrors.aliyun.com


python -m pip install pymodbus  --timeout 200 -i http://mirrors.aliyun.com/pypi/simple/  --trusted-host mirrors.aliyun.com

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

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

相关文章

集合工具类Collections

概述 java.utils.Collections:是集合工具类 作用&#xff1a;Collections并不属于集合&#xff0c;是用来操作集合的工具类。 Collections常用的API Collections排序相关API 使用范围&#xff1a;只能对于List集合的排序。 排序方式1&#xff1a; 注意&#xff1a;本方式…

23 在HST场景中,考虑物理层相关技术

文章目录 实验参数A&#xff1a;解调参考信号(DMRS)1 DMRS分配图2 实验结果图figur3figur4 3. 实验结论 B 映射资源元素。1 映射图2 实验结果图figure 6figure 7 3. 实验结论figure8 3 补充结论 C μ1 实验结果图&#xff1a;figure 9figure 10 2 结论 实验参数 注释&#xff1…

数据结构和算法-红黑树(定义 性质 查找 插入 删除)

文章目录 红黑树的定义和性质为什么要发明红黑树&#xff1f;红黑树怎么考总览红黑树的定义实例&#xff1a;一颗红黑树练习&#xff1a;是否符合红黑树的要求一种可能的出题思路补充概念&#xff1a;节点黑高 红黑树的性质 红黑树的查找红黑树的插入实例小结与黑高相关的理论 …

web前端游戏项目-堆木头游戏【附源码】

web前端游戏项目-堆木头游戏 《堆木头》游戏玩法简单&#xff0c;通过鼠标点击放木头的按钮&#xff0c;叠加在一起&#xff0c;构建出各种结构。游戏适合所有年龄段的孩子&#xff0c;可以锻炼孩子的动手能力和手眼协调能力&#xff0c;激发孩子的创造力和想象力 运行效果 …

使用GitZip下载GitHub指定文件

目录 一、GitZip二、安装GitZip三、链接GitHub四、检验是否安装成功五、总结 一、GitZip GitZip是一个非常实用的浏览器插件&#xff0c;它主要有以下几个优点&#xff1a; 下载指定文件&#xff1a;在我们浏览Github时&#xff0c;如果只想下载某个子目录的内容&#xff0c;…

15-高并发-如何扩容

对于一个发展初期的系统来说&#xff0c;不太确定商业模型到底行不行&#xff0c;最好的办法是按照最小可行产品方法进行产品验证&#xff0c;因此&#xff0c;刚开始的功能会比较少&#xff0c;是一个大的单体应用&#xff0c;一般按照三层架构进行设计开发&#xff0c;使用单…

服务器IBM x3650 m2 管理口访问故障处理

服务器的内存告警后&#xff0c;连接管理口查看信息&#xff0c;管理口状态灯显示正常&#xff0c;但是无法ping通和访问。 处理过程如下&#xff1a; 1、在centos 6.6中安装ipmitool&#xff0c;替换为阿里云的yum源&#xff0c;然后安装。 # wget -O /etc/yum.repos.d/Cen…

【String、StringBuilder 和 StringBuffer 的 区别】

✅ String、StringBuilder 和 StringBuffer 的 区别 ✅典型解析✅扩展知识仓✅String 的不可变性✅ 为什么JDK 9 中把String 的char[ ] 改成了 byte[ ] ? ✅为什么String设计成不可变的✅缓存✅安全性✅线程安全✅hashcode缓存✅ 性能 ✅String 的 " " 是如何实现的…

Ubuntu 常用命令之 du 命令用法介绍

&#x1f4d1;Linux/Ubuntu 常用命令归类整理 Ubuntu系统下的du命令是一个用来估计和显示文件和目录所占用的磁盘空间的命令。du是“disk usage”的缩写&#xff0c;这个命令可以帮助用户了解磁盘被哪些文件和目录使用。 du命令的常见参数有 -a&#xff1a;列出所有文件和目…

STM32的以太网外设+PHY(LAN8720)使用详解(3):PHY寄存器详解

0 工具准备 1.野火 stm32f407霸天虎开发板 2.LAN8720数据手册 3.STM32F4xx中文参考手册1 PHY寄存器 前面介绍到&#xff0c;站管理接口&#xff08;SMI&#xff09;允许应用程序通过2线时钟和数据线访问任意PHY寄存器&#xff0c;同时该接口支持访问最多32个PHY&#xff0c;也…

一个基于多接口的业务自动化测试框架!

这是一个成熟的框架&#xff0c;不是要让别人当小白鼠&#xff0c;它已经先后在两家公司的5条业务线进行了推广应用&#xff0c;用例条数到了几千条以上&#xff0c;并且从2018年开始每天都在CI/CD流程中被调用执行。 已有那么多接口测试框架&#xff0c;为什么重复造轮子&…

在芯片设计端,从事DFT岗位是什么体验?

从1975年PHILIPS公司实验中心首次提出“可测性设计”概念至今&#xff0c;DFT已经伴随着芯片走过了半个世纪。 但DFT在数字IC设计岗位中还是显得很神秘很低调。 你说他重要吧&#xff0c;并不是所有芯片设计公司都有这个岗位&#xff0c;你说他不重要吧&#xff0c;但凡芯片产…

数据结构 | 北京大学期末试卷查漏补缺

目录 顺序存储 优点 缺点 适用于&#xff1a; 链式存储 优点 缺点 适用于&#xff1a; 折半查找为什么要使用顺序存储结构 树的存储结构​编辑 对于一个数据结构&#xff0c;一般包括 DFS&BFS 什么是递归程序 C语言不带头结点的单链表逆置 检测字符…

【CMake保姆级教程】制作动静态链接库、指定动静态库输出路径

文章目录 前言一、动静态链接库的介绍1.1 动态链接库 (DLL)1.2 静态链接库 (LIB) 二、制作静态库三、制作动态库四、指定动静态库输出路径4.1 方式1 - 适用于动态库4.2 方式2 - 都适用 总结 前言 在软件开发中&#xff0c;我们经常听到动态链接库&#xff08;Dynamic Link Lib…

c语言易错题之数据类型变换

1.题目 #include<stdio.h> int main() {int arr[]{1,2,3,4,5};short*p (short*)arr;int i 0;for(i0;i<4;i){*(pi)0;}for(i0;i<5;i){printf("%d ",arr[i];}return 0; }2.解析 这道题主要容易错在&#xff0c;大家会以为通过指针赋值的时候&#xff0c;…

基于springboot的日记本系统源码+数据库+安装使用说明

之前写的SpringBoot日记本系统备受好评&#xff0c;考虑到还是有很多小伙伴不会部署&#xff0c;所以这一篇文章就单独来讲一下部署步骤吧。 需要资源 idea&#xff08;破不破解都行&#xff09; MySQL&#xff08;最好5.7以上版本&#xff0c;最好8.0&#xff09; Navicat…

SpringBoot Elasticsearch全文搜索

文章目录 概念全文搜索相关技术Elasticsearch概念近实时索引类型文档分片(Shard)和副本(Replica) 下载启用SpringBoot整合引入依赖创建文档类创建资源库测试文件初始化数据创建控制器 问题参考 概念 全文搜索&#xff08;检索&#xff09;&#xff0c;工作原理&#xff1a;计算…

Node.js-模块化(二)

1. 模块化的基本概念 1.1 什么是模块化 模块化是指解决一个复杂问题时&#xff0c;自顶向下逐层将系统拆分成若干模块的过程。对于整个系统来说&#xff0c;模块是可组合、分解和更换的单元。 1.2 编程领域中的模块化 编程领域中的模块化&#xff0c;就是遵守固定的规则&…

Spring源码分析 @Autowired 是怎样完成注入的?究竟是byType还是byName亦两者皆有

1. 五种不同场景下 Autowired 的使用 第一种情况 上下文中只有一个同类型的bean 配置类 package org.example.bean;import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration;Configuration public class FruitCo…

git首次使用--去公司第一次拉取

文章目录 一&#xff0c; 在企业中首次拉取项目二&#xff0c;提交项目1. 提交----新添加的文件2. 将分支上的代码同步到master3. 提交----更改后的文件 三&#xff0c;常见问题1. Git Pull Failed 提示&#xff1a;以下是本篇文章正文内容&#xff0c;下面案例可供参考 一&am…