PyQt5 QtSerialPort读取Hex串口数据出现拆分问题求助
解决QtSerialPort串口Hex数据接收拆分问题
问题原因
串口通信属于流式传输,readyRead信号触发仅代表当前有数据可读,但不一定是完整的一帧数据。你遇到的拆分是串口传输的正常现象,必须通过数据缓存和帧解析逻辑来处理。
解决方案
核心思路是维护全局接收缓冲区,每次收到数据就追加到缓冲区,再按照协议规则(比如固定帧长度)从缓冲区中提取完整帧进行判断。以下是修改后的完整代码:
from PyQt5 import QtCore, QtWidgets, QtSerialPort class Widget(QtWidgets.QWidget): def __init__(self, parent=None): super(Widget, self).__init__(parent) self.send1_btn = QtWidgets.QPushButton( text="Send1", clicked=self.send1 ) self.send2_btn = QtWidgets.QPushButton( text="Send2", clicked=self.send2 ) self.send3_btn = QtWidgets.QPushButton( text="Send3", clicked=self.send3 ) lay = QtWidgets.QVBoxLayout(self) hlay = QtWidgets.QHBoxLayout() hlay.addWidget(self.send1_btn) hlay.addWidget(self.send2_btn) hlay.addWidget(self.send3_btn) lay.addLayout(hlay) self.serial = QtSerialPort.QSerialPort('/dev/ttyUSB0', baudRate=QtSerialPort.QSerialPort.Baud57600, parity=QtSerialPort.QSerialPort.NoParity, dataBits=QtSerialPort.QSerialPort.Data8, stopBits=QtSerialPort.QSerialPort.OneStop) self.serial.open(QtCore.QIODevice.ReadWrite) self.serial.setDataTerminalReady(True) self.serial.readyRead.connect(self.handle_ready_Read) # 初始化全局接收缓冲区 self.recv_buffer = b'' # 定义目标完整帧 self.target_frame = b'\xaa\x02\x3c\x31\x19' # 固定帧长度 self.frame_length = len(self.target_frame) QtCore.pyqtSlot() def handle_ready_Read(self): # 读取当前所有可用数据,追加到缓冲区 new_data = self.serial.readAll() self.recv_buffer += new_data.data() # 循环检查缓冲区中是否有完整帧 while len(self.recv_buffer) >= self.frame_length: # 提取缓冲区前N字节作为当前帧 current_frame = self.recv_buffer[:self.frame_length] print(f"当前解析帧: {current_frame}") if current_frame == self.target_frame: print("Ok") else: print("Error") # 移除已处理的帧,保留剩余未处理数据 self.recv_buffer = self.recv_buffer[self.frame_length:] @QtCore.pyqtSlot() def send1(self): # Reset,out service self.serial.write(b'\xCC\x02\x3C\x55\x5F') # Syncro self.serial.write(b'\xCC\x02\x3C\x24\x2E') # Setup self.serial.write(b'\xCC\x04\x3C\x23\x00\x10\x3F') # Enable self.serial.write(b'\xCC\x02\x3C\x12\x1C') @QtCore.pyqtSlot() def send2(self): # value self.serial.write(b'\xCC\x04\x3C\x34\x00\x05\x45') self.step1=1 @QtCore.pyqtSlot() def send3(self): # Confirm Ok self.serial.write(b'\xCC\x02\x3C\x22\x2C') if __name__ == '__main__': import sys app = QtWidgets.QApplication(sys.argv) w = Widget() w.show() sys.exit(app.exec_())
关键修改点
- 添加
self.recv_buffer全局缓冲区,存储所有未处理的串口数据 - 每次收到新数据后,将其追加到缓冲区,避免数据丢失
- 循环检查缓冲区长度是否达标,提取完整帧进行判断,处理后移除已解析的部分
- 修正原代码中判断条件的错误(原代码错误使用
b'xAAxO2x3Cx31x19 ',正确Hex表示应为b'\xaa\x02\x3c\x31\x19')
扩展说明
如果你的通信协议有更复杂的规则(比如起始标志+长度字段+校验位),可以调整解析逻辑:
- 先在缓冲区中定位起始标志(如
0xaa) - 根据协议中的长度字段确定后续需要读取的字节数
- 等待缓冲区数据足够后,提取完整帧并进行校验
内容的提问来源于stack exchange,提问作者Eric
相关产品推荐
相关产品推荐

