增加串口测试工具

This commit is contained in:
hold the blade 2025-11-19 23:31:16 +08:00
parent 964095b486
commit 6d456431af
3 changed files with 250 additions and 48 deletions

235
SerialTool/SerialTool.py Normal file
View File

@ -0,0 +1,235 @@
import tkinter as tk
from tkinter import ttk
import serial
import serial.tools.list_ports
import threading
import time
from datetime import datetime
class SerialApp:
def __init__(self, root):
self.root = root
self.root.title("串口通信工具")
self.root.geometry("800x600")
# 串口相关变量
self.serial_port = None
self.is_connected = False
self.read_thread = None
self.stop_thread = False
self.create_widgets()
self.refresh_ports()
def create_widgets(self):
# 主框架
main_frame = ttk.Frame(self.root, padding="10")
main_frame.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S))
# 配置行权重
self.root.columnconfigure(0, weight=1)
self.root.rowconfigure(0, weight=1)
main_frame.columnconfigure(1, weight=1)
# 串口配置区域
config_frame = ttk.LabelFrame(main_frame, text="串口配置", padding="5")
config_frame.grid(row=0, column=0, columnspan=2, sticky=(tk.W, tk.E), pady=(0, 10))
config_frame.columnconfigure(1, weight=1)
# 串口选择
ttk.Label(config_frame, text="串口:").grid(row=0, column=0, sticky=tk.W, padx=(0, 5))
self.port_combo = ttk.Combobox(config_frame, state="readonly")
self.port_combo.grid(row=0, column=1, sticky=(tk.W, tk.E), padx=(0, 10))
# 刷新按钮
self.refresh_btn = ttk.Button(config_frame, text="刷新", command=self.refresh_ports)
self.refresh_btn.grid(row=0, column=2, padx=(0, 10))
# 波特率选择
ttk.Label(config_frame, text="波特率:").grid(row=0, column=3, sticky=tk.W, padx=(0, 5))
self.baud_combo = ttk.Combobox(config_frame, values=[
"9600", "19200", "38400", "57600", "115200", "230400", "460800", "921600"
], state="readonly")
self.baud_combo.set("115200")
self.baud_combo.grid(row=0, column=4, sticky=(tk.W, tk.E))
# 连接/断开按钮
self.connect_btn = ttk.Button(config_frame, text="打开串口", command=self.toggle_connection)
self.connect_btn.grid(row=0, column=5, padx=(10, 0))
# 数据显示区域
display_frame = ttk.LabelFrame(main_frame, text="接收数据", padding="5")
display_frame.grid(row=1, column=0, columnspan=2, sticky=(tk.W, tk.E, tk.N, tk.S), pady=(0, 10))
main_frame.rowconfigure(1, weight=1)
display_frame.columnconfigure(0, weight=1)
display_frame.rowconfigure(0, weight=1)
# 文本框和滚动条
self.text_frame = ttk.Frame(display_frame)
self.text_frame.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S))
self.text_frame.columnconfigure(0, weight=1)
self.text_frame.rowconfigure(0, weight=1)
self.text_area = tk.Text(self.text_frame, wrap=tk.WORD, width=80, height=20)
scrollbar = ttk.Scrollbar(self.text_frame, orient=tk.VERTICAL, command=self.text_area.yview)
self.text_area.configure(yscrollcommand=scrollbar.set)
self.text_area.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S))
scrollbar.grid(row=0, column=1, sticky=(tk.N, tk.S))
# 状态栏
self.status_var = tk.StringVar(value="就绪")
status_bar = ttk.Label(main_frame, textvariable=self.status_var, relief=tk.SUNKEN)
status_bar.grid(row=2, column=0, columnspan=2, sticky=(tk.W, tk.E))
def refresh_ports(self):
"""刷新可用串口列表"""
ports = serial.tools.list_ports.comports()
port_list = [port.device for port in ports]
self.port_combo['values'] = port_list
if port_list:
self.port_combo.set(port_list[0])
def toggle_connection(self):
"""打开或关闭串口连接"""
if not self.is_connected:
self.connect_serial()
else:
self.disconnect_serial()
def connect_serial(self):
"""打开串口连接"""
port = self.port_combo.get()
baudrate = self.baud_combo.get()
if not port:
self.status_var.set("错误: 请选择串口")
return
try:
self.serial_port = serial.Serial(
port=port,
baudrate=int(baudrate),
bytesize=serial.EIGHTBITS,
parity=serial.PARITY_NONE,
stopbits=serial.STOPBITS_ONE,
timeout=1
)
self.is_connected = True
self.stop_thread = False
self.connect_btn.config(text="关闭串口")
self.status_var.set(f"已连接到 {port},波特率 {baudrate}")
# 启动读取线程
self.read_thread = threading.Thread(target=self.read_serial_data, daemon=True)
self.read_thread.start()
except Exception as e:
self.status_var.set(f"连接错误: {str(e)}")
def disconnect_serial(self):
"""关闭串口连接"""
self.stop_thread = True
self.is_connected = False
if self.serial_port and self.serial_port.is_open:
self.serial_port.close()
self.connect_btn.config(text="打开串口")
self.status_var.set("串口已关闭")
def read_serial_data(self):
"""在单独的线程中读取串口数据"""
buffer = bytearray()
while not self.stop_thread and self.serial_port and self.serial_port.is_open:
try:
if self.serial_port.in_waiting > 0:
data = self.serial_port.read(self.serial_port.in_waiting)
buffer.extend(data)
# 处理缓冲区中的数据
while len(buffer) >= 2:
# 检查是否是 0x03 0x01 命令
if buffer[0] == 0x03 and buffer[1] == 0x01 and len(buffer) <= 4:
self.handle_0301_command(buffer[:2])
buffer = buffer[2:]
# 检查是否是 0x03 0x03 命令
elif buffer[0] == 0x03 and buffer[1] == 0x03 and len(buffer) <= 4:
self.handle_0303_command(buffer[:2])
buffer = buffer[2:]
else:
# 如果不是我们处理的命令,显示并丢弃第一个字节
self.display_data(buffer[:1], "RX")
buffer = buffer[1:]
time.sleep(0.01)
except Exception as e:
self.root.after(0, lambda: self.status_var.set(f"读取错误: {str(e)}"))
break
def handle_0301_command(self, data):
"""处理 0x03 0x01 命令"""
# 显示接收到的数据
self.display_data(data, "RX")
# 发送回复 0x03 0x01 0xAA 0xAA
response = bytes([0x03, 0x01, 0xAA, 0xAA])
self.send_data(response)
def handle_0303_command(self, data):
"""处理 0x03 0x03 命令"""
# 显示接收到的数据
self.display_data(data, "RX")
# 发送回复 0x03 0x03 0x05 0x01 0x01 0x01 0x01 0x01 0xAA 0xAA
response = bytes([0x03, 0x03, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, 0xAA, 0xAA])
self.send_data(response)
def send_data(self, data):
"""发送数据到串口"""
if self.serial_port and self.serial_port.is_open:
try:
self.serial_port.write(data)
self.display_data(data, "TX")
except Exception as e:
self.root.after(0, lambda: self.status_var.set(f"发送错误: {str(e)}"))
def display_data(self, data, direction):
"""在文本框中显示数据"""
timestamp = datetime.now().strftime("%H:%M:%S.%f")[:-3]
hex_str = ' '.join([f'{byte:02X}' for byte in data])
display_text = f"[{timestamp}] {direction}: {hex_str}\n"
# 在主线程中更新GUI
self.root.after(0, lambda: self.update_text_display(display_text))
def update_text_display(self, text):
"""更新文本框显示"""
self.text_area.insert(tk.END, text)
self.text_area.see(tk.END)
def __del__(self):
"""析构函数,确保串口关闭"""
if hasattr(self, 'serial_port') and self.serial_port and self.serial_port.is_open:
self.serial_port.close()
def main():
root = tk.Tk()
app = SerialApp(root)
# 处理窗口关闭事件
def on_closing():
app.disconnect_serial()
root.destroy()
root.protocol("WM_DELETE_WINDOW", on_closing)
root.mainloop()
if __name__ == "__main__":
main()

View File

@ -1,33 +0,0 @@
[PreviousLibFiles]
LibFiles=Drivers\STM32F1xx_HAL_Driver\Inc\stm32f1xx_hal_tim.h;Drivers\STM32F1xx_HAL_Driver\Inc\stm32f1xx_ll_tim.h;Drivers\STM32F1xx_HAL_Driver\Inc\stm32f1xx_hal_tim_ex.h;Drivers\STM32F1xx_HAL_Driver\Inc\Legacy\stm32_hal_legacy.h;Drivers\STM32F1xx_HAL_Driver\Inc\stm32f1xx_hal.h;Drivers\STM32F1xx_HAL_Driver\Inc\stm32f1xx_hal_def.h;Drivers\STM32F1xx_HAL_Driver\Inc\stm32f1xx_hal_rcc.h;Drivers\STM32F1xx_HAL_Driver\Inc\stm32f1xx_hal_rcc_ex.h;Drivers\STM32F1xx_HAL_Driver\Inc\stm32f1xx_ll_bus.h;Drivers\STM32F1xx_HAL_Driver\Inc\stm32f1xx_ll_rcc.h;Drivers\STM32F1xx_HAL_Driver\Inc\stm32f1xx_ll_system.h;Drivers\STM32F1xx_HAL_Driver\Inc\stm32f1xx_ll_utils.h;Drivers\STM32F1xx_HAL_Driver\Inc\stm32f1xx_hal_gpio.h;Drivers\STM32F1xx_HAL_Driver\Inc\stm32f1xx_hal_gpio_ex.h;Drivers\STM32F1xx_HAL_Driver\Src\stm32f1xx_hal_gpio_ex.c;Drivers\STM32F1xx_HAL_Driver\Inc\stm32f1xx_ll_gpio.h;Drivers\STM32F1xx_HAL_Driver\Inc\stm32f1xx_hal_dma_ex.h;Drivers\STM32F1xx_HAL_Driver\Inc\stm32f1xx_hal_dma.h;Drivers\STM32F1xx_HAL_Driver\Inc\stm32f1xx_ll_dma.h;Drivers\STM32F1xx_HAL_Driver\Inc\stm32f1xx_hal_cortex.h;Drivers\STM32F1xx_HAL_Driver\Inc\stm32f1xx_ll_cortex.h;Drivers\STM32F1xx_HAL_Driver\Inc\stm32f1xx_hal_pwr.h;Drivers\STM32F1xx_HAL_Driver\Inc\stm32f1xx_ll_pwr.h;Drivers\STM32F1xx_HAL_Driver\Inc\stm32f1xx_hal_flash.h;Drivers\STM32F1xx_HAL_Driver\Inc\stm32f1xx_hal_flash_ex.h;Drivers\STM32F1xx_HAL_Driver\Inc\stm32f1xx_hal_exti.h;Drivers\STM32F1xx_HAL_Driver\Inc\stm32f1xx_ll_exti.h;Drivers\STM32F1xx_HAL_Driver\Inc\stm32f1xx_hal_uart.h;Drivers\STM32F1xx_HAL_Driver\Inc\stm32f1xx_ll_usart.h;Drivers\STM32F1xx_HAL_Driver\Src\stm32f1xx_hal_tim.c;Drivers\STM32F1xx_HAL_Driver\Src\stm32f1xx_hal_tim_ex.c;Drivers\STM32F1xx_HAL_Driver\Src\stm32f1xx_hal.c;Drivers\STM32F1xx_HAL_Driver\Src\stm32f1xx_hal_rcc.c;Drivers\STM32F1xx_HAL_Driver\Src\stm32f1xx_hal_rcc_ex.c;Drivers\STM32F1xx_HAL_Driver\Src\stm32f1xx_hal_gpio.c;Drivers\STM32F1xx_HAL_Driver\Src\stm32f1xx_hal_dma.c;Drivers\STM32F1xx_HAL_Driver\Src\stm32f1xx_hal_cortex.c;Drivers\STM32F1xx_HAL_Driver\Src\stm32f1xx_hal_pwr.c;Drivers\STM32F1xx_HAL_Driver\Src\stm32f1xx_hal_flash.c;Drivers\STM32F1xx_HAL_Driver\Src\stm32f1xx_hal_flash_ex.c;Drivers\STM32F1xx_HAL_Driver\Src\stm32f1xx_hal_exti.c;Drivers\STM32F1xx_HAL_Driver\Src\stm32f1xx_hal_uart.c;Drivers\STM32F1xx_HAL_Driver\Inc\stm32f1xx_hal_tim.h;Drivers\STM32F1xx_HAL_Driver\Inc\stm32f1xx_ll_tim.h;Drivers\STM32F1xx_HAL_Driver\Inc\stm32f1xx_hal_tim_ex.h;Drivers\STM32F1xx_HAL_Driver\Inc\Legacy\stm32_hal_legacy.h;Drivers\STM32F1xx_HAL_Driver\Inc\stm32f1xx_hal.h;Drivers\STM32F1xx_HAL_Driver\Inc\stm32f1xx_hal_def.h;Drivers\STM32F1xx_HAL_Driver\Inc\stm32f1xx_hal_rcc.h;Drivers\STM32F1xx_HAL_Driver\Inc\stm32f1xx_hal_rcc_ex.h;Drivers\STM32F1xx_HAL_Driver\Inc\stm32f1xx_ll_bus.h;Drivers\STM32F1xx_HAL_Driver\Inc\stm32f1xx_ll_rcc.h;Drivers\STM32F1xx_HAL_Driver\Inc\stm32f1xx_ll_system.h;Drivers\STM32F1xx_HAL_Driver\Inc\stm32f1xx_ll_utils.h;Drivers\STM32F1xx_HAL_Driver\Inc\stm32f1xx_hal_gpio.h;Drivers\STM32F1xx_HAL_Driver\Inc\stm32f1xx_hal_gpio_ex.h;Drivers\STM32F1xx_HAL_Driver\Src\stm32f1xx_hal_gpio_ex.c;Drivers\STM32F1xx_HAL_Driver\Inc\stm32f1xx_ll_gpio.h;Drivers\STM32F1xx_HAL_Driver\Inc\stm32f1xx_hal_dma_ex.h;Drivers\STM32F1xx_HAL_Driver\Inc\stm32f1xx_hal_dma.h;Drivers\STM32F1xx_HAL_Driver\Inc\stm32f1xx_ll_dma.h;Drivers\STM32F1xx_HAL_Driver\Inc\stm32f1xx_hal_cortex.h;Drivers\STM32F1xx_HAL_Driver\Inc\stm32f1xx_ll_cortex.h;Drivers\STM32F1xx_HAL_Driver\Inc\stm32f1xx_hal_pwr.h;Drivers\STM32F1xx_HAL_Driver\Inc\stm32f1xx_ll_pwr.h;Drivers\STM32F1xx_HAL_Driver\Inc\stm32f1xx_hal_flash.h;Drivers\STM32F1xx_HAL_Driver\Inc\stm32f1xx_hal_flash_ex.h;Drivers\STM32F1xx_HAL_Driver\Inc\stm32f1xx_hal_exti.h;Drivers\STM32F1xx_HAL_Driver\Inc\stm32f1xx_ll_exti.h;Drivers\STM32F1xx_HAL_Driver\Inc\stm32f1xx_hal_uart.h;Drivers\STM32F1xx_HAL_Driver\Inc\stm32f1xx_ll_usart.h;Drivers\CMSIS\Device\ST\STM32F1xx\Include\stm32f103xb.h;Drivers\CMSIS\Device\ST\STM32F1xx\Include\stm32f1xx.h;Drivers\CMSIS\Device\ST\STM32F1xx\Include\system_stm32f1xx.h;Drivers\CMSIS\Device\ST\STM32F1xx\Include\system_stm32f1xx.h;Drivers\CMSIS\Device\ST\STM32F1xx\Source\Templates\system_stm32f1xx.c;Drivers\CMSIS\Include\cmsis_armcc.h;Drivers\CMSIS\Include\cmsis_armclang.h;Drivers\CMSIS\Include\cmsis_compiler.h;Drivers\CMSIS\Include\cmsis_gcc.h;Drivers\CMSIS\Include\cmsis_iccarm.h;Drivers\CMSIS\Include\cmsis_version.h;Drivers\CMSIS\Include\core_armv8mbl.h;Drivers\CMSIS\Include\core_armv8mml.h;Drivers\CMSIS\Include\core_cm0.h;Drivers\CMSIS\Include\core_cm0plus.h;Drivers\CMSIS\Include\core_cm1.h;Drivers\CMSIS\Include\core_cm23.h;Drivers\CMSIS\Include\core_cm3.h;Drivers\CMSIS\Include\core_cm33.h;Drivers\CMSIS\Include\core_cm4.h;Drivers\CMSIS\Include\core_cm7.h;Drivers\CMSIS\Include\core_sc000.h;Drivers\CMSIS\Include\core_sc300.h;Drivers\CMSIS\Include\mpu_armv7.h;Drivers\CMSIS\Include\mpu_armv8.h;Drivers\CMSIS\Include\tz_context.h;
[PreviousUsedKeilFiles]
SourceFiles=..\Core\Src\main.c;..\Core\Src\gpio.c;..\Core\Src\dma.c;..\Core\Src\tim.c;..\Core\Src\usart.c;..\Core\Src\stm32f1xx_it.c;..\Core\Src\stm32f1xx_hal_msp.c;..\Drivers\STM32F1xx_HAL_Driver\Src\stm32f1xx_hal_gpio_ex.c;..\Drivers\STM32F1xx_HAL_Driver\Src\stm32f1xx_hal_tim.c;..\Drivers\STM32F1xx_HAL_Driver\Src\stm32f1xx_hal_tim_ex.c;..\Drivers\STM32F1xx_HAL_Driver\Src\stm32f1xx_hal.c;..\Drivers\STM32F1xx_HAL_Driver\Src\stm32f1xx_hal_rcc.c;..\Drivers\STM32F1xx_HAL_Driver\Src\stm32f1xx_hal_rcc_ex.c;..\Drivers\STM32F1xx_HAL_Driver\Src\stm32f1xx_hal_gpio.c;..\Drivers\STM32F1xx_HAL_Driver\Src\stm32f1xx_hal_dma.c;..\Drivers\STM32F1xx_HAL_Driver\Src\stm32f1xx_hal_cortex.c;..\Drivers\STM32F1xx_HAL_Driver\Src\stm32f1xx_hal_pwr.c;..\Drivers\STM32F1xx_HAL_Driver\Src\stm32f1xx_hal_flash.c;..\Drivers\STM32F1xx_HAL_Driver\Src\stm32f1xx_hal_flash_ex.c;..\Drivers\STM32F1xx_HAL_Driver\Src\stm32f1xx_hal_exti.c;..\Drivers\STM32F1xx_HAL_Driver\Src\stm32f1xx_hal_uart.c;..\Drivers\CMSIS\Device\ST\STM32F1xx\Source\Templates\system_stm32f1xx.c;..\Core\Src\system_stm32f1xx.c;..\Drivers\STM32F1xx_HAL_Driver\Src\stm32f1xx_hal_gpio_ex.c;..\Drivers\STM32F1xx_HAL_Driver\Src\stm32f1xx_hal_tim.c;..\Drivers\STM32F1xx_HAL_Driver\Src\stm32f1xx_hal_tim_ex.c;..\Drivers\STM32F1xx_HAL_Driver\Src\stm32f1xx_hal.c;..\Drivers\STM32F1xx_HAL_Driver\Src\stm32f1xx_hal_rcc.c;..\Drivers\STM32F1xx_HAL_Driver\Src\stm32f1xx_hal_rcc_ex.c;..\Drivers\STM32F1xx_HAL_Driver\Src\stm32f1xx_hal_gpio.c;..\Drivers\STM32F1xx_HAL_Driver\Src\stm32f1xx_hal_dma.c;..\Drivers\STM32F1xx_HAL_Driver\Src\stm32f1xx_hal_cortex.c;..\Drivers\STM32F1xx_HAL_Driver\Src\stm32f1xx_hal_pwr.c;..\Drivers\STM32F1xx_HAL_Driver\Src\stm32f1xx_hal_flash.c;..\Drivers\STM32F1xx_HAL_Driver\Src\stm32f1xx_hal_flash_ex.c;..\Drivers\STM32F1xx_HAL_Driver\Src\stm32f1xx_hal_exti.c;..\Drivers\STM32F1xx_HAL_Driver\Src\stm32f1xx_hal_uart.c;..\Drivers\CMSIS\Device\ST\STM32F1xx\Source\Templates\system_stm32f1xx.c;..\Core\Src\system_stm32f1xx.c;;;
HeaderPath=..\Drivers\STM32F1xx_HAL_Driver\Inc;..\Drivers\STM32F1xx_HAL_Driver\Inc\Legacy;..\Drivers\CMSIS\Device\ST\STM32F1xx\Include;..\Drivers\CMSIS\Include;..\Core\Inc;
CDefines=USE_HAL_DRIVER;STM32F103xB;USE_HAL_DRIVER;USE_HAL_DRIVER;
[PreviousGenFiles]
AdvancedFolderStructure=true
HeaderFileListSize=7
HeaderFiles#0=..\Core\Inc\gpio.h
HeaderFiles#1=..\Core\Inc\dma.h
HeaderFiles#2=..\Core\Inc\tim.h
HeaderFiles#3=..\Core\Inc\usart.h
HeaderFiles#4=..\Core\Inc\stm32f1xx_it.h
HeaderFiles#5=..\Core\Inc\stm32f1xx_hal_conf.h
HeaderFiles#6=..\Core\Inc\main.h
HeaderFolderListSize=1
HeaderPath#0=..\Core\Inc
HeaderFiles=;
SourceFileListSize=7
SourceFiles#0=..\Core\Src\gpio.c
SourceFiles#1=..\Core\Src\dma.c
SourceFiles#2=..\Core\Src\tim.c
SourceFiles#3=..\Core\Src\usart.c
SourceFiles#4=..\Core\Src\stm32f1xx_it.c
SourceFiles#5=..\Core\Src\stm32f1xx_hal_msp.c
SourceFiles#6=..\Core\Src\main.c
SourceFolderListSize=1
SourcePath#0=..\Core\Src
SourceFiles=;

File diff suppressed because one or more lines are too long