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

PySerial写STM32串口:Mac/Linux不遵守波特率,Windows正常

STM32 USB串口设备在MacOS/Linux下PySerial写入超速导致超时问题

设备厂商将核心板从Teensy更换为STM32后,原有的PySerial文件上传代码仅在Windows下正常运行,MacOS和Linux环境中数据写入速度远超设定的波特率(直接以文件读取速度写入),导致设备无法接收完整数据并触发写入超时。

目前通过在非Windows系统中添加time.sleep(0.000087)字节间延迟作为临时方案,但效果不稳定:多数情况可行,但偶尔仍会触发设备读取超时,疑似存在数据损坏问题。


简化后的Python 3代码

import serial
import os
import time

# 假设getHumanReadableSize是已实现的工具函数
def getHumanReadableSize(size):
    for unit in ['B', 'KB', 'MB']:
        if size < 1024:
            return f"{size:.2f}{unit}"
        size /= 1024
    return f"{size:.2f}GB"

_SERIAL_SETTINGS = {'baudrate': 115200, 
                    'bytesize': 8, 
                    'parity': 'N', 
                    'stopbits': 1, 
                    'xonxoff': False, 
                    'dsrdtr': False, 
                    'rtscts': False, 
                    'timeout': 3, 
                    'write_timeout': None, 
                    'inter_byte_timeout': None}

# port已根据系统提前识别
ser = serial.Serial(port)
ser.applySettings(_SERIAL_SETTINGS)

# file和file_size已从外部传入
bytes_sent = 0
fname = os.path.basename(file)
report_every_n_bytes = 512

with open(file, mode='rb') as binary_file:
    # 发送文件接收命令:格式为 "WR=filename,size\n"
    cmd = b'WR=' + fname.encode('utf-8') + b', ' + str(file_size).encode('utf-8') + b'\n'
    ser.write(cmd)
    response = ser.readline()  # 设备应返回 "OK Write filename, size\n"
    
    byte = binary_file.read(1)
    print(f'{fname} - Data sent: {getHumanReadableSize(bytes_sent)} - Data remaining: {getHumanReadableSize(file_size - bytes_sent)} - Speed: 0.00B/s', end='', flush=True)
    start_time = time.time()
    
    while byte:
        ser.write(byte)
        ser.flush()
        # 临时 workaround:非Windows系统手动添加延迟
        # if platform.system() != 'Windows': time.sleep(0.000087)
        bytes_sent += 1
        byte = binary_file.read(1)
        
        if bytes_sent % report_every_n_bytes == 0:
            elapsed = time.time() - start_time
            speed = bytes_sent / elapsed if elapsed > 0 else 0
            print(f'\r{fname} - Data sent: {getHumanReadableSize(bytes_sent)} - Data remaining: {getHumanReadableSize(file_size - bytes_sent)} - Speed: {getHumanReadableSize(speed)}/s   ', end='', flush=True)

    # 最终进度报告
    elapsed = time.time() - start_time
    speed = bytes_sent / elapsed if elapsed > 0 else 0
    print(f'\r{fname} - Data sent: {getHumanReadableSize(bytes_sent)} - Data remaining: {getHumanReadableSize(file_size - bytes_sent)} - Speed: {getHumanReadableSize(speed)}/s           ')
    
    # 检查设备响应,预期为“OK, Write complete.”,实际收到“ERROR Write Timed Out”
    response = ser.readline()
    print(response)

已尝试的无效方案

  • 降低波特率
  • 分块写入(替代单字节写入)
  • 单独或组合启用各类流控设置(xonxoff、dsrdtr、rtscts)
  • 修改奇偶校验和停止位参数

补充细节

  • 设备通过USB连接至PCB端口
  • 写入操作完成后执行ser.readline()时,收到设备返回的“ERROR Write Timed Out”错误
  • 根据设备文档,该错误触发条件:收到WR命令后,未接收到指定大小的数据,且10秒内无新数据传入
  • 问题可稳定复现,仅操作系统不同时出现差异,多台同条件机器均会发生

疑问

  1. 代码或配置中遗漏了什么关键点?
  2. 若问题与底层设备驱动有关,具体机制是什么?该如何解决?

内容的提问来源于stack exchange,提问作者Jason Ramboz

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 04:07:11