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

Mac向Arduino传输数据的Python代码故障排查求助

Python串口向Arduino批量发送数据块异常问题解决

问题描述

编写Python代码从Mac向Arduino传输数据以编程闪存设备,预期每次读取256字节块发送,但实际运行时反复发送0x00;改为单字节发送则正常。代码如下:

import serial, time, sys

try:
    dataFile = open(sys.argv[1], "rb")
except IOError:
    sys.exit("file cannot be opened")  
arduino = serial.Serial('/dev/cu.usbmodem2101', 19200, timeout=1)
time.sleep(1) # give the connection a second to settle
arduino.write(("WAKEUP").encode('ascii'))
if( arduino.readline() != ("ACK").encode('ascii') ):
    sys.exit("no initial ACK from programmer")  
print("received initial ACK")
for block in range(1, 131073): # 256Mb is 131072 x 256B blocks
    blockData = dataFile.read(256)
    checksum = 256 - (sum(blockData) % 256) # checksum when added to summed data should result in 0
    arduino.write(blockData) # send the data
    arduino.write(checksum) # send the checksum
    if( arduino.readline() != ("ACK").encode('ascii') ): # wait for the block to be processed
        sys.exit("Failed to complete data transfer")
    print("Block = " + str(block) + " sent succesfully" )
arduino.close()
dataFile.close()

问题分析

  1. checksum发送格式错误:PySerial的serial.write()方法要求传入字节类对象(如bytes、bytearray),但代码中直接传入整数类型的checksum。当整数超出0-255范围时(比如文件读完后sum(blockData)=0,checksum=256),会被截断为0x00发送,导致Arduino端接收异常。
  2. 未处理文件读取完毕的情况:当文件内容读取完成后,dataFile.read(256)会返回空的bytes对象,但循环仍会继续执行131072次,此时发送的是空数据块和错误的checksum,表现为反复发送0x00。

解决方案

1. 修正checksum发送方式

将整数类型的checksum转换为单字节的bytes对象,同时确保值在0-255范围内:

arduino.write(bytes([checksum % 256]))

2. 终止文件读取完成后的循环

在读取数据块后判断是否为空,为空则跳出循环,避免无效发送:

blockData = dataFile.read(256)
if not blockData:
    break  # 文件读取完毕,终止循环

完整修正后的代码

import serial, time, sys

try:
    dataFile = open(sys.argv[1], "rb")
except IOError:
    sys.exit("file cannot be opened")  

arduino = serial.Serial('/dev/cu.usbmodem2101', 19200, timeout=1)
time.sleep(1)  # 等待连接稳定
arduino.write(b"WAKEUP")  # 直接使用字节字面量更简洁

if arduino.readline() != b"ACK":
    sys.exit("no initial ACK from programmer")  
print("received initial ACK")

block_num = 1
while True:
    blockData = dataFile.read(256)
    if not blockData:
        break  # 文件读取完毕,退出循环
    
    checksum = 256 - (sum(blockData) % 256)
    checksum_byte = bytes([checksum % 256])  # 转换为单字节
    
    arduino.write(blockData)
    arduino.write(checksum_byte)
    
    if arduino.readline() != b"ACK":
        sys.exit("Failed to complete data transfer")
    print(f"Block = {block_num} sent successfully")
    block_num += 1

arduino.close()
dataFile.close()

额外优化建议

  • 使用b"WAKEUP"这类字节字面量替代字符串编码,代码更简洁高效
  • 改用while True循环替代固定次数的for循环,适配不同大小的文件
  • 增加checksum的范围校验,避免因计算值超出字节范围导致的异常

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 21:30:52