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

Arduino Uno与Windows PC串口通信出现意外字符的原因及解决方法

Arduino Uno与Windows PC串口通信出现意外字符问题

问题概述

Arduino Uno通过RS-232转TTL适配器连接Windows PC,使用Python发送ASCII数据,Arduino回传时出现非ASCII错误字符(0xFE/0xFF),且错误字符数量与输入中的空格数一致。实际需求是通过Arduino向TEOM控制单元发送[STX][数据][ETX]格式命令,额外字节会导致通信失败。树莓派运行相同逻辑代码可正常通信,但Arduino Uno无法正常工作。

代码片段

Python代码

import serial
import time

port = 'COM3'  # 替换为实际串口
baud_rate = 9600

try:
    with serial.Serial(port, baud_rate, timeout=1) as ser:
        data = 'TEST as you go test and test again\r\n'
        encoded_data = data.encode('ascii')
        ser.write(encoded_data)
        time.sleep(1)
        response = ser.read_all()
        response = response.decode('ascii')
        print("Response:", response)

except serial.SerialException as e:
    print("Error opening serial port:", e)

Arduino代码

#include <SoftwareSerial.h>

SoftwareSerial SIM900(2, 3);

void setup() {
  SIM900.begin(9600);
  Serial.begin(9600);
  Serial.println("Enter command");
}

void loop() {
  if (Serial.available()) {
    String command = Serial.readStringUntil('\n');
    Serial.println("C: " + command);
    sendCommand(command);
  }

  if (SIM900.available()) {
    String response = SIM900.readStringUntil('\n');
    Serial.println("Response: " + response);
    SIM900.flush();
    SIM900.print(response);
  }
}

void sendCommand(String command) {
  const char STX = '\x02';
  const char ETX = '\x03';

  SIM900.print(STX);
  SIM900.print(command);
  SIM900.print(ETX);
  SIM900.println();
}

报错信息

UnicodeDecodeError                        Traceback (most recent call last)

     14         time.sleep(1)
     15         response = ser.read_all()
---&gt; 16         response = response.decode('ascii')
     17         print("Response:", response)
     19 except serial.SerialException as e:

UnicodeDecodeError: 'ascii' codec can't decode byte 0xfe in position 0: ordinal not in range(128)

补充测试中未指定编码解码时的报错:

UnicodeDecodeError: 'utf-8' codec can't decode byte 0xff in position 0: invalid start byte

打印原始字节示例:

b'\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xffTEST as you go test and test again\r\r\n'

已尝试的解决方法

  • 在Arduino中调用serial.flush(),无改善
  • Python发送数据后调用ser.reset_input_buffer(),无变化
  • 切换Python解码编码为latin1或utf-8,结果更差
  • 对比字节值,确认意外字符出现在响应开头

关键现象

  • 意外字符(0xFE/0xFF)的数量与输入中的空格数完全一致
  • 发送无空格的单个单词(如Test)时,无意外字符
  • 树莓派运行相同逻辑代码可正常通信

软件版本

  • Python 3.9.12
  • Arduino IDE 2.0.3(CLI版本0.29.0)

问题原因分析

  1. 串口引脚接反:SoftwareSerial的RX和TX引脚与RS-232转TTL适配器的接线接反,导致电平反转,接收数据时将空格字符错误识别为0xFE/0xFF。
  2. 代码逻辑错误:Arduino代码中错误监听硬件串口(Serial)的输入,而非用于连接PC的软串口(SIM900),导致数据流向混乱,回传时产生错误字节。
  3. SoftwareSerial局限性:Arduino Uno的SoftwareSerial库在9600波特率下可靠性较低,易受中断影响,导致数据读取错误。

解决方案

1. 修正硬件接线

确保RS-232转TTL适配器的TX引脚连接到Arduino软串口的RX引脚(代码中SoftwareSerial SIM900(2,3)的第一个参数是RX,即引脚2),适配器的RX引脚连接到Arduino软串口的TX引脚(引脚3),绝对不能接反。

2. 修正Arduino代码逻辑

调整代码,让软串口负责接收PC的命令并回传,硬件串口仅用于调试:

#include <SoftwareSerial.h>

// 软串口连接PC:RX=2,TX=3
SoftwareSerial PC_Serial(2, 3);

void setup() {
  PC_Serial.begin(9600);
  Serial.begin(9600); // 硬件串口用于调试输出
  Serial.println("Ready to receive commands");
}

void loop() {
  // 监听PC通过软串口发来的命令
  if (PC_Serial.available()) {
    String command = PC_Serial.readStringUntil('\n');
    Serial.println("Received from PC: " + command);
    
    // 包装为[STX][数据][ETX]格式(若连接TEOM,此处改为发送给TEOM串口)
    const char STX = '\x02';
    const char ETX = '\x03';
    PC_Serial.print(STX);
    PC_Serial.print(command);
    PC_Serial.print(ETX);
    PC_Serial.println();
  }

  // 若连接TEOM,添加监听TEOM响应并回传PC的逻辑
  // if (TEOM_Serial.available()) {
  //   String teom_response = TEOM_Serial.readStringUntil('\n');
  //   PC_Serial.println(teom_response);
  // }
}

3. 替换更可靠的软串口库

Arduino Uno的SoftwareSerial库存在可靠性问题,建议改用AltSoftSerial库(Uno上仅支持引脚8(TX)和9(RX)),它使用硬件定时器实现,抗干扰能力更强。

4. 优化Python代码

移除不必要的time.sleep(),改用latin1解码避免报错:

import serial

port = 'COM3'
baud_rate = 9600

try:
    with serial.Serial(port, baud_rate, timeout=2) as ser:
        ser.reset_input_buffer()  # 清空输入缓冲区
        data = 'TEST as you go test and test again\r\n'
        ser.write(data.encode('ascii'))
        
        response = ser.read_all()
        print("Raw response bytes:", response)
        # 使用latin1解码所有字节,避免Unicode错误
        response_str = response.decode('latin1')
        print("Decoded response:", response_str)

except serial.SerialException as e:
    print("Serial port error:", e)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 06:22:06