pySerial解码报错:utf-8无法解码0xff字节,求解决方案
问题分析与解决方案
问题现象
Arduino输出格式如下的文本数据:
3.30x530.00x2.59x1325.0x28.70x1013.14x0.91x23.41 3.50x531.00x2.60x1327.5x28.70x1013.11x1.17x23.41 3.60x531.00x2.60x1327.5x28.70x1013.14x0.89x23.41
Python程序读取时前1-2次正常运行,随后报错:'utf-8' codec can't decode byte 0xff in position 1: invalid start byte,报错行:
arduino_data = arduino_data[0:len(arduino_data)].decode("utf-8")
核心原因
- 串口缓冲区残留脏数据:每次调用函数都打开/关闭串口,Arduino重启或串口连接不稳定时,缓冲区会残留二进制乱码(比如0xff这类非UTF-8字节)。
- 解码无容错机制:直接用UTF-8解码未过滤的串口数据,遇到非标准字符直接抛出异常。
- 变量未初始化:代码中
list_in_floats和list_values未在函数内定义,会导致运行时错误。 - 频繁启停串口:反复打开/关闭串口会导致Arduino端的串口握手不稳定,输出异常数据。
解决方案
1. 增加解码容错,过滤无效字节
修改解码逻辑,忽略无法解码的字节,同时过滤空行和非打印字符:
# 替换原解码行 arduino_data = arduino_data.decode("utf-8", errors="ignore").strip()
2. 初始化串口时清空缓冲区
打开串口后等待Arduino完成初始化,再清空输入输出缓冲区,避免残留旧数据:
arduino = serial.Serial('COM3', 9600, timeout=1) time.sleep(2) # 给Arduino重启预留时间 arduino.flushInput() arduino.flushOutput()
3. 避免频繁打开/关闭串口
将串口初始化移到函数外部,只执行一次,函数内仅做读取操作:
import time import schedule import pandas as pd import serial # 全局初始化串口,仅执行一次 arduino = serial.Serial('COM3', 9600, timeout=1) time.sleep(2) arduino.flushInput() arduino.flushOutput() print('Established serial connection to Arduino') def main_func(): global arduino arduino_data = arduino.readline() # 解码并过滤无效数据 arduino_data = arduino_data.decode("utf-8", errors="ignore").strip() if not arduino_data: print("No valid data received") return list_values = arduino_data.split('x') list_in_floats = [] for item in list_values: try: list_in_floats.append(float(item)) except ValueError: # 跳过无法转换为浮点数的无效项 continue print(f'Collected readings from Arduino: {list_in_floats}') # 程序结束时统一关闭串口 def close_serial(): arduino.close() print('Connection closed') # 示例调度逻辑 schedule.every(10).seconds.do(main_func) try: while True: schedule.run_pending() time.sleep(1) except KeyboardInterrupt: close_serial()
4. 验证Arduino输出逻辑
确保Arduino使用Serial.println()输出纯文本(而非二进制数据),格式稳定:
// Arduino示例代码框架 void setup() { Serial.begin(9600); // 等待串口连接完成 while (!Serial) {} } void loop() { // 替换为实际传感器读数 float val1 = 3.30, val2 = 530.00, val3 = 2.59; // 按格式输出,末尾添加换行 Serial.print(val1, 2); Serial.print("x"); Serial.print(val2, 2); Serial.print("x"); Serial.print(val3, 2); // ... 输出剩余变量 Serial.println(); delay(1000); }
5. 增加数据校验(可选)
在Arduino输出时添加校验位,Python端验证数据完整性后再处理,比如在每行末尾添加简单的校验和,确保接收的数据未被篡改。
内容的提问来源于stack exchange,提问作者Emily Eberhardt
相关产品推荐
相关产品推荐

