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
相关产品推荐
相关产品推荐

