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

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")

核心原因

  1. 串口缓冲区残留脏数据:每次调用函数都打开/关闭串口,Arduino重启或串口连接不稳定时,缓冲区会残留二进制乱码(比如0xff这类非UTF-8字节)。
  2. 解码无容错机制:直接用UTF-8解码未过滤的串口数据,遇到非标准字符直接抛出异常。
  3. 变量未初始化:代码中list_in_floats和list_values未在函数内定义,会导致运行时错误。
  4. 频繁启停串口:反复打开/关闭串口会导致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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 18:42:46