Prechádzať zdrojové kódy

实现手动发送命令的串口助手

xuxinyi 1 mesiac pred
rodič
commit
dbeebfb63b
2 zmenil súbory, kde vykonal 87 pridanie a 39 odobranie
  1. 14 5
      .idea/workspace.xml
  2. 73 34
      main.py

+ 14 - 5
.idea/workspace.xml

@@ -4,7 +4,7 @@
     <option name="autoReloadType" value="SELECTIVE" />
   </component>
   <component name="ChangeListManager">
-    <list default="true" id="1ac4e985-6885-47ec-89fe-c34ac50172a1" name="更改" comment="first commit">
+    <list default="true" id="1ac4e985-6885-47ec-89fe-c34ac50172a1" name="更改" comment="初步实现串口助手">
       <change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
       <change beforePath="$PROJECT_DIR$/main.py" beforeDir="false" afterPath="$PROJECT_DIR$/main.py" afterDir="false" />
     </list>
@@ -55,7 +55,7 @@
       <option name="number" value="Default" />
       <option name="presentableId" value="Default" />
       <updated>1760066680854</updated>
-      <workItem from="1760066681868" duration="3456000" />
+      <workItem from="1760066681868" duration="3977000" />
     </task>
     <task id="LOCAL-00001" summary="first commit">
       <option name="closed" value="true" />
@@ -65,7 +65,15 @@
       <option name="project" value="LOCAL" />
       <updated>1760066983356</updated>
     </task>
-    <option name="localTasksCounter" value="2" />
+    <task id="LOCAL-00002" summary="初步实现串口助手">
+      <option name="closed" value="true" />
+      <created>1760076496354</created>
+      <option name="number" value="00002" />
+      <option name="presentableId" value="LOCAL-00002" />
+      <option name="project" value="LOCAL" />
+      <updated>1760076496354</updated>
+    </task>
+    <option name="localTasksCounter" value="3" />
     <servers />
   </component>
   <component name="TypeScriptGeneratedFilesManager">
@@ -84,9 +92,10 @@
   </component>
   <component name="VcsManagerConfiguration">
     <MESSAGE value="first commit" />
-    <option name="LAST_COMMIT_MESSAGE" value="first commit" />
+    <MESSAGE value="初步实现串口助手" />
+    <option name="LAST_COMMIT_MESSAGE" value="初步实现串口助手" />
   </component>
   <component name="com.intellij.coverage.CoverageDataManagerImpl">
-    <SUITE FILE_PATH="coverage/bl_lora_manager$main.coverage" NAME="main 覆盖结果" MODIFIED="1760076068896" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="false" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$" />
+    <SUITE FILE_PATH="coverage/bl_lora_manager$main.coverage" NAME="main 覆盖结果" MODIFIED="1760076627930" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="false" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$" />
   </component>
 </project>

+ 73 - 34
main.py

@@ -4,19 +4,19 @@ import threading
 import tkinter as tk
 from tkinter import ttk, scrolledtext, messagebox
 
+
 class SerialAssistant:
     def __init__(self, master):
         self.master = master
-        self.master.title("Python 串口助手 (青春版)")
-        self.master.geometry("700x450")
+        self.master.title("Python 帧格式串口助手")
+        self.master.geometry("800x550")
         self.master.resizable(False, False)
 
-        # 串口对象和状态
         self.ser = None
         self.is_running = False
-        self.hex_display = tk.BooleanVar(value=False)  # 是否以16进制显示
+        self.hex_display = tk.BooleanVar(value=True)
 
-        # 串口设置
+        # 串口设置
         frame_top = ttk.LabelFrame(master, text="串口设置", padding=10)
         frame_top.pack(fill="x")
 
@@ -44,12 +44,41 @@ class SerialAssistant:
         self.text_rx = scrolledtext.ScrolledText(frame_rx, wrap=tk.WORD, height=15)
         self.text_rx.pack(fill="both", expand=True)
 
-        # 发送区
-        frame_tx = ttk.LabelFrame(master, text="发送数据", padding=10)
+        # 发送
+        frame_tx = ttk.LabelFrame(master, text="帧发送设置", padding=10)
         frame_tx.pack(fill="x")
-        self.entry_tx = ttk.Entry(frame_tx, width=70)
-        self.entry_tx.pack(side="left", padx=5)
-        ttk.Button(frame_tx, text="发送", command=self.send_data).pack(side="left", padx=5)
+
+        # 命令模板下拉
+        ttk.Label(frame_tx, text="命令模板:").grid(row=0, column=0)
+        self.combo_frame = ttk.Combobox(frame_tx, width=50, state="readonly", values=[
+            "0A 00 00 00",  # 保留字段部分固定
+            "08 00 00 00",
+            "03 0A 00 D0",
+            "07 03 00 00",
+            "05 00 00 14",
+            "06 00 00 14",
+            "05 00 00 14"
+        ])
+        self.combo_frame.grid(row=0, column=1, padx=5)
+        self.combo_frame.current(0)
+
+        # 源地址下拉
+        ttk.Label(frame_tx, text="源地址(2B):").grid(row=1, column=0)
+        self.combo_src = ttk.Combobox(frame_tx, width=10, values=[
+            "29 8A", "FF FF", "2A 75"
+        ])
+        self.combo_src.grid(row=1, column=1, padx=5)
+        self.combo_src.current(0)
+
+        # 目标地址下拉
+        ttk.Label(frame_tx, text="目标地址(2B):").grid(row=1, column=2)
+        self.combo_dst = ttk.Combobox(frame_tx, width=10, values=[
+            "B4 60", "50 05", "60 06" , "FF FF"
+        ])
+        self.combo_dst.grid(row=1, column=3, padx=5)
+        self.combo_dst.current(0)
+
+        ttk.Button(frame_tx, text="发送帧", command=self.send_frame).grid(row=1, column=4, padx=10)
 
         # 状态栏
         self.status = ttk.Label(master, text="状态: 未连接", relief="sunken", anchor="w")
@@ -88,35 +117,45 @@ class SerialAssistant:
                 count = self.ser.in_waiting
                 if count:
                     raw_data = self.ser.read(count)
-                    # 判断显示格式
-                    if self.hex_display.get():
-                        display_data = " ".join(f"{b:02X}" for b in raw_data)
-                    else:
-                        display_data = raw_data.decode("utf-8", errors="ignore")
-
-                    self.text_rx.insert(tk.END, display_data + "\n")  # 自动换行
+                    display_data = " ".join(f"{b:02X}" for b in raw_data) if self.hex_display.get() else raw_data.decode("utf-8", errors="ignore")
+                    self.text_rx.insert(tk.END, display_data + "\n")
                     self.text_rx.see(tk.END)
             except Exception:
                 break
 
-    def send_data(self):
-        if self.ser and self.ser.is_open:
-            data = self.entry_tx.get()
-            if data:
-                try:
-                    # 若以 "0x" 开头或包含空格数字,则自动解析为 hex 发送
-                    if all(c in "0123456789ABCDEFabcdefxX " for c in data) and (" " in data or data.startswith("0x")):
-                        data_bytes = bytes.fromhex(data.replace("0x", "").replace("0X", ""))
-                    else:
-                        data_bytes = data.encode("utf-8")
-
-                    self.ser.write(data_bytes)
-                    self.text_rx.insert(tk.END, f"[发送] {data}\n")
-                    self.entry_tx.delete(0, tk.END)
-                except Exception as e:
-                    messagebox.showerror("发送错误", str(e))
-        else:
+    def send_frame(self):
+        if not (self.ser and self.ser.is_open):
             messagebox.showwarning("警告", "请先打开串口!")
+            return
+
+        try:
+            cmd_template = self.combo_frame.get().replace(" ", "")
+            src_addr = self.combo_src.get().replace(" ", "")
+            dst_addr = self.combo_dst.get().replace(" ", "")
+
+            if len(cmd_template) % 2 != 0:
+                raise ValueError("命令模板长度非法")
+            if len(src_addr) != 4 or len(dst_addr) != 4:
+                raise ValueError("地址长度非法")
+
+            # 组帧: 55 BB [命令模板] [源地址] [目标地址] FF EE
+            frame = bytearray()
+            frame.extend(b'\x55\xBB')
+            frame.extend(bytes.fromhex(cmd_template))
+            frame.extend(bytes.fromhex(src_addr))
+            # 保留字段 3B, 可在模板里也可固定
+            if len(cmd_template) < 4:
+                frame.extend(b'\x00\x00\x00')
+            frame.extend(bytes.fromhex(dst_addr))
+            frame.extend(b'\xFF\xEE')
+
+            self.ser.write(frame)
+            self.text_rx.insert(tk.END, f"[发送] {' '.join(f'{b:02X}' for b in frame)}\n")
+            self.text_rx.see(tk.END)
+
+        except ValueError as e:
+            messagebox.showerror("输入错误", str(e))
+
 
 if __name__ == "__main__":
     root = tk.Tk()