xuxinyi 1 месяц назад
Родитель
Сommit
5dc8e00a91
2 измененных файлов с 171 добавлено и 30 удалено
  1. 48 1
      .idea/workspace.xml
  2. 123 29
      main.py

+ 48 - 1
.idea/workspace.xml

@@ -1,12 +1,21 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <project version="4">
+  <component name="AutoImportSettings">
+    <option name="autoReloadType" value="SELECTIVE" />
+  </component>
   <component name="ChangeListManager">
-    <list default="true" id="1ac4e985-6885-47ec-89fe-c34ac50172a1" name="更改" comment="" />
+    <list default="true" id="1ac4e985-6885-47ec-89fe-c34ac50172a1" name="更改" comment="first commit">
+      <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>
     <option name="SHOW_DIALOG" value="false" />
     <option name="HIGHLIGHT_CONFLICTS" value="true" />
     <option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
     <option name="LAST_RESOLUTION" value="IGNORE" />
   </component>
+  <component name="Git.Settings">
+    <option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
+  </component>
   <component name="ProjectColorInfo"><![CDATA[{
   "associatedIndex": 6
 }]]></component>
@@ -17,7 +26,17 @@
   </component>
   <component name="PropertiesComponent"><![CDATA[{
   "keyToString": {
+    "ModuleVcsDetector.initialDetectionPerformed": "true",
+    "Python.main.executor": "Run",
     "RunOnceActivity.ShowReadmeOnStart": "true",
+    "RunOnceActivity.TerminalTabsStorage.copyFrom.TerminalArrangementManager.252": "true",
+    "RunOnceActivity.git.unshallow": "true",
+    "git-widget-placeholder": "master",
+    "node.js.detected.package.eslint": "true",
+    "node.js.detected.package.tslint": "true",
+    "node.js.selected.package.eslint": "(autodetect)",
+    "node.js.selected.package.tslint": "(autodetect)",
+    "nodejs_package_manager_path": "npm",
     "vue.rearranger.settings.migration": "true"
   }
 }]]></component>
@@ -36,10 +55,38 @@
       <option name="number" value="Default" />
       <option name="presentableId" value="Default" />
       <updated>1760066680854</updated>
+      <workItem from="1760066681868" duration="3456000" />
+    </task>
+    <task id="LOCAL-00001" summary="first commit">
+      <option name="closed" value="true" />
+      <created>1760066983356</created>
+      <option name="number" value="00001" />
+      <option name="presentableId" value="LOCAL-00001" />
+      <option name="project" value="LOCAL" />
+      <updated>1760066983356</updated>
     </task>
+    <option name="localTasksCounter" value="2" />
     <servers />
   </component>
   <component name="TypeScriptGeneratedFilesManager">
     <option name="version" value="3" />
   </component>
+  <component name="Vcs.Log.Tabs.Properties">
+    <option name="TAB_STATES">
+      <map>
+        <entry key="MAIN">
+          <value>
+            <State />
+          </value>
+        </entry>
+      </map>
+    </option>
+  </component>
+  <component name="VcsManagerConfiguration">
+    <MESSAGE value="first commit" />
+    <option name="LAST_COMMIT_MESSAGE" value="first commit" />
+  </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$" />
+  </component>
 </project>

+ 123 - 29
main.py

@@ -1,30 +1,124 @@
 import serial
-import time
-
-try:
-    # 配置串口参数 - 请根据实际设备修改端口号
-    ser = serial.Serial(
-        port='COM27',  # 修改为实际的端口号
-        baudrate=115200,
-        parity=serial.PARITY_NONE,
-        stopbits=serial.STOPBITS_ONE,
-        bytesize=serial.EIGHTBITS,
-        timeout=1  # 添加超时设置,避免程序卡死
-    )
-
-    if ser.is_open:
-        print(f"成功打开串口: {ser.port}")
-
-        # 发送数据
-        data = "Hello, Serial!"
-        ser.write(data.encode('utf-8'))
-        print(f"发送数据: {data}")
-
-        time.sleep(1)
-        ser.close()
-        print("串口已关闭")
-
-except serial.SerialException as e:
-    print(f"串口错误: {e}")
-except Exception as e:
-    print(f"发生错误: {e}")
+import serial.tools.list_ports
+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.resizable(False, False)
+
+        # 串口对象和状态
+        self.ser = None
+        self.is_running = False
+        self.hex_display = tk.BooleanVar(value=False)  # 是否以16进制显示
+
+        # 串口设置区
+        frame_top = ttk.LabelFrame(master, text="串口设置", padding=10)
+        frame_top.pack(fill="x")
+
+        ttk.Label(frame_top, text="端口:").grid(row=0, column=0)
+        self.combo_port = ttk.Combobox(frame_top, width=10, values=self.list_serial_ports())
+        self.combo_port.grid(row=0, column=1, padx=5)
+        if self.combo_port["values"]:
+            self.combo_port.current(0)
+
+        ttk.Label(frame_top, text="波特率:").grid(row=0, column=2)
+        self.combo_baud = ttk.Combobox(frame_top, width=10, values=[9600, 19200, 38400, 57600, 115200])
+        self.combo_baud.current(4)
+        self.combo_baud.grid(row=0, column=3, padx=5)
+
+        self.btn_open = ttk.Button(frame_top, text="打开串口", command=self.open_serial)
+        self.btn_open.grid(row=0, column=4, padx=5)
+        self.btn_close = ttk.Button(frame_top, text="关闭串口", command=self.close_serial, state=tk.DISABLED)
+        self.btn_close.grid(row=0, column=5, padx=5)
+
+        ttk.Checkbutton(frame_top, text="16进制显示", variable=self.hex_display).grid(row=0, column=6, padx=10)
+
+        # 接收区
+        frame_rx = ttk.LabelFrame(master, text="接收数据", padding=10)
+        frame_rx.pack(fill="both", expand=True)
+        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.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)
+
+        # 状态栏
+        self.status = ttk.Label(master, text="状态: 未连接", relief="sunken", anchor="w")
+        self.status.pack(fill="x", side="bottom")
+
+    def list_serial_ports(self):
+        ports = [port.device for port in serial.tools.list_ports.comports()]
+        return ports if ports else ["无可用端口"]
+
+    def open_serial(self):
+        port = self.combo_port.get()
+        baud = self.combo_baud.get()
+        try:
+            self.ser = serial.Serial(port, baudrate=int(baud), timeout=0)
+            self.is_running = True
+            self.btn_open["state"] = tk.DISABLED
+            self.btn_close["state"] = tk.NORMAL
+            self.status["text"] = f"状态: 已连接 {port} ({baud}bps)"
+            self.text_rx.insert(tk.END, f"[系统] 成功打开串口 {port}\n")
+            threading.Thread(target=self.read_serial, daemon=True).start()
+        except Exception as e:
+            messagebox.showerror("错误", f"无法打开串口: {e}")
+
+    def close_serial(self):
+        self.is_running = False
+        if self.ser and self.ser.is_open:
+            self.ser.close()
+        self.btn_open["state"] = tk.NORMAL
+        self.btn_close["state"] = tk.DISABLED
+        self.status["text"] = "状态: 未连接"
+        self.text_rx.insert(tk.END, "[系统] 串口已关闭\n")
+
+    def read_serial(self):
+        while self.is_running and self.ser and self.ser.is_open:
+            try:
+                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")  # 自动换行
+                    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:
+            messagebox.showwarning("警告", "请先打开串口!")
+
+if __name__ == "__main__":
+    root = tk.Tk()
+    app = SerialAssistant(root)
+    root.mainloop()