串口输入缓冲区历史数据干扰问题 python的解决方案,非常简单
加上这行代码就行self.serial.reset_input_buffer()
下面详细介绍
问题分析
接收数据包含历史残留的原因是:串口接收缓冲区中未及时清理的历史数据与新响应混合。Modbus RTU 协议基于时序传输,若在发送新指令前未清空缓冲区,会导致残留数据被误读。
解决方案
在发送新命令前清空串口输入缓冲区,确保只读取当前命令的响应。
修改代码步骤
-
在发送命令前清空输入缓冲区:
在general_send_and_rec_modbus_06
方法的发送逻辑前添加self.serial.reset_input_buffer()
。
python
def general_send_and_rec_modbus_06(self, device_address,register_addr,value,function_code=0x06):"""组合命令生成与发送的整合方法"""try:# ... [参数校验和命令构造部分保持不变] ...# ========== 发送部分 ==========if not hasattr(self, 'serial') or not self.serial.is_open:messagebox.showwarning("警告", "请先打开串口")return# 清空输入缓冲区,避免历史数据干扰self.serial.reset_input_buffer()# 发送当前命令self.serial.write(message)# ... [后续格式化显示和接收逻辑保持不变] ...self.receive_data() # 调用接收方法except Exception as e:messagebox.showerror("错误", f"操作失败: {str(e)}")
-
优化接收逻辑(可选):
Modbus RTU 的响应长度与功能码相关,例如:-
功能码 0x03(读寄存器):响应长度 = 5 + 2*寄存器数量(字节)。
-
功能码 0x06(写单个寄存器):固定响应长度 8 字节(包含 CRC)。
可改进
receive_data
方法,根据功能码动态判断数据完整性: -
python
def receive_data(self):self.serial.timeout = 1 # 设置超时时间received_data = b""start_time = time.time()while True:# 超时退出循环if time.time() - start_time > self.serial.timeout:break# 读取当前缓冲区所有数据new_data = self.serial.read(self.serial.in_waiting or 1)if new_data:received_data += new_data# 根据Modbus协议判断数据完整性(示例以功能码0x03和0x06为例)if len(received_data) >= 2:function_code = received_data[1]if function_code == 0x03:# 检查数据长度:地址(1) + 功能码(1) + 字节数(1) + 数据(2*N) + CRC(2)byte_count = received_data[2]expected_length = 5 + byte_countif len(received_data) >= expected_length:breakelif function_code == 0x06:# 固定长度:地址(1) + 功能码(1) + 寄存器地址(2) + 数据(2) + CRC(2) = 8字节if len(received_data) >= 8:break# 显示接收数据if received_data:hex_data = ' '.join(f"{b:02X}" for b in received_data)self.receive_text.insert(tk.INSERT, f"接收的数据: {hex_data}\n")else:self.receive_text.insert(tk.INSERT, "接收回复报文: 无数据接收\n")