使用pyserial与Tkinter向Raspberry Pico串口发数据无响应问题
串口通信故障排查:Python(Tkinter)与Raspberry Pico数据传输失败
我正在编写一个Python程序,通过pyserial模块结合Tkinter图形界面向Raspberry Pico发送数据,但按下按钮后Pico未接收到数据。程序GUI正常打开且可点击按钮,但始终看不到回传数据。
原Python代码
import serial import time import tkinter as tk def activate_serial(): with serial.Serial('COM12', 9600, timeout=1) as ser: while ser.in_waiting>0: out = ser.readline() print(out) time.sleep(0.5) def send_data(): serial.Serial('COM12', 9600, timeout=1).write(bytes(str(1)+'\n','utf-8')) gui = tk.Tk() label_no = tk.Label(text="Entry") send = tk.Button(text="Send Command", command=send_data()) input_mod = tk.Entry() label_no.pack() input_mod.pack() send.pack() gui.after(500,activate_serial) gui.mainloop()
Pico端Arduino代码
void setup() { Serial.begin(9600); } void loop() { if (Serial.available()>0) { int dataIn = Serial.parseInt(); Serial.readString(); digitalWrite(LED_BUILTIN, HIGH); delay(100); digitalWrite(LED_BUILTIN, LOW); Serial.println(dataIn); } }
问题根源与修复方案
1. 按钮命令绑定错误
原代码中send = tk.Button(text="Send Command", command=send_data())直接调用了send_data()函数,导致程序启动时就执行一次发送,而点击按钮时不会触发。正确写法是绑定函数引用,不带括号:
send = tk.Button(text="Send Command", command=send_data)
2. 重复创建串口对象导致资源冲突
send_data()每次创建新的Serial对象,发送后未关闭,会导致串口端口被占用,同时和activate_serial()的串口实例冲突。应全局维护一个串口连接,避免重复创建。
3. 串口监听逻辑阻塞事件循环且仅执行一次
activate_serial()中的with语句会在函数结束时关闭串口,导致后续无法监听数据。time.sleep(0.5)会阻塞Tkinter事件循环,导致界面卡顿且无法及时响应新数据。gui.after(500,activate_serial)仅调用一次监听函数,无法持续读取串口回传数据。
修复后的Python代码
import serial import tkinter as tk # 全局串口对象 ser = None def init_serial(): global ser try: ser = serial.Serial('COM12', 9600, timeout=1) print("串口连接成功") # 启动持续监听 listen_serial() except Exception as e: print(f"串口连接失败: {e}") def listen_serial(): global ser if ser and ser.is_open: # 非阻塞读取所有可用数据 while ser.in_waiting > 0: out = ser.readline().decode('utf-8').strip() if out: print(f"收到回传数据: {out}") # 每隔100ms再次监听,避免阻塞事件循环 gui.after(100, listen_serial) def send_data(): global ser if ser and ser.is_open: # 发送数据,确保换行符正确 ser.write(b"1\n") print("已发送数据: 1") else: print("串口未连接,无法发送数据") gui = tk.Tk() gui.title("Pico串口控制") label_no = tk.Label(text="Entry") send = tk.Button(text="Send Command", command=send_data) input_mod = tk.Entry() label_no.pack(pady=5) input_mod.pack(pady=5) send.pack(pady=10) # 初始化串口 gui.after(500, init_serial) gui.mainloop() # 程序结束时关闭串口 if ser and ser.is_open: ser.close()
Pico端代码优化(可选)
原代码中Serial.readString()可能读取到空内容,可改为读取剩余的换行符,避免影响后续数据读取:
void setup() { Serial.begin(9600); pinMode(LED_BUILTIN, OUTPUT); } void loop() { if (Serial.available() > 0) { int dataIn = Serial.parseInt(); // 清除缓冲区剩余的换行符 while (Serial.available() > 0 && Serial.peek() == '\n') { Serial.read(); } digitalWrite(LED_BUILTIN, HIGH); delay(100); digitalWrite(LED_BUILTIN, LOW); Serial.println(dataIn); } }
内容的提问来源于stack exchange,提问作者Nate
相关产品推荐
相关产品推荐

