python3+tkinter+pyserial编写一个串口控制工具

2024-02-25 04:50

本文主要是介绍python3+tkinter+pyserial编写一个串口控制工具,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

python3+tkinter+pyserial编写一个串口控制工具

首先展示一下自己做的串口工具界面的全貌

在这里插入图片描述
可以看到其中包括文本框、选项框、按键、输入框还有列表,整个界面是用tkinter 实现的。

tkinter是一个方便使用python语言做界面的库,内涵多种控件,使用灵活方便

在windows系统下,tkinter 是python的自带库,就和re、os一样,直接import就能用;
但是在linux系统下,tkinter需要自行安装,指令如下:

sudo apt-get update
sudo apt-get install python3-tk

如果不行的话,需要自己去github或者 pypi.org网站找安装包,然后在终端切换到包所在的目录,输入

python setup.py install 

一般上面两种办法都能安装成功的, import tkinter试一下,不报错就说明安装成功了。
下面代码主要是tkinter对各控件的布局、参数设置的内容,可以直接运行。具体的执行内容pass掉了。

简单概括这个脚本所包含的tkinter的使用:

1.创建Tk父窗口,作为对象调用set_init_window进行窗口控件初始化
2.涉及到按钮Button、框架Frame、标签Label、输入框Entry
还有普通文本框Text、滚动文本框scrolltext、滚动条scrollbar
以及可以用作列表的Treeview控件、下拉选项框Combobox
3.控件的place、grid布局的使用和区别

4.自动获取电脑上可用的串口,作为串口下拉选项框的值

import tkinter
from tkinter import ttk,filedialog,messagebox,scrolledtext
from tkinter import *
import openpyxl
import threading
import time
import serial
import serial.tools.list_ports
import re
from code_dic import MY_CODE
class MY_GUI():#构造函数def __init__(self,name):self.init_window_name=name#窗口控件设置初始化def set_init_window(self):                        #控件设置的内容主要是这个函数,使用非常简单,主要是调用并设置参数self.init_window_name.title('串口控制')self.init_window_name.geometry('1168x631+20+10')self.init_window_name['bg']='pink'self.init_window_name.attributes('-alpha',1)#每个控件都需要用pack、place、grid布局去安置,就是设计了一个控件,要放在什么位置的意思。#按钮self.file_choose_button=Button(self.init_window_name,text='选择文件',bg='lightblue',width=10,command=self.thread_file)self.file_choose_button.place(x=40,y=170)   #place布局,x、y指的是距离父窗口左上端点的位置,像素位置self.conduct_button=Button(self.init_window_name,text='执行',bg='lightblue',width=10,command=self.com_output)self.conduct_button.place(x=40,y=455)self.log_save_button=Button(self.init_window_name,text='保存日志',bg='lightblue',width=10,command=self.thread_save)self.log_save_button.place(x=335,y=455)self.clear_button=Button(self.init_window_name,text='清空',bg='lightblue',width=10,command=self.thread_clear)self.clear_button.place(x=460,y=455)#按钮的command参数必须要指向一个函数进行调用,我这里用多线程实现,可以使各按钮的功能无干涉#串口选择框架self.com_choose_frame=Frame(self.init_window_name)self.com_choose_frame.place(x=20,y=12)#框架容纳多个控件,使界面布局更有层次感#串口选择框架内部标签,标签的值一般不做改变self.com_label=Label(self.com_choose_frame,text='COMx: ')self.com_label.grid(row=0,column=0,sticky=E)self.baudrate_label=Label(self.com_choose_frame,text='Baudrate: ')self.baudrate_label.grid(row=1,column=0,sticky=E,pady=10)#串口框架内部下拉选项框self.com_choose=StringVar()self.com_choose_combo=ttk.Combobox(self.com_choose_frame,width=30,textvariable=self.com_choose)self.com_choose_combo['state']='readonly'self.com_choose_combo.grid(row=0,column=1,padx=15)   #grid是表格式结构,行列都从0开始,padx表示x方向上两栏的间距self.com_choose_combo['values']=self.com_name_get()   #这里调用了一个函数,函数的返回值是一个数组#下拉选项框下拉的时候出现很多选项,选中之后只显示选中的选项#波特率选项框self.baudrate_value=StringVar(value='9600')     #StringVar是一个字符串变量控件self.baudrate_choose_combo=ttk.Combobox(self.com_choose_frame,width=30,textvariable=self.baudrate_value)#选项框中选中的值会赋值给字符串变量,并显示在combobox上self.baudrate_choose_combo['values']=('9600','115200')self.baudrate_choose_combo['state']='readonly'self.baudrate_choose_combo.grid(row=1,column=1,padx=15)#串口框架内部按钮self.connect_button=Button(self.com_choose_frame,text='连接',bg='lightblue',width=10,command=self.com_connect)self.connect_button.grid(row=0,column=2,padx=15)self.cancel_button=Button(self.com_choose_frame,text='取消',bg='lightblue',width=10,command=self.com_cancel)self.cancel_button.grid(row=1,column=2,padx=15)#处理结果显示滚动文本框self.result_text=scrolledtext.ScrolledText(self.init_window_name,width=77,height=42)self.result_text.place(x=600,y=50)#滚动文本框是tkinter库自带的一个小封装,将text构件scrollbar滚动条控件组合形成的,可以直接调用#其他文本框self.file_path_text=Text(self.init_window_name,width=57,height=1)self.file_path_text.place(x=150,y=175)self.com_log_text=Text(self.com_choose_frame,width=78,height=5)self.com_log_text.grid(row =2,column =0,columnspan=3,pady=5)self.com_log_text.insert(END,'此处显示串口工作信息'+'\n')           #这一句给字符串变量赋初值#标签self.result_data_label=Label(self.init_window_name,text='输出结果')self.result_data_label.place(x=600,y=15)self.num_input_label=Label(self.init_window_name,text='输入编号: ')self.num_input_label.place(x=150,y=460)#输入编号框self.input_num=StringVar()self.input_num_entry=Entry(self.init_window_name,textvariable=self.input_num,width=10)self.input_num_entry.place(x=215,y=460)#代码解析后进行显示self.code_frame=Frame(self.init_window_name,width=78,height=29,bg='white')self.code_frame.place(x=20,y=210)#解析后的代码放在表格内显示self.code_tree=ttk.Treeview(self.code_frame,show='headings',height=10,columns=('0','1','2','3','4')) #show='headings'会隐藏首列,否则首列太宽self.code_bar=ttk.Scrollbar(self.code_frame,orient=VERTICAL,command=self.code_tree.yview)self.code_tree.configure(yscrollcommand=self.code_bar.set)self.code_tree.grid(row=0,column=0,sticky=NSEW)self.code_bar.grid(row=0,column=1,sticky=NS)self.code_tree.column('0',width=30)self.code_tree.column('1',width=250)self.code_tree.column('2',width=50)self.code_tree.column('3',width=100)self.code_tree.column('4',width=100)self.code_tree.heading('0',text='序号')self.code_tree.heading('1',text='命令')self.code_tree.heading('2',text='状态')self.code_tree.heading('3',text='失败则执行次数')self.code_tree.heading('4',text='再失败则跳转至')#执行结果显示frameself.result_frame=Frame(self.init_window_name,width=78,height=15,bg='white')self.result_frame.place(x=20,y=500)self.result_tree=ttk.Treeview(self.result_frame,show='headings',height=4,columns=('0','1','2'))self.result_bar=ttk.Scrollbar(self.result_frame,orient=VERTICAL,command=self.result_tree.yview)self.result_tree.configure(yscrollcommand=self.result_bar.set)self.result_tree.grid(row=0,column=0,sticky=NSEW)self.result_bar.grid(row=0,column=1,sticky=NS)self.result_tree.column('0',width=30)self.result_tree.column('1',width=80)self.result_tree.column('2',width=420)self.result_tree.heading('0',text='编号')self.result_tree.heading('1',text='是否成功')self.result_tree.heading('2',text='从哪句指令开始失败')#自动获取当前连接的串口名def com_name_get(self):pass#连接按键的执行内容def com_connect(self):pass#取消按键的执行内容def com_cancel(self):pass#执行按键的执行内容def com_output(self):pass#新建线程,负责选择代码文件、保存代码执行结果和清空代码表格#新建选择文件线程def thread_file(self):thisthread=threading.Thread(target=self.file_choose)thisthread.start()#选择文件打开,并在界面中显示def file_choose(self):pass#新建线程保存执行结果def thread_save(self):thisthread=threading.Thread(target=self.code_log_save)thisthread.start()#保存代码执行结果日志def code_log_save(self):pass#新建线程清空所选文件以备重新选择def thread_clear(self):thisthread=threading.Thread(target=self.file_clear)thisthread.start()#删除所选文件,清空解析后的代码表格def file_clear(self):pass
#主线程
def start():init_window=Tk()            #因为写了一个类,所以要产生一个窗口对象,调用类的函数,进行窗口的构造和控件设置my_window=MY_GUI(init_window)my_window.set_init_window()init_window.mainloop()start()

pyserial 库是python用来控制串口的库,串口的开闭、读写都可以直接调用函数

将界面中的控件和串口的控制建立联系,才能在界面里用按钮控制串口,并将读写的内容在界面的滚动文本框里进行打印。
其中,重要的部分是:

1.自动获取电脑的可用串口名,并作为串口下拉选项框的选项
import re                       #正则表达式,可匹配任何字段
import serial.tools.list_ports  #获取串口名直接调用这个工具
def com_name_get(self):self.port_list=list(serial.tools.list_ports.comports())self.com_port_names=[]self.pattern=re.compile(r'[(](.*?)[)]',re.S) if len(self.port_list)>0:for i in range(len(self.port_list)):self.com_name=re.findall(self.pattern,str(self.port_list[i]))self.com_port_names.append(self.com_name)return self.com_port_names

在设备管理器里面查看串口的话,会发现COM1这个字段即串口名字是用括号括起来的,用serial.Serial开启串口只需要把COM1这个字段进行赋值,也就是只将电脑的串口名的括号内的字段捕获,并给serial赋值,开启这个串口。

pattern=re.compile(r'[(](.*?)[)]',re.S) 
com_name=re.findall(self.pattern,str(self.port_list[i]))

以上两句是正则表达式匹配括号内的值的方法。

2.点击连接按钮,在串口日志文本框显示串口是否成功打开,如果串口连接的设备有自动启动程序,则读取设备自启动程序的输出内容并显示
import time
def com_connect(self):self.result_text.insert(END,'请连接串口设备'+'\n')self.ser_name=str(self.com_choose.get())self.ser_baudrate=str(self.baudrate_value.get())try:self.ser=serial.Serial(self.ser_name)self.ser.baudrate=self.ser_baudrateself.ser.timeout=0.5self.com_log_text.insert(END,time.ctime(time.time())+'\t\t'+'串口成功打开'+'\n')self.com_log_text.see(tkinter.END)self.com_log_text.update()while True:newline=self.ser.readline()#字节类型self.result_text.insert(END,newline)self.result_text.see(tkinter.END)self.result_text.update()except:newline=time.ctime(time.time())+'\t\t'+'串口打开故障或串口被关闭'+'\n'self.com_log_text.insert(END,newline)self.com_log_text.see(tkinter.END)self.com_log_text.update()

这三句可以实现text文本框的动态打印,不会将原有内容清楚,一直向下滚动打印

text.insert(END,newline)
text.see(tkinter.END)
text.update()

这个串口工具还包括解析一个excel表格,将表格中的内容写入串口,将串口的执行结果写道界面的两个表格里显示,以及保存等,暂时还没写入文章,有了新的文章会把链接贴上。敬请期待~

这篇关于python3+tkinter+pyserial编写一个串口控制工具的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/744442

相关文章

浅析如何使用Swagger生成带权限控制的API文档

《浅析如何使用Swagger生成带权限控制的API文档》当涉及到权限控制时,如何生成既安全又详细的API文档就成了一个关键问题,所以这篇文章小编就来和大家好好聊聊如何用Swagger来生成带有... 目录准备工作配置 Swagger权限控制给 API 加上权限注解查看文档注意事项在咱们的开发工作里,API

Java数字转换工具类NumberUtil的使用

《Java数字转换工具类NumberUtil的使用》NumberUtil是一个功能强大的Java工具类,用于处理数字的各种操作,包括数值运算、格式化、随机数生成和数值判断,下面就来介绍一下Number... 目录一、NumberUtil类概述二、主要功能介绍1. 数值运算2. 格式化3. 数值判断4. 随机

使用Navicat工具比对两个数据库所有表结构的差异案例详解

《使用Navicat工具比对两个数据库所有表结构的差异案例详解》:本文主要介绍如何使用Navicat工具对比两个数据库test_old和test_new,并生成相应的DDLSQL语句,以便将te... 目录概要案例一、如图两个数据库test_old和test_new进行比较:二、开始比较总结概要公司存在多

Java中基于注解的代码生成工具MapStruct映射使用详解

《Java中基于注解的代码生成工具MapStruct映射使用详解》MapStruct作为一个基于注解的代码生成工具,为我们提供了一种更加优雅、高效的解决方案,本文主要为大家介绍了它的具体使用,感兴趣... 目录介绍优缺点优点缺点核心注解及详细使用语法说明@Mapper@Mapping@Mappings@Co

使用Python实现图片和base64转换工具

《使用Python实现图片和base64转换工具》这篇文章主要为大家详细介绍了如何使用Python中的base64模块编写一个工具,可以实现图片和Base64编码之间的转换,感兴趣的小伙伴可以了解下... 简介使用python的base64模块来实现图片和Base64编码之间的转换。可以将图片转换为Bas

使用Java实现一个解析CURL脚本小工具

《使用Java实现一个解析CURL脚本小工具》文章介绍了如何使用Java实现一个解析CURL脚本的工具,该工具可以将CURL脚本中的Header解析为KVMap结构,获取URL路径、请求类型,解析UR... 目录使用示例实现原理具体实现CurlParserUtilCurlEntityICurlHandler

Rsnapshot怎么用? 基于Rsync的强大Linux备份工具使用指南

《Rsnapshot怎么用?基于Rsync的强大Linux备份工具使用指南》Rsnapshot不仅可以备份本地文件,还能通过SSH备份远程文件,接下来详细介绍如何安装、配置和使用Rsnaps... Rsnapshot 是一款开源的文件系统快照工具。它结合了 Rsync 和 SSH 的能力,可以帮助你在 li

Spring IOC控制反转的实现解析

《SpringIOC控制反转的实现解析》:本文主要介绍SpringIOC控制反转的实现,IOC是Spring的核心思想之一,它通过将对象的创建、依赖注入和生命周期管理交给容器来实现解耦,使开发者... 目录1. IOC的基本概念1.1 什么是IOC1.2 IOC与DI的关系2. IOC的设计目标3. IOC

基于Go语言实现一个压测工具

《基于Go语言实现一个压测工具》这篇文章主要为大家详细介绍了基于Go语言实现一个简单的压测工具,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录整体架构通用数据处理模块Http请求响应数据处理Curl参数解析处理客户端模块Http客户端处理Grpc客户端处理Websocket客户端

java图像识别工具类(ImageRecognitionUtils)使用实例详解

《java图像识别工具类(ImageRecognitionUtils)使用实例详解》:本文主要介绍如何在Java中使用OpenCV进行图像识别,包括图像加载、预处理、分类、人脸检测和特征提取等步骤... 目录前言1. 图像识别的背景与作用2. 设计目标3. 项目依赖4. 设计与实现 ImageRecogni