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 # 无输出(已缓存)