You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PySerial读取RS232串口时,如何处理行首CRLF以获取完整响应?

串口读取实验室泵响应不完整问题

我通过USB转RS232串口适配器连接实验室泵,发送命令正常,但读取响应时无法获取完整内容。

发送命令

ser.write(b'ver\r\n') 

响应相关信息

泵应返回固件版本号,后跟代表状态的字符(停止:, 泵送>, 堵转*)。我使用以下PySerial代码读取响应:

time.sleep(1)
while True:
    line = ser.readline()
    print(line)

示波器监测的泵实际响应(解码后)

CR LF SP SP 1 1 . 0 6 2 CR LF CR LF :

Python脚本读取到的内容

b'\r\n'
b'  11.062\r\n'
b'\r\n'

显然末尾的冒号未被读取,因为它在CR LF字符之后。实际应该读取到的内容应为:

b'\r\n  11.062'
b'\r\n'
b'\r\n:'

疑问

是否可以让PySerial识别行首的EoL字符,或者在无EoL字符时仍继续读取串口?


完整测试脚本

import time
import serial
import traceback

print('Libraries imported')

# 配置串口连接
ser = serial.Serial(
    port='COM12',
    baudrate=9600,
    parity=serial.PARITY_NONE,
    stopbits=serial.STOPBITS_TWO,
    bytesize=serial.EIGHTBITS
)

ser.isOpen()

try:
    print('Querying...')
    # \r是CR(回车)字符
    # \n是LF(换行)字符
    # 'b'将其转为字节数组(serial.Serial.write()要求的参数类型)
    ser.write(b'ver\r\n') 

    time.sleep(1)
    while True:
        line = ser.readline()
        print(line)

except Exception:
    traceback.print_exc()

while True:
    entry = input("Press x to close terminal: ")
    if entry == 'x':
        break
    else:
        continue

解决方法

方法1:读取全部缓冲区内容后手动解析

放弃依赖readline()的默认行为,先读取串口缓冲区中所有可用字节,再根据响应结构手动拆分解析:

time.sleep(1)
# 读取当前缓冲区所有字节
full_response = ser.read(ser.in_waiting)
print("完整原始响应:", full_response)

# 手动拆分解析
# 提取版本号:找到两个空格后的内容,直到下一个CRLF
if b'  ' in full_response:
    version_segment = full_response.split(b'  ')[1].split(b'\r\n')[0]
    firmware_version = version_segment.decode('ascii')
    print(f"固件版本: {firmware_version}")

# 提取状态字符:响应的最后一个字节
status_char = full_response[-1:]
if status_char in b':>*':
    status = status_char.decode('ascii')
    print(f"泵状态: {status}")

方法2:逐字节读取直到超时

设置串口超时,逐字节读取所有数据,确保不会遗漏无EoL结尾的字符:

time.sleep(1)
ser.timeout = 0.5  # 设置0.5秒超时,无数据时停止读取
total_data = b''

while True:
    byte = ser.read()
    if not byte:
        break
    total_data += byte

print("完整响应:", total_data)
# 后续解析逻辑同方法1

方法3:自定义行拆分规则处理行首EoL

如果需要保持按行输出的形式,可以先读取全部数据,再重新组织行结构,把行首的EoL和后续内容合并:

time.sleep(1)
raw_data = ser.read(ser.in_waiting)
# 按CRLF拆分原始数据
raw_lines = raw_data.split(b'\r\n')

processed_lines = []
prev_is_empty = False
for line in raw_lines:
    if prev_is_empty and line:
        # 上一行是空行(CRLF),当前行有内容,合并为一行
        processed_lines.append(b'\r\n' + line)
        prev_is_empty = False
    elif not line:
        processed_lines.append(b'\r\n')
        prev_is_empty = True
    else:
        processed_lines.append(line)

# 输出处理后的行
for line in processed_lines:
    print(line)

内容的提问来源于stack exchange,提问作者cringle

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 07:20:03