python写上位机并打包250824

1.python写的串口上位机软件程序

import serial
import serial.tools.list_ports
import tkinter as tk
from tkinter import ttk, scrolledtext, messagebox, filedialog
import threading
import time
from datetime import datetime

class SerialPortAssistant:
def init(self, root):
self.root = root
self.root.title(“串口助手”)
self.root.geometry(“800x600”)

    self.serial_port = Noneself.is_receiving = Falseself.receive_thread = Noneself.create_widgets()self.update_port_list()# 默认设置self.baudrate_var.set("9600")self.databits_var.set("8")self.stopbits_var.set("1")self.parity_var.set("None")self.flowcontrol_var.set("None")def create_widgets(self):# 串口设置区域settings_frame = ttk.LabelFrame(self.root, text="串口设置", padding=10)settings_frame.pack(fill=tk.X, padx=5, pady=5)# 串口号ttk.Label(settings_frame, text="串口号:").grid(row=0, column=0, sticky=tk.W)self.port_var = tk.StringVar()self.port_combobox = ttk.Combobox(settings_frame, textvariable=self.port_var, width=10)self.port_combobox.grid(row=0, column=1, sticky=tk.W)# 波特率ttk.Label(settings_frame, text="波特率:").grid(row=0, column=2, sticky=tk.W)self.baudrate_var = tk.StringVar()baudrates = ["9600", "19200", "38400", "57600", "115200", "230400", "460800", "921600"]self.baudrate_combobox = ttk.Combobox(settings_frame, textvariable=self.baudrate_var, values=baudrates, width=10)self.baudrate_combobox.grid(row=0, column=3, sticky=tk.W)# 数据位ttk.Label(settings_frame, text="数据位:").grid(row=0, column=4, sticky=tk.W)self.databits_var = tk.StringVar()databits = ["5", "6", "7", "8"]self.databits_combobox = ttk.Combobox(settings_frame, textvariable=self.databits_var, values=databits, width=5)self.databits_combobox.grid(row=0, column=5, sticky=tk.W)# 停止位ttk.Label(settings_frame, text="停止位:").grid(row=1, column=0, sticky=tk.W)self.stopbits_var = tk.StringVar()stopbits = ["1", "1.5", "2"]self.stopbits_combobox = ttk.Combobox(settings_frame, textvariable=self.stopbits_var, values=stopbits, width=5)self.stopbits_combobox.grid(row=1, column=1, sticky=tk.W)# 校验位ttk.Label(settings_frame, text="校验位:").grid(row=1, column=2, sticky=tk.W)self.parity_var = tk.StringVar()parities = ["None", "Even", "Odd", "Mark", "Space"]self.parity_combobox = ttk.Combobox(settings_frame, textvariable=self.parity_var, values=parities, width=8)self.parity_combobox.grid(row=1, column=3, sticky=tk.W)# 流控ttk.Label(settings_frame, text="流控:").grid(row=1, column=4, sticky=tk.W)self.flowcontrol_var = tk.StringVar()flowcontrols = ["None", "Hardware (RTS/CTS)", "Software (XON/XOFF)"]self.flowcontrol_combobox = ttk.Combobox(settings_frame, textvariable=self.flowcontrol_var, values=flowcontrols, width=15)self.flowcontrol_combobox.grid(row=1, column=5, sticky=tk.W)# 刷新按钮refresh_btn = ttk.Button(settings_frame, text="刷新", command=self.update_port_list)refresh_btn.grid(row=0, column=6, padx=5)# 打开/关闭按钮self.connect_btn = ttk.Button(settings_frame, text="打开串口", command=self.toggle_connection)self.connect_btn.grid(row=1, column=6, padx=5)# 发送设置区域send_settings_frame = ttk.LabelFrame(self.root, text="发送设置", padding=10)send_settings_frame.pack(fill=tk.X, padx=5, pady=5)# 发送格式ttk.Label(send_settings_frame, text="发送格式:").grid(row=0, column=0, sticky=tk.W)self.send_format_var = tk.StringVar(value="ASCII")ttk.Radiobutton(send_settings_frame, text="ASCII", variable=self.send_format_var, value="ASCII").grid(row=0, column=1, sticky=tk.W)ttk.Radiobutton(send_settings_frame, text="Hex", variable=self.send_format_var, value="Hex").grid(row=0, column=2, sticky=tk.W)# 自动换行self.auto_newline_var = tk.IntVar(value=1)ttk.Checkbutton(send_settings_frame, text="自动添加换行", variable=self.auto_newline_var).grid(row=0, column=3, sticky=tk.W)# 定时发送ttk.Label(send_settings_frame, text="定时发送(ms):").grid(row=0, column=4, sticky=tk.W)self.timer_var = tk.StringVar()self.timer_entry = ttk.Entry(send_settings_frame, textvariable=self.timer_var, width=8)self.timer_entry.grid(row=0, column=5, sticky=tk.W)self.timer_entry.config(state=tk.DISABLED)# 接收设置区域recv_settings_frame = ttk.LabelFrame(self.root, text="接收设置", padding=10)recv_settings_frame.pack(fill=tk.X, padx=5, pady=5)# 接收格式ttk.Label(recv_settings_frame, text="接收格式:").grid(row=0, column=0, sticky=tk.W)self.recv_format_var = tk.StringVar(value="ASCII")ttk.Radiobutton(recv_settings_frame, text="ASCII", variable=self.recv_format_var, value="ASCII").grid(row=0, column=1, sticky=tk.W)ttk.Radiobutton(recv_settings_frame, text="Hex", variable=self.recv_format_var, value="Hex").grid(row=0, column=2, sticky=tk.W)# 显示设置ttk.Label(recv_settings_frame, text="显示设置:").grid(row=0, column=3, sticky=tk.W)self.display_var = tk.StringVar(value="显示时间")ttk.Checkbutton(recv_settings_frame, text="显示时间", variable=self.display_var, onvalue="显示时间", offvalue="").grid(row=0, column=4, sticky=tk.W)# 保存接收数据save_btn = ttk.Button(recv_settings_frame, text="保存接收数据", command=self.save_received_data)save_btn.grid(row=0, column=5, padx=5)# 清除接收区clear_btn = ttk.Button(recv_settings_frame, text="清除接收区", command=self.clear_received_data)clear_btn.grid(row=0, column=6, padx=5)# 发送区域send_frame = ttk.LabelFrame(self.root, text="发送区", padding=10)send_frame.pack(fill=tk.X, padx=5, pady=5)self.send_text = tk.Text(send_frame, height=5)self.send_text.pack(fill=tk.X, expand=True)# 发送按钮send_btn_frame = ttk.Frame(send_frame)send_btn_frame.pack(fill=tk.X, pady=5)self.send_btn = ttk.Button(send_btn_frame, text="发送", command=self.send_data)self.send_btn.pack(side=tk.LEFT, padx=5)self.timer_send_btn = ttk.Button(send_btn_frame, text="启动定时发送", command=self.toggle_timer_send)self.timer_send_btn.pack(side=tk.LEFT, padx=5)self.timer_send_btn.config(state=tk.DISABLED)# 接收区域recv_frame = ttk.LabelFrame(self.root, text="接收区", padding=10)recv_frame.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)self.recv_text = scrolledtext.ScrolledText(recv_frame, height=15)self.recv_text.pack(fill=tk.BOTH, expand=True)# 状态栏self.status_var = tk.StringVar()self.status_var.set("就绪")status_bar = ttk.Label(self.root, textvariable=self.status_var, relief=tk.SUNKEN)status_bar.pack(fill=tk.X, padx=5, pady=5)def update_port_list(self):"""更新可用串口列表"""ports = serial.tools.list_ports.comports()port_list = [port.device for port in ports]self.port_combobox['values'] = port_listif port_list:self.port_combobox.current(0)def toggle_connection(self):"""打开/关闭串口"""if self.serial_port and self.serial_port.is_open:self.close_serial_port()self.connect_btn.config(text="打开串口")self.status_var.set("串口已关闭")else:if self.open_serial_port():self.connect_btn.config(text="关闭串口")self.status_var.set(f"串口 {self.port_var.get()} 已打开")self.start_receiving()def open_serial_port(self):"""打开串口"""try:port = self.port_var.get()baudrate = int(self.baudrate_var.get())bytesize = int(self.databits_var.get())stopbits_map = {"1": serial.STOPBITS_ONE, "1.5": serial.STOPBITS_ONE_POINT_FIVE, "2": serial.STOPBITS_TWO}stopbits = stopbits_map[self.stopbits_var.get()]parity_map = {"None": serial.PARITY_NONE, "Even": serial.PARITY_EVEN, "Odd": serial.PARITY_ODD, "Mark": serial.PARITY_MARK, "Space": serial.PARITY_SPACE}parity = parity_map[self.parity_var.get()]flowcontrol_map = {"None": serial.FLOWCONTROL_NONE,"Hardware (RTS/CTS)": serial.FLOWCONTROL_RTSCTS,"Software (XON/XOFF)": serial.FLOWCONTROL_SOFTWARE}flowcontrol = flowcontrol_map[self.flowcontrol_var.get()]self.serial_port = serial.Serial(port=port,baudrate=baudrate,bytesize=bytesize,parity=parity,stopbits=stopbits,xonxoff=flowcontrol == serial.FLOWCONTROL_SOFTWARE,rtscts=flowcontrol == serial.FLOWCONTROL_RTSCTS,timeout=1)# 启用定时发送按钮self.timer_send_btn.config(state=tk.NORMAL)self.timer_entry.config(state=tk.NORMAL)return Trueexcept Exception as e:messagebox.showerror("错误", f"无法打开串口:\n{str(e)}")return Falsedef close_serial_port(self):"""关闭串口"""if self.serial_port and self.serial_port.is_open:self.stop_receiving()self.stop_timer_send()self.serial_port.close()self.timer_send_btn.config(state=tk.DISABLED)self.timer_entry.config(state=tk.DISABLED)def start_receiving(self):"""开始接收数据"""self.is_receiving = Trueself.receive_thread = threading.Thread(target=self.receive_data, daemon=True)self.receive_thread.start()def stop_receiving(self):"""停止接收数据"""self.is_receiving = Falseif self.receive_thread and self.receive_thread.is_alive():self.receive_thread.join()def receive_data(self):"""接收数据线程"""while self.is_receiving 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)self.display_received_data(data)except Exception as e:self.status_var.set(f"接收错误: {str(e)}")breaktime.sleep(0.01)def display_received_data(self, data):"""显示接收到的数据"""def append_text(text):self.recv_text.insert(tk.END, text)self.recv_text.see(tk.END)self.root.update()display_data = dataif self.recv_format_var.get() == "Hex":display_data = data.hex(' ').upper()if self.display_var.get() == "显示时间":current_time = datetime.now().strftime("[%H:%M:%S.%f] ")append_text(current_time)append_text(display_data.decode('latin-1') if self.recv_format_var.get() == "ASCII" else display_data + '\n')def send_data(self):"""发送数据"""if not self.serial_port or not self.serial_port.is_open:messagebox.showwarning("警告", "请先打开串口")returntry:data = self.send_text.get("1.0", tk.END).strip()if not data:returnif self.send_format_var.get() == "Hex":# 处理Hex发送data = data.replace(" ", "").replace("\n", "")if len(data) % 2 != 0:messagebox.showwarning("警告", "Hex数据长度必须为偶数")returntry:send_data = bytes.fromhex(data)except ValueError:messagebox.showwarning("警告", "无效的Hex数据")returnelse:# ASCII发送send_data = data.encode('utf-8')if self.auto_newline_var.get():send_data += b'\r\n'self.serial_port.write(send_data)self.status_var.set(f"已发送 {len(send_data)} 字节")except Exception as e:messagebox.showerror("错误", f"发送失败:\n{str(e)}")def toggle_timer_send(self):"""切换定时发送状态"""if hasattr(self, 'timer_send_active') and self.timer_send_active:self.stop_timer_send()self.timer_send_btn.config(text="启动定时发送")else:self.start_timer_send()self.timer_send_btn.config(text="停止定时发送")def start_timer_send(self):"""启动定时发送"""try:interval = int(self.timer_var.get())if interval <= 0:raise ValueError("间隔时间必须大于0")self.timer_send_active = Trueself.timer_send_task()except ValueError as e:messagebox.showwarning("警告", f"无效的定时发送间隔:\n{str(e)}")def stop_timer_send(self):"""停止定时发送"""if hasattr(self, 'timer_send_active'):self.timer_send_active = Falsedef timer_send_task(self):"""定时发送任务"""if getattr(self, 'timer_send_active', False):self.send_data()interval = int(self.timer_var.get())self.root.after(interval, self.timer_send_task)def save_received_data(self):"""保存接收到的数据"""data = self.recv_text.get("1.0", tk.END)if not data:messagebox.showwarning("警告", "没有数据可保存")returnfile_path = filedialog.asksaveasfilename(defaultextension=".txt",filetypes=[("Text files", "*.txt"), ("All files", "*.*")],title="保存接收数据")if file_path:try:with open(file_path, 'w', encoding='utf-8') as f:f.write(data)messagebox.showinfo("成功", "数据保存成功")except Exception as e:messagebox.showerror("错误", f"保存失败:\n{str(e)}")def clear_received_data(self):"""清除接收区"""self.recv_text.delete("1.0", tk.END)def on_closing(self):"""窗口关闭事件处理"""self.close_serial_port()self.root.destroy()

if name == “main”:
root = tk.Tk()
app = SerialPortAssistant(root)
root.protocol(“WM_DELETE_WINDOW”, app.on_closing)
root.mainloop()

2、python打包程序

a、pip install pyinstaller

b、打包

import PyInstaller.main

PyInstaller.main.run([
‘–name=SerialPortAssistant’,
‘–onefile’,
‘–windowed’,
‘–add-data=icon.ico;.’, # 如果有图标文件
‘serial_assistant.py’ # 你的主程序文件名
])
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/news/919975.shtml
繁体地址,请注明出处:http://hk.pswp.cn/news/919975.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Wagtail CRX 简介

Wagtail CRX&#xff08;前身为 CodeRed CMS&#xff0c;由 CodeRed Corp 开发&#xff09;是一个基于 Wagtail 的 CMS 扩展包&#xff0c;主要用于快速构建营销型网站&#xff0c;提供预置组件和增强功能。最新版本为 5.0.1&#xff08;发布于 2025 年 5 月 9 日&#xff09;。…

docker compose 安装zabbix 7

docker compose 安装zabbix 7 1.环境 # hostnamectlStatic hostname: ky10Icon name: computer-vmChassis: vmMachine ID: f554764e21b74c2fa057d9aaa296af63Boot ID: 4c155f0185c24a14970ab5ea60de34f4Virtualization: vmwareOperating System: Kylin Linux Advanced Server…

EtherCAT的几种邮箱通信介绍

1. COE&#xff08;CANopen over EtherCAT&#xff09;技术特点&#xff1a;直接复用 CANopen 的对象字典&#xff08;Object Dictionary&#xff09;机制&#xff0c;通过 EtherCAT 的邮箱通信实现非周期性数据交换&#xff0c;同时支持过程数据对象&#xff08;PDO&#xff0…

【Java】springboot的自动配置

如果你用过 Spring Boot&#xff0c;一定对 “引入依赖就能用” 的体验印象深刻 —— 加个spring-boot-starter-web就有了 Web 环境&#xff0c;这个是 SpringBoot 的自动装配&#xff08;Auto-Configuration&#xff09;机制。自动装配的核心注解自动装配的逻辑看似复杂&#…

高通机型QPST平台线刷教程 线刷全分区 只通过引导文件提取单分区 写入单分区

高通芯片机型刷机平台很多&#xff0c;除过一些厂家专用的平台外。qpst是高通芯片类通用刷写平台。其操作简单 可以刷写完整固件。也可以通过单个引导文件来读取 提取整个分区。而且包含读写基带qcn等等的一些功能。 qpst工具下载 QPST 的不同版本可在多个开源平台或技术论坛中…

ES_预处理

1. 预处理的核心概念&#xff1a;什么是 Ingest Pipeline&#xff1f; 想象一下数据进入 Elasticsearch 的旅程。原始数据&#xff08;Raw Data&#xff09;往往并不完美&#xff1a;格式可能混乱&#xff0c;字段可能缺失&#xff0c;或者需要被丰富和转换后才能发挥最大的价值…

我从零开始学习C语言(15)- 基本类型 PART2

开始学习第七章其余部分。7.3.4 转义序列正如在前面示例中见到的那样&#xff0c;字符常量通常是用单引号括起来的单个字符。然而&#xff0c;一些特殊符号&#xff08;比如换行符&#xff09;是无法采用上述方式书写的&#xff0c;因为它们不可见&#xff08;非打印字符&#…

K8S的部署与常用管理

一、k8s的部署 1.1.集群环境初始化 1.1.1.所有主机禁用swap [rootk8s- ~]# systemctl mask dev-nvme0n1p3.swap [rootk8s- ~]# swapoff -a [rootk8s- ~]# systemctl status dev-nvme0n1p3.swap [rootk8s- ~]# vim /etc/fstab 内容&#xff1a; 注释swap 1.1.2.安装k8s部署工…

2025年机械工程与自动化技术国际会议(ICMEAT 2025)

2025年机械工程与自动化技术国际会议&#xff08;ICMEAT 2025&#xff09; 2025 International Conference on Mechanical Engineering and Automation Technology一、大会信息会议简称&#xff1a;ICMEAT 2025 大会地点&#xff1a;中国杭州 审稿通知&#xff1a;投稿后2-3日内…

高数 不定积分(4-3):分部积分法

文章目录写在前面分部积分法&#x1f615; 一个小问题✨ 分部积分法是怎么来的&#xff1f;&#x1f330; 几个小例子⭐ 最终总结&#xff01;后话写在前面 文章传送门&#xff1a;高数 不定积分&#xff08;4-2&#xff09;&#xff1a;换元积分法 今天再更一篇:) 上篇文章&…

Chrome/360 浏览器 WebUI 资源底层机制解析:共享资源与专属资源的奥秘

在 Chromium 和 360 浏览器源码中&#xff0c;我们会发现 WebUI 页面不仅有 C 逻辑处理&#xff08;如 WebUIMessageHandler&#xff09;&#xff0c;还伴随着大量 HTML、CSS 和 JS 文件。尤其是 src/ui/webui/resources 和 src/chrome/browser/360/webui 这两个目录&#xff0…

基于springboot的高校后勤保修服务系统/基于android的高校后勤保修服务系统app

基于springboot的高校后勤保修服务系统/基于android的高校后勤保修服务系统app

Qt QML 用Q_PROPERTY快捷访问c++属性

在之前我写过如何调用函数&#xff0c;当时的属性都是手搓的&#xff0c;也就是自己写成员变量、变化信号和读写函数&#xff0c;但其实有一个很便捷的方法&#xff0c;即使用Q_PROPERTY&#xff0c;下面给出标准结构&#xff1a;Q_PROPERTY(数据类型 变量名 READ 变量名 WRITE…

ubuntu中网卡的 IP 及网关配置设置为永久生效

要将 Ubuntu 中 ens33 和 ens36 网卡的 IP 及网关配置设置为永久生效&#xff08;重启后不丢失&#xff09;&#xff0c;需通过 netplan 配置并禁用 cloud-init 对网络的干扰&#xff08;避免重启后配置被覆盖&#xff09;&#xff0c;具体步骤如下&#xff1a;一、最终的永久生…

不再让Windows更新!Edge游戏助手卸载及关闭自动更新

文章目录Windows系统更新问题方法一&#xff1a;通过注册表手动设置1. 打开注册表编辑器2. 定位到目标路径3. 创建新的DWORD值4. 修改数值方法二&#xff1a;命令行设置1. 打开命令提示符2. 输入命令验证设置是否生效恢复更新Edge关闭游戏助手Edge关闭后台运行Edge关闭自动更新…

css3之flex布局

flex布局要牢记的两个知识点&#xff1a; 开启了flex布局的元素叫flex containerflex container里面的直接子元素叫flex items 这两点要记牢&#xff0c;设置属性的时候才不会搞混这个是flex布局的整体图 一、flex container上的属性 1.flex-direction 修改主轴方向的属性&…

vscode 搭建C/C++开发环境搭建(linux)

1.编译器/调试器安装首先&#xff0c;需要安装编译器&#xff08;GCC/G&#xff09;和调试器&#xff08;GDB&#xff09;,用于编译和调试代码。1.打开终端(Ctrl Alt T)2.更新软件包获取新版本信息sudo apt update3.安装build-essential包,它包含gcc,g等必要库sudo apt install…

vue-pure-admin页面引入和功能添加流程解析

vue-pure-admin (opens new window)是一款开源完全免费且开箱即用的中后台管理系统模版。完全采用 ECMAScript 模块&#xff08;ESM&#xff09;规范来编写和组织代码&#xff0c;使用了最新的 Vue3、Vite、Element-Plus、TypeScript、Pinia、Tailwindcss 等主流技术开发 以下是…

vlc-android: 编译自己的libvlc

概述 VLC 媒体播放器作为一款由志愿者开发团队精心维护的自由、开源且跨平台的多媒体播放器&#xff0c;能轻松驾驭绝大多数多媒体文件&#xff0c;无论是本地磁盘中的视频、音频&#xff0c;还是来自网络的流媒体协议. VLC for Android 支持网络串流&#xff0c;无论是基于 H…

并联谐振与串联谐振

在LC电路中&#xff0c;感抗和容抗相等时对应的频率值称为谐振频率&#xff0c;在接收广播电视信号或无线通信信号时&#xff0c;使接收电路的频率与所选择的发射的信号频率相同就叫做调谐。并联谐振LC并联谐振电路是指将电感器和电容器并联形成&#xff0c;如图所示。在并联谐…