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()
问题分析
- checksum发送格式错误:PySerial的
serial.write()方法要求传入字节类对象(如bytes、bytearray),但代码中直接传入整数类型的checksum。当整数超出0-255范围时(比如文件读完后sum(blockData)=0,checksum=256),会被截断为0x00发送,导致Arduino端接收异常。 - 未处理文件读取完毕的情况:当文件内容读取完成后,
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
相关产品推荐
相关产品推荐

