为什么我再也不用 Qt 写上位机了?一个 12 MB、启动 1 秒、跑在树莓派上的 Python 调试工具诞生记
去年调试一款带多路 ADC+PWM 反馈的电机驱动板时,我第 7 次重启那个基于 Qt 写的上位机——它卡在串口重连时 UI 冻结,日志窗口堆满乱码,打包后体积 68 MB,客户产线工程师说:'你这工具比我们 PLC 还重。'
那一刻我决定:把上位机做回它本来的样子——一个听话的、不抢资源的、插上线就能干活的工具。
不是炫技,不是堆功能,而是回归本质:稳定收发、实时显示、不崩、不卡、不挑机器。
后来这个工具成了我们团队的标准调试伴侣:Windows 笔记本、MacBook Air、树莓派 4B,甚至一台旧的 Surface Go,装完 Python 环境,双击 debug_tool.pyw,1.3 秒内完成初始化,COM 端口自动识别,波形开始跳动。打包成单文件后仅 11.7 MB。
它是怎么做到的?下面我把整个设计过程摊开来讲——没有 PPT 式罗列,只有踩过的坑、调过的参、删掉的库,和最终留下的那不到 200 行真正干活的核心代码。
串口不能靠'等',得靠'问'和'守时'
很多开发者在使用串口通信时习惯采用阻塞式读取,这会导致主线程挂起,界面失去响应。为了解决这个问题,我们需要引入非阻塞机制。在 Python 中,通常结合 threading 库将串口监听放入后台线程,主线程仅负责 UI 渲染和数据更新。
import serial
import threading
import queue
class SerialWorker:
def __init__(self, port, baudrate=115200):
self.port = port
self.baudrate = baudrate
self.data_queue = queue.Queue()
self.serial_conn = None
self.thread = None
def start(self):
try:
self.serial_conn = serial.Serial(self.port, self.baudrate, timeout=1)
self.thread = threading.Thread(target=self._read_loop, daemon=True)
self.thread.start()
except Exception as e:
print(f"串口打开失败:")
():
:
.serial_conn .serial_conn.in_waiting > :
data = .serial_conn.readline().decode(, errors=)
.data_queue.put(data.strip())
:

