串口调试助手 v1.2 功能支持RS232/485通信、HEX收发、自动检测端口、数据记录 开发环境Python 3.8 Tkinter pyserial import tkinter as tk from tkinter import ttk, scrolledtext, messagebox, filedialog import serial import serial.tools.list_ports from threading import Thread, Event import time class SerialDebugger: def __init__(self, master): self.master master self.serial_port None self.receive_thread None self.stop_event Event() self.init_ui() self.auto_detect_ports() def init_ui(self): 初始化用户界面 self.master.title(嵌入式串口调试助手) self.master.geometry(800x600) # 主布局框架 main_frame ttk.Frame(self.master) main_frame.pack(filltk.BOTH, expandTrue) # 串口配置区域 config_frame ttk.LabelFrame(main_frame, text串口配置) config_frame.pack(filltk.X, padx5, pady5) # 端口选择 ttk.Label(config_frame, text端口:).grid(row0, column0, padx5) self.port_combo ttk.Combobox(config_frame, width15) self.port_combo.grid(row0, column1, padx5) ttk.Button(config_frame, text刷新端口, commandself.auto_detect_ports).grid(row0, column2, padx5) # 参数配置 params [ (波特率, [9600, 115200, 57600, 38400, 19200]), (数据位, [8, 7, 6, 5]), (校验位, [无, 奇校验, 偶校验]), (停止位, [1, 1.5, 2]) ] for idx, (text, values) in enumerate(params, start1): ttk.Label(config_frame, textf{text}:).grid(rowidx, column0, padx5) combo ttk.Combobox(config_frame, valuesvalues, width8) combo.set(values[0]) combo.grid(rowidx, column1, padx5) setattr(self, fcombo_{text}, combo) # 操作按钮 self.btn_connect ttk.Button(config_frame, text打开串口, commandself.toggle_connection) self.btn_connect.grid(row4, column2, rowspan3, padx10, pady5) # 接收显示区域 recv_frame ttk.LabelFrame(main_frame, text接收数据) recv_frame.pack(filltk.BOTH, expandTrue, padx5, pady5) self.recv_text scrolledtext.ScrolledText(recv_frame, wraptk.WORD) self.recv_text.pack(filltk.BOTH, expandTrue) # 发送控制区域 send_frame ttk.Frame(main_frame) send_frame.pack(filltk.X, padx5, pady5) self.send_entry ttk.Entry(send_frame) self.send_entry.pack(sidetk.LEFT, filltk.X, expandTrue, padx5) self.hex_send tk.BooleanVar() ttk.Checkbutton(send_frame, textHEX发送, variableself.hex_send).pack(sidetk.LEFT) ttk.Button(send_frame, text发送, commandself.send_data).pack(sidetk.RIGHT, padx5) # 状态栏 self.status_var tk.StringVar() status_bar ttk.Label(main_frame, textvariableself.status_var, relieftk.SUNKEN) status_bar.pack(sidetk.BOTTOM, filltk.X) def auto_detect_ports(self): 自动检测可用串口 ports [port.device for port in serial.tools.list_ports.comports()] self.port_combo[values] ports if ports: self.port_combo.current(0) self.update_status(f检测到{len(ports)}个可用串口) def toggle_connection(self): 切换串口连接状态 if self.serial_port and self.serial_port.is_open: self.close_serial() else: self.open_serial() def open_serial(self): 打开串口 try: self.serial_port serial.Serial( portself.port_combo.get(), baudrateint(self.combo_波特率.get()), bytesizeint(self.combo_数据位.get()), parityself.get_parity(), stopbitsself.get_stopbits(), timeout0.1 ) self.btn_connect.config(text关闭串口) self.start_receive_thread() self.update_status(f已连接 {self.port_combo.get()}) except Exception as e: messagebox.showerror(连接错误, f无法打开串口:\n{str(e)}) def get_parity(self): 获取校验位配置 parity_map { 无: serial.PARITY_NONE, 奇校验: serial.PARITY_ODD, 偶校验: serial.PARITY_EVEN } return parity_map[self.combo_校验位.get()] def get_stopbits(self): 获取停止位配置 stopbits_map { 1: serial.STOPBITS_ONE, 1.5: serial.STOPBITS_ONE_POINT_FIVE, 2: serial.STOPBITS_TWO } return stopbits_map[self.combo_停止位.get()] def start_receive_thread(self): 启动数据接收线程 self.stop_event.clear() self.receive_thread Thread(targetself.receive_data, daemonTrue) self.receive_thread.start() def receive_data(self): 接收数据线程 while not self.stop_event.is_set() and self.serial_port.is_open: try: if self.serial_port.in_waiting 0: data self.serial_port.read(self.serial_port.in_waiting) self.display_data(data) except Exception as e: self.update_status(f接收错误: {str(e)}) break def display_data(self, data): 显示接收数据 text data.hex( ) if self.hex_send.get() else data.decode(utf-8, replace) self.recv_text.insert(tk.END, text) self.recv_text.see(tk.END) self.update_status(f接收字节数: {len(data)}) def send_data(self): 发送数据 if not self.serial_port or not self.serial_port.is_open: messagebox.showwarning(警告, 请先打开串口连接) return data self.send_entry.get() try: if self.hex_send.get(): data bytes.fromhex(data.replace( , )) else: data data.encode(utf-8) self.serial_port.write(data) self.update_status(f发送字节数: {len(data)}) except ValueError: messagebox.showerror(格式错误, HEX数据格式不正确) except Exception as e: messagebox.showerror(发送错误, str(e)) def close_serial(self): 关闭串口连接 self.stop_event.set() if self.serial_port and self.serial_port.is_open: self.serial_port.close() self.btn_connect.config(text打开串口) self.update_status(串口已关闭) def update_status(self, message): 更新状态栏 self.status_var.set(f状态: {message}) def on_closing(self): 窗口关闭事件处理 self.close_serial() self.master.destroy() if __name__ __main__: root tk.Tk() app SerialDebugger(root) root.protocol(WM_DELETE_WINDOW, app.on_closing) root.mainloop()