pySerialTransfer双向通信异常:Python无法正确读取Arduino返回值
Python与Arduino双向串口通信不稳定问题排查
我编写了一个极简的Python与Arduino双向串口通信脚本:Python向Arduino发送整数,Arduino将该整数自增后通过串口返回。但运行时Python无法稳定读取自增后的正确值,仅能每隔多次尝试才读取到一次正确结果。以下是相关代码及控制台日志:
代码与日志
comm.py
from time import sleep from pySerialTransfer import pySerialTransfer as txfer class struct: control = 0 class receivestruct: status = 0 if __name__ == '__main__': try: testStruct = struct rstruct =receivestruct link = txfer.SerialTransfer('COM7') link.open() sleep(2) counter = 0 while True: sendSize = 0 testStruct.control = counter sendSize = link.tx_obj(testStruct.control, start_pos=sendSize) link.send(sendSize) print('sent') #sleep(0.5) read_correctly = False while (read_correctly == False): try: if not (link.available()): pass recSize = 0 # this section returns errors with can't read str as int rstruct.status = link.rx_obj(obj_type='i', start_pos=recSize) counter = rstruct.status recSize += txfer.STRUCT_FORMAT_LENGTHS['i'] print(rstruct.status) read_correctly = True except: pass except KeyboardInterrupt: link.close()
arduino.ino
#include "SerialTransfer.h" SerialTransfer myTransfer; uint32_t rcontrol; uint32_t control; void setup() { Serial.begin(115200); myTransfer.begin(Serial); } void loop() { if(myTransfer.available()) { // use this variable to keep track of how many // bytes we've processed from the receive buffer uint16_t recSize = 0; recSize = myTransfer.rxObj(rcontrol, recSize); control = rcontrol + 1; uint16_t sendSize = 0; sendSize = myTransfer.txObj(control, sendSize); myTransfer.sendData(sendSize); } }
控制台日志
115 sent 115 sent 116 sent 116 sent 116 sent 116 sent 116 sent 116 sent 116 sent 116 sent 116 sent 117 sent 117 sent 117 sent 117 sent 117 sent 117 sent 117 sent 117 sent 117 sent 118 sent 118 sent 118 sent 118 sent 118 sent 118 sent 118 sent 118 sent 118 sent 119 sent 119 sent 119 sent 119 sent 119 sent 119 sent 119 sent 119 sent
问题原因分析
- 数据类型不匹配:Python端使用
obj_type='i'(对应有符号32位int),但Arduino端定义的是uint32_t(无符号32位整数),类型不匹配会导致数据解析错误,出现无法读取或读取值异常的情况。 - 无等待强制读取:Python发送数据后未等待Arduino处理并返回,立刻进入读取循环。串口通信存在延迟,此时缓存中可能没有新数据或残留旧数据,直接读取会触发异常,而宽泛的
except: pass会跳过错误,导致重复读取旧缓存值。 - 异常处理过于宽泛:捕获所有异常且不做任何处理,掩盖了数据解析失败、串口读取异常等真实问题,无法及时排查错误根源。
- 未清空错误缓存:当读取出现异常时,未清空串口接收缓存,残留的错误数据会被后续循环重复读取,导致多次返回旧值。
修正方案
修正后的comm.py
from time import sleep from pySerialTransfer import pySerialTransfer as txfer if __name__ == '__main__': try: link = txfer.SerialTransfer('COM7') link.open() sleep(2) counter = 0 while True: # 发送无符号32位整数,与Arduino端类型匹配 send_size = link.tx_obj(counter, obj_type='I') link.send(send_size) print(f'sent: {counter}') # 等待Arduino返回数据,避免读空或旧缓存 while not link.available(): sleep(0.01) # 读取数据并处理可能的异常 try: rec_size = 0 received_val = link.rx_obj(obj_type='I', start_pos=rec_size) counter = received_val print(f'received: {received_val}') except Exception as e: print(f'读取错误: {e}') link.clear() # 清空缓存,避免残留错误数据 except KeyboardInterrupt: link.close()
修正后的arduino.ino
#include "SerialTransfer.h" SerialTransfer myTransfer; uint32_t rcontrol; uint32_t control; void setup() { Serial.begin(115200); myTransfer.begin(Serial); } void loop() { if(myTransfer.available()) { uint16_t recSize = 0; recSize = myTransfer.rxObj(rcontrol, recSize); control = rcontrol + 1; uint16_t sendSize = 0; sendSize = myTransfer.txObj(control, sendSize); myTransfer.sendData(sendSize); // 等待数据发送完成,避免截断 while(myTransfer.bytesSent() < sendSize) {} } }
内容的提问来源于stack exchange,提问作者itisyeetimetoday
相关产品推荐
相关产品推荐

