使用Pyserial发送多条指令时引导后后续指令未被设备接收如何解决
核心问题定位
- 串口会话被反复重置:代码在遍历每条指令的循环里,每次都执行了
ser.close()+ser.open(),串口每次重开都会断开和设备的现有连接,引导阶段完成后重开串口相当于重新建立连接,之前的引导会话状态直接丢失,设备自然不会响应后续在新会话里发的指令。 - 指令缺少结束符:绝大多数串口设备都要求指令末尾携带换行符(
\n/\r/\r\n)才会判定为一条完整的可执行指令,Putty默认会在你敲回车的时候自动补全结束符,所以手动操作正常,而原代码里直接发送指令内容,没有额外追加设备要求的结束符,设备会认为指令未结束,一直等待后续输入。 - 计时逻辑错误:变量
x初始值为0,第一次进入循环时time.perf_counter() - x会直接远大于设置的等待时间,导致指令刚发送就跳出等待逻辑,还没等设备返回就清空了缓冲区。 - 写超时配置不合理:初始化串口时设置了
write_timeout=0,部分场景下会导致写入操作直接非阻塞返回,实际上数据还没完全写入串口缓冲区就被后续操作打断。
修复后的代码示例
import serial import time from datetime import datetime # 加载指令列表 with open('commands.txt') as f: list_of_commands = [tuple(map(str.strip, i.split(','))) for i in f] # 初始化日志 date = datetime.now().strftime("%Y-%m-%d") log = open(f'{date}.txt', 'w+', encoding='utf-8') # 加载串口配置 with open('info.txt', 'r') as f: lines = f.readlines() port = lines[0].strip() baud = int(lines[1].strip()) ser = None try: # 串口仅初始化打开一次 ser = serial.Serial( port=port, baudrate=baud, timeout=2, parity=serial.PARITY_NONE, stopbits=serial.STOPBITS_ONE, # 关闭write_timeout=0的配置,使用默认阻塞写入 write_timeout=5 ) # 等待串口初始化完成 time.sleep(2) except ConnectionError: log.write('串口连接失败') else: for cmd_item in list_of_commands: sleep_time = int(cmd_item[0]) cmd = cmd_item[1] # 追加设备要求的结束符,这里如果是CR就改成\r,CRLF就改成\r\n encoded_cmd = (cmd + '\n').encode("utf-8") # 发送指令 ser.write(encoded_cmd) # 确保数据完全发出 ser.flush() # 等待设备返回 wait_start = time.perf_counter() while time.perf_counter() - wait_start < sleep_time: if ser.in_waiting: recv_data = ser.readline() recv_text = recv_data.decode('utf-8', errors='ignore') print(recv_text) log.write(recv_text) log.flush() # 仅清空输入缓冲区,不要清空输出缓冲区避免未发出的数据被丢弃 ser.reset_input_buffer() print(f"完成指令发送: {cmd}") finally: if ser and ser.is_open: ser.close() log.close()
额外注意事项
- 先确认设备要求的指令结束符类型,常见的有
\n(LF)、\r(CR)、\r\n(CRLF)三种,需要和设备要求保持一致 - 如果是工业类串口设备,建议额外开启流控配置(如果设备支持的话),或者将发送后等待flush的时间延长到0.1~0.5秒
- 不要在指令执行过程中随意关闭、重开串口,会直接丢失当前会话的所有状态,导致设备回到初始等待引导的状态
内容的提问来源于stack exchange,提问作者dtrinh
相关产品推荐
相关产品推荐

