【python】tkinter+pyserial实现串口调试助手 您所在的位置:网站首页 Python开发上位机 【python】tkinter+pyserial实现串口调试助手

【python】tkinter+pyserial实现串口调试助手

#【python】tkinter+pyserial实现串口调试助手| 来源: 网络整理| 查看: 265

目录 Python串口调试助手(基于tkinter)开发环境需安装的模块:适合对象:界面样式主题修改完整代码如下:

Python串口调试助手(基于tkinter)

新手自学一周的成果;基本功能完善,初测无什么BUG。语法比较新手向注释完整,适合学习使用。 采用官方tkinter界面库小巧自带,配合ttkbootstrap插件可快速切换主体,颜值即正义!

开发环境

解释器:Python 3.11 环境:pycharm

需安装的模块:

串口模块安装命令:pip3 install pyserial GUI插件安装命令:python -m pip install ttkbootstrap

适合对象:

需具备Python基本语法基础: 串口学习参考资料:点击跳转 tkinter学习资料:点击跳转

界面样式

--------------------------------------------------------样式一--------------------------------------------------- 样式一

-------------------------------------------------样式二---------------------------------------------------------

样式二

-------------------------------------------------样式三--------------------------------------------------------- 样式三

主题修改

可通过第118行进行主题修改,注释后面的都可设置。

Style(theme='pulse') #主题修改 可选['cyborg', 'journal', 'darkly', 'flatly' 'solar', 'minty', 'litera', 'united', 'pulse', 'cosmo', 'lumen', 'yeti', 'superhero','sandstone'] 完整代码如下: # -*- coding: utf-8 -*- # @Time : 2022/11/29 14:49 # @Author : Administrator # @Email : [email protected] # @File : 串口调试助手.py # @Project : sdudy1 import time from tkinter.ttk import * from tkinter import * import datetime import serial # 导入模块 import serial.tools.list_ports import threading from tkinter import messagebox from ttkbootstrap import Style global UART #全局型式保存串口句柄 global RX_THREAD #全局型式保存串口接收函数 global gui #全局型式保存GUI句柄 tx_cnt=0 #发送字符数统计 rx_cnt=0 #接收字符数统计 def ISHEX(data): #判断输入字符串是否为十六进制 if len(data)%2: return False for item in data: if item not in '0123456789ABCDEFabcdef': #循环判断数字和字符 return False return True def uart_open_close(fun,com,bund): #串口打开关闭控制 global UART global RX_THREAD if fun==1:#打开串口 try: UART = serial.Serial(com, bund, timeout=0.2) # 提取串口号和波特率并打开串口 if UART.isOpen(): #判断是否打开成功 lock = threading.Lock() RX_THREAD = UART_RX_TREAD('URX1',lock) #开启数据接收进程 RX_THREAD.setDaemon(True) #开启守护进程 主进程结束后接收进程也关闭 会报警告 不知道咋回事 RX_THREAD.start() RX_THREAD.resume() return True except: return False return False else: #关闭串口 print("关闭串口") RX_THREAD.pause() UART.close() def uart_tx(data,isHex=False): #串口发送数据 global UART try: if UART.isOpen(): #发送前判断串口状态 避免错误 print("uart_send=" + data) gui.tx_rx_cnt(tx=len(data)) #发送计数 if isHex: #十六进制发送 data_bytes = bytes.fromhex(data) return UART.write(bytes(data_bytes)) else: #字符发送 return UART.write(data.encode('gb2312')) except:#错误返回 messagebox.showinfo('错误', '发送失败') class UART_RX_TREAD(threading.Thread): #数据接收进程 部分重构 global gui def __init__(self, name, lock): threading.Thread.__init__(self) self.mName = name self.mLock = lock self.mEvent = threading.Event() def run(self): #主函数 print('开启数据接收\r') while True: self.mEvent.wait() self.mLock.acquire() if UART.isOpen(): rx_buf = UART.read() if len(rx_buf) >0: rx_buf += UART.readall() #有延迟但不易出错 gui.tx_rx_cnt(rx=len(rx_buf)) if gui.ascii_hex_get() == False: print('收到hex数据', rx_buf.hex().upper()) gui.txt_rx.insert(END, rx_buf.hex().upper()) else: str_data = str(rx_buf, encoding='gb2312') print("串口收到消息:", len(rx_buf), str_data) gui.txt_rx.insert(END,str_data) # self.txt_rx.insert(END,str_data) self.mLock.release() #time.sleep(3) def pause(self): #暂停 self.mEvent.clear() def resume(self):#恢复 self.mEvent.set() '''GUI''''''''''''''''''''''''''''''''''''''''''''''''''''''''' class GUI: def __init__(self): self.root = Tk() self.root.title('梵德觅串口调试助手') #窗口名称 self.root.geometry("800x360+500+150") #尺寸位置 self.interface() Style(theme='pulse') #主题修改 可选['cyborg', 'journal', 'darkly', 'flatly' 'solar', 'minty', 'litera', 'united', 'pulse', 'cosmo', 'lumen', 'yeti', 'superhero','sandstone'] def interface(self): """"界面编写位置""" #--------------------------------操作区域-----------------------------# self.fr1=Frame(self.root) self.fr1.place(x=0,y=0,width=180,height=360) #区域1位置尺寸 self.lb1 =Label(self.fr1, text='端口号:',font="微软雅黑",fg='red') #点击可刷新 self.lb1.place(x=0,y=5,width=100,height=35) self.var_cb1 = StringVar() self.comb1 = Combobox(self.fr1,textvariable=self.var_cb1) self.comb1['values'] = list(serial.tools.list_ports.comports()) #列出可用串口 self.comb1.current(0) # 设置默认选项 0开始 self.comb1.place(x=10,y=40,width=150,height=30) com=list(serial.tools.list_ports.comports()) print('**********可用串口***********') for i in range(0, len(com)): print(com[i]) print('***************************') self.lb2 = Label(self.fr1, text='波特率:') self.comb2 = Combobox(self.fr1,values=['2400','9600','57600','115200']) self.comb2.current(3) #设置默认选项 115200 self.lb2.place(x=5,y=75,width=60,height=20) self.comb2.place(x=10,y=100,width=100,height=25) self.var_bt1 = StringVar() self.var_bt1.set("打开串口") self.btn1 = Button(self.fr1,textvariable=self.var_bt1,command=self.uart_opn_close) #绑定 uart_opn_close 方法 self.btn1.place(x=10,y=140,width=60,height=30) self.var_cs = IntVar() #定义返回类型 self.rd1 = Radiobutton(self.fr1,text="Ascii",variable=self.var_cs,value=0,command = self.txt_clr) #选择后清除显示内容 self.rd2 = Radiobutton(self.fr1,text="Hex",variable=self.var_cs,value=1,command = self.txt_clr) self.rd1.place(x=5,y=180,width=60,height=30) self.rd2.place(x=5,y=210,width=60,height=30) self.btn3 = Button(self.fr1, text='清空',command = self.txt_clr) #绑定清空方法 self.btn4 = Button(self.fr1, text='保存',command=self.savefiles) #绑定保存方法 self.btn3.place(x=10,y=260,width=60,height=30) self.btn4.place(x=100,y=260,width=60,height=30) self.btn5 = Button(self.fr1, text='功能',command=self.ascii_hex_get) #测试用 self.btn6 = Button(self.fr1, text='发送',command=self.uart_send) #绑定发送方法 self.btn5.place(x=10,y=315,width=60,height=30) self.btn6.place(x=100,y=315,width=60,height=30) #-------------------------------文本区域-----------------------------# self.fr2=Frame(self.root) #区域1 容器 relief groove=凹 ridge=凸 self.fr2.place(x=180,y=0,width=620,height=360) #区域1位置尺寸 self.txt_rx = Text(self.fr2) self.txt_rx.place(relheight=0.6,relwidth=0.9,relx=0.05,rely=0.01) #比例计算控件尺寸和位置 self.txt_tx = Text(self.fr2) self.txt_tx.place(relheight=0.25,relwidth=0.9,relx=0.05,rely=0.66) #比例计算控件尺寸位置 self.lb3 =Label(self.fr2, text='接收:0 发送:0',bg="yellow",anchor='w') #字节统计 self.lb3.place(relheight=0.05,relwidth=0.3,relx=0.045,rely=0.925) self.lb4 = Label(self.fr2, text=' ', anchor='w',relief=GROOVE) #时钟 self.lb4.place(relheight=0.05, relwidth=0.1, relx=0.85, rely=0.935) #------------------------------------------方法----------------------------------------------- def gettim(self):#获取时间 未用 timestr = time.strftime("%H:%M:%S") # 获取当前的时间并转化为字符串 self.lb4.configure(text=timestr) # 重新设置标签文本 # tim_str = str(datetime.datetime.now()) + '\n' # self.lb4['text'] = tim_str self.txt_rx.after(1000, self.gettim) # 每隔1s调用函数 gettime 自身获取时间 GUI自带的定时函数 def txt_clr(self):#清空显示 self.txt_rx.delete(0.0, 'end') # 清空文本框 self.txt_tx.delete(0.0, 'end') # 清空文本框 def ascii_hex_get(self):#获取单选框状态 if(self.var_cs.get()): return False else: return True def uart_opn_close(self):#打开关闭串口 if(self.var_bt1.get() == '打开串口'): if(uart_open_close(1,str(self.comb1.get())[0:5],self.comb2.get())==True): #传递下拉框选择的参数 COM号+波特率 【0:5】表示只提取COM号字符 self.var_bt1.set('关闭串口') #改变按键内容 self.txt_rx.insert(0.0, self.comb1.get() + ' 打开成功\r\n') # 开头插入 else: print("串口打开失败") messagebox.showinfo('错误','串口打开失败') else: uart_open_close(0, 'COM1', 115200) #关闭时参数无效 self.var_bt1.set('打开串口') def uart_send(self): #发送数据 send_data = self.txt_tx.get(0.0, 'end').strip() if self.ascii_hex_get(): #字符发送 uart_tx(send_data) else: send_data = send_data.replace(" ", "").replace("\n", "0A").replace("\r", "0D") #替换空格和回车换行 if(ISHEX(send_data)==False): messagebox.showinfo('错误', '请输入十六进制数') return uart_tx(send_data,True) def tx_rx_cnt(self,rx=0,tx=0): #发送接收统计 global tx_cnt global rx_cnt rx_cnt += rx tx_cnt += tx self.lb3['text'] = '接收:'+str(rx_cnt),'发送:'+str(tx_cnt) def savefiles(self): #保存日志TXT文本 try: with open('log.txt','a') as file: #a方式打开 文本追加模式 file.write(self.txt_rx.get(0.0,'end')) messagebox.showinfo('提示', '保存成功') except: messagebox.showinfo('错误', '保存日志文件失败!') if __name__ == '__main__': print('Star...') gui = GUI() gui.gettim() #开启时钟 gui.root.mainloop() UART.close() #结束关闭 避免下次打开错误 print('End...')


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有