pySerial写入指令后readline返回写入内容,无法获取正确串口数据
pySerial串口通信readline返回发送指令的问题排查与解决
问题概述
使用pySerial进行串口通信时,readline()无法获取设备返回的正确数据,多数情况下读取到的是自身发送的指令(#001STA或001STA),仅偶尔出现异常结果。预期设备返回格式为:
#001,▒▒▒,25080,009,009,004,004,000,66,00700,069,042,0000000000000000000000000
代码问题分析
第一段代码存在的问题
- 端口配置错误:定义了
rereport = "COM16"但未赋值给ser.port,导致串口未正确指定通信端口。 - 流控设置矛盾:代码中
ser.xonxoff = True开启了软件流控,但注释标注为“disable”,若设备采用无流控配置,会导致通信不匹配。 - 指令格式可能缺失结束符:发送的指令
#001STA未添加设备要求的换行符(如\r\n),设备可能无法识别指令并返回数据。
第二段代码存在的问题
- 串口未打开:仅配置了端口参数,未调用
ser.open()就尝试发送数据,会直接抛出异常。 - 发送数据写法错误:
ser.write(wrData).encode("Ascii")逻辑错误,正确写法应为ser.write(wrData.encode("Ascii")),当前写法会导致发送原始字符串而非字节数据,引发通信异常。 - 无缓冲区初始化:未清空输入缓冲区,残留的历史数据会干扰读取结果。
解决建议
1. 修正串口初始化与配置
- 确保端口参数正确赋值:将第一段代码的
rereport = "COM16"改为ser.port = "COM16"。 - 串口打开前添加异常捕获,避免因端口占用等问题崩溃:
try: ser.open() except serial.SerialException as e: print(f"串口打开失败: {e}") exit() - 统一流控设置:根据设备手册确认流控模式,若为无流控,设置:
ser.xonxoff = False ser.rtscts = False ser.dsrdtr = False
2. 修正发送数据逻辑
- 发送数据前必须将字符串转为字节对象,第二段代码中修正为:
ser.write(wrData.encode("ASCII")) - 给指令添加设备要求的结束符(多数串口设备需要
\r或\r\n作为指令结束标志):wdata = "#001STA\r\n"
3. 规范缓冲区与读取逻辑
- 串口打开后清空一次缓冲区即可:
ser.flushInput() ser.flushOutput() - 读取数据前先检查输入缓冲区是否有数据,避免空读或超时读取残留数据:
ser.write(wdata.encode()) time.sleep(0.3) # 等待设备响应,时长根据设备调整 while ser.in_waiting > 0: response = ser.readline().decode().strip() # 跳过设备回显的指令(若设备存在回显) if response == wdata.strip(): continue print(f"设备返回: {response}")
4. 排查硬件与设备回显
- 检查串口接线是否正确,避免TX/RX短接导致的回环读取。
- 使用串口助手测试:发送指令后观察是否有回显,若设备默认回显发送的指令,读取时需跳过回显内容,再处理真正的返回数据。
修正后的示例代码
import time import serial # 串口配置 ser = serial.Serial() ser.port = "COM16" ser.baudrate = 9600 ser.bytesize = serial.EIGHTBITS ser.parity = serial.PARITY_NONE ser.stopbits = serial.STOPBITS_ONE ser.timeout = 1 ser.write_timeout = 0.5 # 匹配设备流控(此处为无流控) ser.xonxoff = False ser.rtscts = False ser.dsrdtr = False try: ser.open() except serial.SerialException as e: print(f"串口打开失败: {e}") exit() # 初始化缓冲区 ser.flushInput() ser.flushOutput() # 带结束符的指令 wdata = "#001STA\r\n" print("通信开始") try: while ser.is_open: # 发送指令 ser.write(wdata.encode()) # 等待设备响应 time.sleep(0.3) # 读取所有可用返回数据 while ser.in_waiting > 0: response = ser.readline().decode().strip() # 跳过回显的指令 if response == wdata.strip(): continue print(f"设备返回: {response}") # 间隔1秒再次发送 time.sleep(1) except KeyboardInterrupt: print("程序终止") finally: ser.close()
内容的提问来源于stack exchange,提问作者Ohguk Kwon
相关产品推荐
相关产品推荐

