优化代码

This commit is contained in:
2025-10-17 15:36:54 +08:00
parent 452aaaeaba
commit e3167a0144
2 changed files with 37 additions and 75 deletions

View File

@@ -91,61 +91,6 @@ class RS485Manager:
crc >>= 1
return crc
@staticmethod
def _parse_modbus_rtu_float_default(response_bytes):
"""
默认解析 Modbus RTU 响应中的 32 位 IEEE 754 单精度浮点数。
假定为大端 (ABCD) 字节序。
"""
# 最小预期长度: 从站ID(1) + 功能码(1) + 字节计数(1) + 4字节数据 + CRC(2) = 9字节
min_response_len = 9
expected_data_byte_count = 4 # 32位浮点数占用4字节
if not response_bytes or len(response_bytes) < min_response_len:
log(f"警告: 响应字节过短或为空,无法解析为浮点数。响应: {response_bytes.hex() if response_bytes else 'None'}")
return None
# 提取响应组件
# 注意: Modbus RTU CRC是LSB在前所以这里需要调整
# response_bytes[:-2] 是用于CRC计算的数据部分
# response_bytes[-2:] 是CRC本身
data_for_crc = response_bytes[:-2]
received_crc = (response_bytes[-1] << 8) | response_bytes[-2] # CRC的低字节在前高字节在后
# 1. CRC 校验
calculated_crc = RS485Manager._calculate_crc16_modbus(data_for_crc)
if calculated_crc != received_crc:
log(f"错误: CRC校验失败。接收CRC: {received_crc:04X}, 计算CRC: {calculated_crc:04X}. 响应: {response_bytes.hex()}")
return None
function_code = response_bytes[1]
byte_count = response_bytes[2]
data_bytes = response_bytes[3:3 + expected_data_byte_count]
# 2. 功能码检查 (假设读取保持寄存器0x03或输入寄存器0x04)
if function_code not in [0x03, 0x04]:
log(f"警告: 响应功能码 {function_code:02X} 不符合预期 (期望0x03或0x04)。响应: {response_bytes.hex()}")
return None
# 3. 字节计数检查
if byte_count != expected_data_byte_count:
log(f"警告: 响应字节计数 {byte_count} 不符合预期 (期望{expected_data_byte_count})。响应: {response_bytes.hex()}")
return None
# 4. 提取的数据字节长度检查 (与字节计数检查有重叠,但更安全)
if len(data_bytes) != expected_data_byte_count:
log(f"错误: 提取的数据字节长度不正确。期望{expected_data_byte_count}, 实际{len(data_bytes)}. 响应: {response_bytes.hex()}")
return None
# 5. 转换为浮点数 (大端, ABCD)
try:
parsed_float = struct.unpack('>f', data_bytes)[0]
log(f"成功解析浮点数: {parsed_float}")
return parsed_float
except Exception as e:
log(f"错误: 浮点数转换失败: {e}. 数据字节: {data_bytes.hex()}. 响应: {response_bytes.hex()}")
return None
def execute_raw_command(self, bus_id, command):
"""
【契约】执行一个“发后不理”的原始指令。
@@ -203,8 +148,9 @@ class RS485Manager:
bus_id = command_info.get("bus_number")
command_bytes = command_info.get("command_bytes")
if bus_id is None or command_bytes is None:
log("错误: Raw485Command 缺少 'bus_number''command_bytes' 字段。")
# 增加对命令有效性的检查
if bus_id is None or not command_bytes or len(command_bytes) < 2:
log(f"错误: CollectTask 的 'command' 字段无效。bus_id: {bus_id}, command_bytes: {command_bytes}")
return None
except Exception as e:
@@ -220,46 +166,54 @@ class RS485Manager:
rts_pin = port_info['rts_pin']
lock = port_info['lock']
response_buffer = bytearray() # 改:用缓冲累积
response_bytes = None # 在锁外部初始化,确保其作用域
response_buffer = bytearray()
with lock:
try:
# II. 线程安全与指令发送
rts_pin.value(1) # 设置为发送模式 (DE/RE = HIGH)
time.sleep_us(100) # 短暂延时,确保方向切换完成
rts_pin.value(1)
time.sleep_us(100)
uart.write(command_bytes)
uart.flush()
time.sleep_us(100) # 短暂延时,确保数据完全发出
rts_pin.value(0) # 切换回接收模式 (DE/RE = LOW)
time.sleep_us(100)
rts_pin.value(0)
log(f"总线 {bus_id} 原始命令发送成功: {command_bytes.hex()}")
# III. 接收响应(修复:超时循环 + 小块读)
# III. 接收响应
start_time = time.ticks_ms()
response_timeout = self.default_timeouts.get('rs485_response', 500)
while time.ticks_diff(time.ticks_ms(), start_time) < response_timeout:
if uart.any():
chunk = uart.read(32) # 小块读
chunk = uart.read(32)
if chunk:
response_buffer.extend(chunk)
start_time = time.ticks_ms() # 重置超时
start_time = time.ticks_ms() # 收到数据就重置超时
time.sleep_ms(5)
if response_buffer:
# 新增:搜索有效帧,跳前缀
response_bytes = self._find_modbus_frame(response_buffer, bus_id, 4)
if response_bytes:
log(f"总线 {bus_id} 收到有效响应: {response_bytes.hex()}")
# 动态地从请求命令中获取预期的从站ID和功能码
expected_slave_id = command_bytes[0]
expected_func_code = command_bytes[1]
found_frame = self._find_modbus_frame(response_buffer, expected_slave_id, expected_func_code)
if found_frame:
log(f"总线 {bus_id} 收到有效响应: {found_frame.hex()}")
response_bytes = found_frame # 将找到的帧赋值给外部变量
else:
log(f"警告: 总线 {bus_id} 响应中无有效帧。收到响应: {response_buffer.hex()}")
return None
else:
log(f"警告: 总线 {bus_id} 未收到响应。")
except Exception as e:
log(f"错误: 在总线 {bus_id} 上执行采集命令失败: {e}")
return None
# IV. 统一处理和解析
# 无论是因为超时、未找到有效帧还是发生异常,只要 response_bytes 仍为 None就任务失败
if response_bytes is None:
return None
# IV. 解析(用修复版)
parsed_value = RS485Manager._parse_modbus_rtu_default(response_bytes) # 改名,支持动态
# 使用找到的有效帧进行解析
parsed_value = RS485Manager._parse_modbus_rtu_default(response_bytes)
return parsed_value

View File

@@ -49,10 +49,18 @@ class Processor:
# 根据指令类型,分发到不同的业务处理方法
if 'raw_485_command' in instruction:
self._process_exec_command(instruction['raw_485_command'])
cmd = instruction['raw_485_command']
if cmd:
self._process_exec_command(cmd)
else:
log("警告:'raw_485_command' 指令内容为空。")
elif 'batch_collect_command' in instruction:
self._process_collect_command(instruction['batch_collect_command'])
cmd = instruction['batch_collect_command']
if cmd:
self._process_collect_command(cmd)
else:
log("警告:'batch_collect_command' 指令内容为空。")
else:
log(f"警告:收到未知或不适用于此设备的指令类型: {instruction}")