MicroPython Modbus library v2.3.7使用笔记1

https://micropython-modbus.readthedocs.io/en/latest/readme_link.html#

MicroPython v1.24.1 on 2024-11-29; Generic ESP32 module with ESP32

1、线程:modbus slaver TCP协议,做电力仪表数据采集、处理、转发单元,配300个寄存器regs,二十几台表一次性轮询存入lista,再一次性写modbus slaver的set_ireg(0, lista)。

2、中断:modbus master RTU每3秒定时轮询电表,因为存在超时未完成情况,设置标志位,轮询未完成时,不进行新任务。

线程1modbus slaver TCP接收上位机查询Modbus Poll、Kepware等应用程序,如果线程2modbus master轮询完成正在写内存set_ireg(),同时读写,内核有机制避免资源冲突么?

用随机数set_ireg测试

lista = [urandom.randint(1, 65535) for i in range(300)]

t_randint.py 生产300个随机整数测试写mbSlaver.py实例

from micropython import const
import urandom,time
import mbSlaver

def set_iregs():
    
    while True :
        lista = [urandom.randint(1, 65535) for i in range(300)]
        # print(lista)
        time.sleep(1)
        set_ireg_startime = time.ticks_ms()
        mbSlaver.client.set_ireg(0, lista)
        set_ireg_endtime = time.ticks_ms()
        set_ireg_duration = set_ireg_endtime - set_ireg_startime
        print(f"main() set_ireg duration :{set_ireg_duration} ms")
        
if __name__ == "__main__":
    set_iregs()

mbSlaver.py  modbus slaver TCP Server

# GW-DTU-301 数据转发单元
import network
from machine import Pin

# import modbus client classes
from umodbus.tcp import ModbusTCP

# TCP Slave setup
tcp_port = 502  # port to listen to
# set IP address of the MicroPython device explicitly
local_ip = "192.168.1.119"  # IP address
# or get it from the system after a connection to the network has been made

# ModbusTCP can get TCP requests from a host device to provide/set data
client = ModbusTCP()
is_bound = False

# check whether client has been bound to an IP and port
is_bound = client.get_bound_status()

if not is_bound:
    client.bind(local_ip=local_ip, local_port=tcp_port)

# commond slave register setup, to be used with the Master example above
register_definitions = {
    "COILS": {
        "COIL": {
            "register": 0,
            "len": 10,
            "val": [i for i in range(10)],  # 启用10个元素,初始赋值0
        }
    },
    "HREGS": {
        "HREG": {
            "register": 0,
            "len": 10,
            "val": [i for i in range(10)],  # 启用10个元素,初始赋值0
        }
    },
    "ISTS": {
        "ISTS": {
            "register": 0,
            "len": 10,
            "val": [i for i in range(10)],  # 启用10个元素,初始赋值0
        }
    },
    "IREGS": {
        "IREG": {
            "register": 0,
            "len": 300,
            "val": [0 for i in range(300)],  # 启用300个元素,初始赋值0
        }
    },
}

"""
# alternatively the register definitions can also be loaded from a JSON file
import json

with open('registers/example.json', 'r') as file:
    register_definitions = json.load(file)
"""
print("Setting up registers ... initial ...")
# use the defined values of each register type provided by register_definitions
client.setup_registers(registers=register_definitions)
# alternatively use dummy default values (True for bool regs, 999 otherwise)
# client.setup_registers(registers=register_definitions, use_default_vals=True)
print("Register setup done")
print("Serving as TCP client on {}:{}".format(local_ip, tcp_port))


def call_mbslaver():
    while True:
        try:
            result = client.process()
        except KeyboardInterrupt:
            print("KeyboardInterrupt, stopping TCP client...")
            break
        except Exception as e:
            print("Exception during execution: {}".format(e))
    print("Finished providing/accepting data as client")


if __name__ == "__main__":
    call_mbslaver()


main.py

# GW-DTU-301 数据转发单元 main
import network, _thread, micropython, esp32, machine
import mbSlaver,t_randint,time

lock = _thread.allocate_lock()

try:
    _thread.start_new_thread(mbSlaver.call_mbslaver, ())
except Exception as e:
    machine.reset()

time.sleep(3)
_thread.start_new_thread(t_randint.set_iregs, ())

while True:
#     lock.acquire()
#     lock.release()
    micropython.mem_info()
    print(time.localtime())
    time.sleep(10)  # 主线程阻塞,不影响其他线程调度执行


测试结果:

还有一个mbSlaver重复导入的问题,deepseek这样回答感觉与实际运行结果一致:

在Python中,处理文件导入重复的问题通常涉及模块导入机制和代码组织。

理解Python的模块缓存机制
Python默认会缓存已导入的模块(存储在 sys.modules 中),重复的 import 语句不会重新执行模块代码。例如:
# module_a.py
print("Module A 被导入")

# main.py
import module_a  # 输出 "Module A 被导入"
import module_a  # 无输出(已缓存)

### ESP32 使用 MicroPython 进行 Modbus 通信的示例代码 为了实现 ESP32 设备上的 Modbus RTU 主站功能,可以利用 `micropython-modbus` 库来简化操作过程。下面是一个简单的 Python 脚本实例,用于读取从设备寄存器中的保持寄存器值。 #### 安装依赖库 确保已经安装了适用于 MicroPythonModbus 库。可以通过如下方式获取: ```bash pip install git+https://gitcode.com/gh_mirrors/mi/micropython-modbus.git ``` 注意这一步通常是在计算机端完成,实际部署到 ESP32 上前需先将该库转换为适合上传的形式或直接在线下载至板子内[^1]。 #### 初始化 UART 和 Modbus 实例 创建一个新的脚本来初始化 UART 接口以及 Modbus 类对象: ```python from machine import Pin, UART import modbus_tk.modbus_rtu as mb_rtulib import time uart = UART(2, baudrate=9600, bits=8, parity=None, stop=1, tx=Pin(17), rx=Pin(16)) master = mb_rtulib.RtuMaster(uart) def read_holding_registers(slave_addr, start_reg, count): try: result = master.execute(slave_id=slave_addr, function_code=mb_rtulib.READ_HOLDING_REGISTERS, starting_address=start_reg, quantity_of_x=count) return result except Exception as e: print(f"Error occurred during reading registers: {e}") return None ``` 这段代码定义了一个名为 `read_holding_registers()` 函数,用来发送请求给指定地址 (slave_addr) 的从机,并尝试从中读取一定数量(count) 的保持寄存器(start_reg 开始)。 #### 测试读取数据 接下来编写一段测试程序去调用上述方法并打印返回的结果: ```python if __name__ == "__main__": slave_address = 1 # 假设目标从站地址为1 register_start = 0 # 寄存器起始位置 num_to_read = 10 # 需要读取的数量 while True: values = read_holding_registers(slave_address, register_start, num_to_read) if values is not None: print("Read Holding Registers:", list(values)) time.sleep_ms(500) # 每隔半秒查询一次 ``` 此部分实现了每隔一段时间就向特定地址发起读命令的功能,直到断开连接为止。如果成功接收到响应,则会将其内容输出到控制台;否则捕获异常并将错误信息记录下来以便调试。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值