Python读取Arduino串口控制GUI换页触发OSError(9)错误如何解决
报错原因
- 串口句柄无效:每次页面跳转时你都调用了
ser.close()关闭串口,但跳转回对应页面后没有重新执行串口初始化打开逻辑,后续访问ser.in_waiting时操作的是已失效的串口句柄,直接触发OSError 9报错。 - 页面跳转逻辑错误:Python的
import语句仅会在第一次导入模块时执行模块顶层代码,后续重复导入page1/page2不会重新运行串口读取的while循环,跳转逻辑本身就无法正常复用。 - 串口读取逻辑错误:代码中连续调用两次
ser.read(),第一次读取到的字节直接被丢弃,既会导致数据丢失,也可能引发串口缓冲读取异常。
解决方案
不要用销毁窗口+导入模块的方式实现页面跳转,调整整体架构后即可解决问题,具体修改点如下:
- 统一管理串口资源:全局仅初始化打开一次串口,程序运行全程保持串口打开状态,仅在程序完全退出时调用
ser.close()释放资源,避免反复开关串口产生句柄错误。 - 重构页面跳转逻辑:使用GUI框架自带的页面切换能力(如tkinter的Frame显隐切换),不要销毁重建窗口,也不要用import实现跳转。
- 修正串口读取逻辑:移除冗余的
ser.read()调用,同时用GUI框架的定时器轮询串口,避免while死循环阻塞GUI线程。
可参考修改后的示例代码(以tkinter为例)
import serial import tkinter as tk # 全局仅初始化一次串口,根据实际情况修改串口号、波特率 ser = serial.Serial('COM3', 9600, timeout=1) # 初始化主窗口 root = tk.Tk() root.title("串口控制页面") root.geometry("300x200") # 创建两个页面对象 page1 = tk.Frame(root) page2 = tk.Frame(root) # 页面1布局 tk.Label(page1, text="第一页", font=("微软雅黑", 20)).pack(pady=50) page1.pack(fill="both", expand=True) # 页面2布局 tk.Label(page2, text="第二页", font=("微软雅黑", 20)).pack(pady=50) page2.pack(fill="both", expand=True) # 全局串口轮询逻辑 def serial_poll(): if ser.in_waiting: recv_data = ser.read().decode() print(f"收到串口数据:{recv_data}") if recv_data == '1': # 切换到第二页 page2.lift() elif recv_data == '5': # 切换回第一页 page1.lift() # 每100ms轮询一次串口 root.after(100, serial_poll) # 启动串口轮询 serial_poll() # 初始显示第一页 page1.lift() # 启动GUI主循环 root.mainloop() # 程序退出时关闭串口 ser.close()
注意事项
- 不要在GUI主线程中用
while True死循环执行逻辑,会直接阻塞GUI刷新导致程序无响应。 - 多页面GUI场景下,公共资源(如串口、数据库连接等)要统一管理,避免反复创建销毁产生异常。
内容的提问来源于stack exchange,提问作者alex
相关产品推荐
相关产品推荐

