串口调试工具(Python2.7+pyserial+Tkinter)

时间:2021-02-22 06:16:24

需要与串口设备进行通讯,那么一个调试工具是必须的。

根据我自己的需要,写了个简易版本的串口调试工具:

预览图:

串口调试工具(Python2.7+pyserial+Tkinter)

======================

项目结构:

COM

--SerialHelper.py

UI

--Adaptive.py

--SerialTool.py

--PyTkinter.py

main.py

======================

COM文件夹

SerialHelper.py 串口通讯帮助类

 #! /usr/bin/env python
# -*- coding: utf-8 -*- '''
Serial设备通讯帮助类
'''
__author__ = "jakey.chen"
__version__ = "v1.0" import sys
import threading
import time
import serial
import binascii
import logging class SerialHelper(object):
def __init__(self, Port="COM6", BaudRate="", ByteSize="", Parity="N", Stopbits=""):
'''
初始化一些参数
'''
self.l_serial = None
self.alive = False
self.port = Port
self.baudrate = BaudRate
self.bytesize = ByteSize
self.parity = Parity
self.stopbits = Stopbits
self.thresholdValue = 64
self.receive_data = "" def start(self):
'''
开始,打开串口
'''
self.l_serial = serial.Serial()
self.l_serial.port = self.port
self.l_serial.baudrate = self.baudrate
self.l_serial.bytesize = int(self.bytesize)
self.l_serial.parity = self.parity
self.l_serial.stopbits = int(self.stopbits)
self.l_serial.timeout = 2 try:
self.l_serial.open()
if self.l_serial.isOpen():
self.alive = True
except Exception as e:
self.alive = False
logging.error(e) def stop(self):
'''
结束,关闭串口
'''
self.alive = False
if self.l_serial.isOpen():
self.l_serial.close() def read(self):
'''
循环读取串口发送的数据
'''
while self.alive:
try:
number = self.l_serial.inWaiting()
if number:
self.receive_data += self.l_serial.read(number).replace(binascii.unhexlify(""), "")
if self.thresholdValue <= len(self.receive_data):
self.receive_data = ""
except Exception as e:
logging.error(e) def write(self, data, isHex=False):
'''
发送数据给串口设备
'''
if self.alive:
if self.l_serial.isOpen():
if isHex:
# data = data.replace(" ", "").replace("\n", "")
data = binascii.unhexlify(data)
self.l_serial.write(data) if __name__ == '__main__':
import threading
ser = SerialHelper()
ser.start() ser.write("", isHex=False)
thread_read = threading.Thread(target=ser.read)
thread_read.setDaemon(True)
thread_read.start()
import time
time.sleep(25)
ser.stop()

======================

UI文件夹

Adaptive.py 防止错位

 #! /usr/bin/env python
# -*- coding: utf-8 -*- import platform g_systemName = platform.system()
g_systemInfo = platform.platform()
g_pyVersion = platform.python_version()
size_dict = dict() # System will be Linux and python == 2.7
if g_systemName == "Linux" and g_pyVersion[:3] == "2.7":
if "Ubuntu" in g_systemInfo:
size_dict = {
"list_box_height": 20,
"send_text_height": 12,
"receive_text_height": 15,
"reset_label_width": 24,
"clear_label_width": 22
} # raspberry pi
elif "armv6l" in g_systemInfo:
size_dict = {
"list_box_height": 19,
"send_text_height": 12,
"receive_text_height": 15,
"reset_label_width": 24,
"clear_label_width": 22
}
else:
if g_systemInfo[:9]== "Windows-8":
size_dict = {
"list_box_height": 14,
"send_text_height": 6,
"receive_text_height": 18,
"reset_label_width": 7,
"clear_label_width": 5
} elif g_systemInfo[:9]== "Windows-7":
size_dict = {
"list_box_height": 13,
"send_text_height": 12,
"receive_text_height": 15,
"reset_label_width": 7,
"clear_label_width": 5
} elif g_systemInfo[:10]== "Windows-XP":
size_dict = {
"list_box_height": 20,
"send_text_height": 12,
"receive_text_height": 22,
"reset_label_width": 7,
"clear_label_width": 5
} # font
monaco_font = ('Monaco', 12)

PyTkinter.py 根据个人喜好来初始化一些Tkinter控件的颜色配置

 #! /usr/bin/env python
# -*- coding: utf-8 -*- '''
Tkinter控件初始化配置(默认为深色)
'''
__author__ = "jakey.chen"
__version__ = "v1.0" import Tkinter as tk g_default_theme = "dark"
# g_default_theme = "default" class PyButton(tk.Button):
'''
Button
'''
def __init__(self, master, theme=g_default_theme, **kv):
self.theme = theme
self.kv = kv
self.temp = dict()
self.choose_theme()
tk.Button.__init__(self, master, self.temp) def choose_theme(self):
if self.theme == "dark":
dark_theme_dict = {
"activebackground": "#00B2EE",
"activeforeground": "#E0EEEE",
"bg": "#008B8B",
"fg": "#FFFFFF"
}
for key,value in dark_theme_dict.items():
self.temp[key] = value for key,value in self.kv.items():
self.temp[key] = value class PyLabel(tk.Label):
'''
Label
'''
def __init__(self, master, theme=g_default_theme, **kv):
self.theme = theme
self.kv = kv
self.temp = dict()
self.choose_theme()
tk.Label.__init__(self, master, self.temp) def choose_theme(self):
if self.theme == "dark":
dark_theme_dict = {
"bg": "#292929",
"fg": "#E0EEEE"
}
for key,value in dark_theme_dict.items():
self.temp[key] = value for key,value in self.kv.items():
self.temp[key] = value class PyLabelFrame(tk.LabelFrame):
'''
Frame
'''
def __init__(self, master, theme=g_default_theme, **kv):
self.theme = theme
self.kv = kv
self.temp = dict()
self.choose_theme()
tk.LabelFrame.__init__(self, master, self.temp) def choose_theme(self):
if self.theme == "dark":
dark_theme_dict = {
"bg": "#292929",
"fg": "#1E90FF"
}
for key,value in dark_theme_dict.items():
self.temp[key] = value for key,value in self.kv.items():
self.temp[key] = value class PyListbox(tk.Listbox):
'''
Listbox
'''
def __init__(self, master, theme=g_default_theme, **kv):
self.theme = theme
self.kv = kv
self.temp = dict()
self.choose_theme()
tk.Listbox.__init__(self, master, self.temp) def choose_theme(self):
if self.theme == "dark":
dark_theme_dict = {
"bg": "#292929",
"fg": "#1E90FF",
"selectbackground": "#00B2EE"
}
for key,value in dark_theme_dict.items():
self.temp[key] = value for key,value in self.kv.items():
self.temp[key] = value class PyText(tk.Text):
'''
Text
'''
def __init__(self, master, theme=g_default_theme, **kv):
self.theme = theme
self.kv = kv
self.temp = dict()
self.choose_theme()
tk.Text.__init__(self, master, self.temp) def choose_theme(self):
if self.theme == "dark":
dark_theme_dict = {
"bg": "#292929",
"fg": "#1E90FF"
}
for key,value in dark_theme_dict.items():
self.temp[key] = value for key,value in self.kv.items():
self.temp[key] = value class PyCheckbutton(tk.Checkbutton):
'''
Checkbutton
'''
def __init__(self, master, theme=g_default_theme, **kv):
self.theme = theme
self.kv = kv
self.temp = dict()
self.choose_theme()
tk.Checkbutton.__init__(self, master, self.temp) def choose_theme(self):
if self.theme == "dark":
dark_theme_dict = {
"bg": "#292929",
"fg": "#FFFFFF",
"activebackground": "#292929",
"activeforeground": "#FFFFFF",
"selectcolor": "#292929"
}
for key,value in dark_theme_dict.items():
self.temp[key] = value for key,value in self.kv.items():
self.temp[key] = value class PyRadiobutton(tk.Radiobutton):
'''
Radiobutton
'''
def __init__(self, master, theme=g_default_theme, **kv):
self.theme = theme
self.kv = kv
self.temp = dict()
self.choose_theme()
tk.Radiobutton.__init__(self, master, self.temp) def choose_theme(self):
if self.theme == "dark":
dark_theme_dict = {
"bg": "#292929",
"fg": "#FFFFFF",
"activebackground": "#292929",
"selectcolor": "#292929"
}
for key,value in dark_theme_dict.items():
self.temp[key] = value for key,value in self.kv.items():
self.temp[key] = value class PyEntry(tk.Entry):
'''
Entry
'''
def __init__(self, master, theme=g_default_theme, **kv):
self.theme = theme
self.kv = kv
self.temp = dict()
self.choose_theme()
tk.Entry.__init__(self, master, self.temp) def choose_theme(self):
if self.theme == "dark":
dark_theme_dict = {
"bg": "#292929",
"fg": "#E0EEEE",
"insertbackground": "#E0EEEE"
}
for key,value in dark_theme_dict.items():
self.temp[key] = value for key,value in self.kv.items():
self.temp[key] = value if __name__ == '__main__':
root = tk.Tk()
root.configure(bg="#292929")
PyButton(root, text="", font=("Monaco", 12)).pack()
PyLabel(root, text="", font=("Monaco", 15)).pack()
PyCheckbutton(root, text="", font=("Monaco", 15)).pack()
PyEntry(root, font=("Monaco", 15)).pack()
PyText(root, font=("Monaco", 15), height=2, width=20).pack()
listbox_0 = PyListbox(root, height=2, font=("Monaco", 15))
listbox_0.pack()
for i in range(2):
listbox_0.insert("end", i)
radio_intvar = tk.IntVar()
PyRadiobutton(root, text="", variable=radio_intvar, value=0, font=("Monaco", 15)).pack()
PyRadiobutton(root, text="", variable=radio_intvar, value=1, font=("Monaco", 15)).pack()
radio_intvar.set(1) root.mainloop()

SerialTool.py 主界面

 #! /usr/bin/env python
# -*- coding: utf-8 -*- import Tkinter as tk
import ttk
import PyTkinter as pytk
import Adaptive font = Adaptive.monaco_font
size_dict = Adaptive.size_dict
g_default_theme = pytk.g_default_theme class SerialToolUI(object):
def __init__(self, master=None):
self.root = master
self.create_frame()
self.thresholdValue = 1 def create_frame(self):
'''
新建窗口,分为上下2个部分,下半部分为状态栏
'''
self.frm = pytk.PyLabelFrame(self.root)
self.frm_status = pytk.PyLabelFrame(self.root) self.frm.grid(row=0, column=0, sticky="wesn")
self.frm_status.grid(row=1, column=0, sticky="wesn") self.create_frm()
self.create_frm_status() def create_frm(self):
'''
上半部分窗口分为左右2个部分
'''
self.frm_left = pytk.PyLabelFrame(self.frm)
self.frm_right = pytk.PyLabelFrame(self.frm) self.frm_left.grid(row=0, column=0, padx=5, pady=5, sticky="wesn")
self.frm_right.grid(row=0, column=1, padx=5, pady=5, sticky="wesn") self.create_frm_left()
self.create_frm_right() def create_frm_left(self):
'''
上半部分左边窗口:
Listbox显示可用的COM口
Button按钮点击连接设备
'''
self.frm_left_label = pytk.PyLabel(self.frm_left,
text="Serial Ports",
font=font)
self.frm_left_listbox = pytk.PyListbox(self.frm_left,
height=size_dict["list_box_height"],
font=font)
self.frm_left_serial_set = pytk.PyLabelFrame(self.frm_left)
self.frm_left_btn = pytk.PyButton(self.frm_left,
text="Open",
font=font,
command=self.Toggle) self.frm_left_label.grid(row=0, column=0, padx=5, pady=5, sticky="w")
self.frm_left_listbox.grid(row=1, column=0, padx=5, pady=5, sticky="wesn")
self.frm_left_serial_set.grid(row=2, column=0, padx=5, pady=5, sticky="wesn")
self.frm_left_btn.grid(row=3, column=0, padx=5, pady=5, sticky="wesn") self.frm_left_listbox.bind("<Double-Button-1>", self.Open)
self.create_frm_left_serial_set() def create_frm_left_serial_set(self):
'''
串口配置,比如波特率,奇偶校验等
'''
setting_label_list = ["BaudRate :", "Parity :", "DataBit :", "StopBit :"]
baudrate_list = ["", "", "", "", "", "", "",
"", "", "", "", ""]
# PARITY_NONE, PARITY_EVEN, PARITY_ODD PARITY_MARK, PARITY_SPACE
parity_list = ["N", "E", "O", "M", "S"]
bytesize_list = ["", "", "", ""]
stopbits_list = ["", "1.5", ""]
for index,item in enumerate(setting_label_list):
frm_left_label_temp = pytk.PyLabel(self.frm_left_serial_set,
text=item,
font=('Monaco', 10))
frm_left_label_temp.grid(row=index, column=0, padx=1, pady=2, sticky="e")
self.frm_left_combobox_baudrate = ttk.Combobox(self.frm_left_serial_set,
width=15,
values=baudrate_list)
self.frm_left_combobox_parity = ttk.Combobox(self.frm_left_serial_set,
width=15,
values=parity_list)
self.frm_left_combobox_databit = ttk.Combobox(self.frm_left_serial_set,
width=15,
values=bytesize_list)
self.frm_left_combobox_stopbit = ttk.Combobox(self.frm_left_serial_set,
width=15,
values=stopbits_list)
self.frm_left_combobox_baudrate.grid(row=0, column=1, padx=2, pady=2, sticky="e")
self.frm_left_combobox_parity.grid(row=1, column=1, padx=2, pady=2, sticky="e")
self.frm_left_combobox_databit.grid(row=2, column=1, padx=2, pady=2, sticky="e")
self.frm_left_combobox_stopbit.grid(row=3, column=1, padx=2, pady=2, sticky="e") self.frm_left_combobox_baudrate.current(3)
self.frm_left_combobox_parity.current(0)
self.frm_left_combobox_databit.current(3)
self.frm_left_combobox_stopbit.current(0) def create_frm_right(self):
'''
上半部分右边窗口:
分为4个部分:
1、Label显示和重置按钮和发送按钮
2、Text显示(发送的数据)
3、Label显示和十六进制选择显示和清除接收信息按钮
4、Text显示接收到的信息
'''
self.frm_right_reset = pytk.PyLabelFrame(self.frm_right)
self.frm_right_send = pytk.PyText(self.frm_right,
width=50,
height=size_dict["send_text_height"],
font=("Monaco", 9))
self.frm_right_clear = pytk.PyLabelFrame(self.frm_right)
self.frm_right_receive = pytk.PyText(self.frm_right,
width=50,
height=size_dict["receive_text_height"],
font=("Monaco", 9)) self.frm_right_reset.grid(row=0, column=0, padx=1, sticky="wesn")
self.frm_right_send.grid(row=1, column=0, padx=1, sticky="wesn")
self.frm_right_clear.grid(row=2, column=0, padx=1, sticky="wesn")
self.frm_right_receive.grid(row=3, column=0, padx=1, sticky="wesn") self.frm_right_receive.tag_config("green", foreground="#228B22") self.create_frm_right_reset()
self.create_frm_right_clear() def create_frm_right_reset(self):
'''
1、Label显示和重置按钮和发送按钮
'''
self.frm_right_reset_label = pytk.PyLabel(self.frm_right_reset,
text="Data Send" + " "*size_dict["reset_label_width"],
font=font)
self.new_line_cbtn_var = tk.IntVar()
self.send_hex_cbtn_var = tk.IntVar()
self.frm_right_reset_newLine_checkbtn = pytk.PyCheckbutton(self.frm_right_reset,
text="New Line",
variable=self.new_line_cbtn_var,
font=font)
self.frm_right_reset_hex_checkbtn = pytk.PyCheckbutton(self.frm_right_reset,
text="Hex",
variable=self.send_hex_cbtn_var,
font=font)
self.frm_right_reset_btn = pytk.PyButton(self.frm_right_reset,
text="Reset",
width=10,
font=font,
command=self.Reset)
self.frm_right_send_btn = pytk.PyButton(self.frm_right_reset,
text="Send",
width=10,
font=font,
command=self.Send) self.frm_right_reset_label.grid(row=0, column=0, sticky="w")
self.frm_right_reset_newLine_checkbtn.grid(row=0, column=1, sticky="wesn")
self.frm_right_reset_hex_checkbtn.grid(row=0, column=2, sticky="wesn")
self.frm_right_reset_btn.grid(row=0, column=3, padx=5, pady=5, sticky="wesn")
self.frm_right_send_btn.grid(row=0, column=4, padx=5, pady=5, sticky="wesn") def create_frm_right_clear(self):
'''
3、Label显示和十六进制显示和清除接收信息按钮
'''
self.receive_hex_cbtn_var = tk.IntVar()
self.frm_right_clear_label = pytk.PyLabel(self.frm_right_clear,
text="Data Received"+ " "*size_dict["clear_label_width"],
font=font)
self.frm_right_threshold_label = pytk.PyLabel(self.frm_right_clear,
text="Threshold:",
font=font)
self.thresholdStr = tk.StringVar()
self.frm_right_threshold_entry = pytk.PyEntry(self.frm_right_clear,
textvariable=self.thresholdStr,
width=6,
font=font)
self.frm_right_hex_checkbtn = pytk.PyCheckbutton(self.frm_right_clear,
text="Hex",
variable=self.receive_hex_cbtn_var,
relief="flat",
font=font)
self.frm_right_clear_btn = pytk.PyButton(self.frm_right_clear,
text="Clear",
width=10,
font=font,
command=self.Clear) self.frm_right_clear_label.grid(row=0, column=0, padx=5, pady=5, sticky="w")
self.frm_right_threshold_label.grid(row=0, column=1, padx=5, pady=5, sticky="wesn")
self.frm_right_threshold_entry.grid(row=0, column=2, padx=5, pady=5, sticky="wesn")
self.frm_right_hex_checkbtn.grid(row=0, column=3, padx=5, pady=5, sticky="wesn")
self.frm_right_clear_btn.grid(row=0, column=4, padx=5, pady=5, sticky="wesn") self.thresholdStr.set(1)
self.thresholdStr.trace('w', self.GetThresholdValue) def create_frm_status(self):
'''
下半部分状态栏窗口
'''
self.frm_status_label = pytk.PyLabel(self.frm_status,
text="Ready",
font=font)
self.frm_status_label.grid(row=0, column=0, padx=5, pady=5, sticky="wesn") def Toggle(self):
pass def Open(self, event):
pass def Reset(self):
self.frm_right_send.delete("0.0", "end") def Send(self):
pass def Clear(self):
self.frm_right_receive.delete("0.0", "end") def GetThresholdValue(self, *args):
try:
self.thresholdValue = int(self.thresholdStr.get())
except:
pass if __name__ == '__main__':
'''
main loop
'''
root = tk.Tk()
if g_default_theme == "dark":
root.configure(bg="#292929")
combostyle = ttk.Style()
combostyle.theme_use('alt')
combostyle.configure("TCombobox", selectbackground="#292929", fieldbackground="#292929",
background="#292929", foreground="#FFFFFF")
root.title("Serial-Tool")
SerialToolUI(master=root)
root.resizable(False, False)
root.mainloop()

======================

界面逻辑主程序

main.py

 #! /usr/bin/env python
# -*- coding: utf-8 -*- import time
import datetime
import threading
import binascii
import platform
import logging from UI import SerialTool
from COM import SerialHelper if platform.system() == "Windows":
from serial.tools import list_ports
elif platform.system() == "Linux":
import glob, os, re import Tkinter as tk
import ttk logging.basicConfig(level=logging.DEBUG,
format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s',
datefmt='%a, %d %b %Y %H:%M:%S') class MainSerialToolUI(SerialTool.SerialToolUI):
def __init__(self, master=None):
super(MainSerialToolUI, self).__init__()
self.ser = None
self.receive_count = 0
self.receive_data = ""
self.list_box_serial = list()
self.find_all_serial() def __del__(self):
if platform.system() == "Linux":
try:
self.ser.SetStopEvent()
except:
pass def find_all_serial(self):
'''
获取到串口列表
'''
if platform.system() == "Windows":
try:
self.temp_serial = list()
for com in list_ports.comports():
strCom = com[0] + ": " + com[1][:-7].decode("gbk").encode("utf-8")
self.temp_serial.append(strCom)
for item in self.temp_serial:
if item not in self.list_box_serial:
self.frm_left_listbox.insert("end", item)
for item in self.list_box_serial:
if item not in self.temp_serial:
index = list(self.frm_left_listbox.get(0, self.frm_left_listbox.size())).index(item)
self.frm_left_listbox.delete(index) self.list_box_serial = self.temp_serial self.thread_findserial = threading.Timer(1, self.find_all_serial)
self.thread_findserial.setDaemon(True)
self.thread_findserial.start()
except Exception as e:
logging.error(e)
elif platform.system() == "Linux":
try:
self.temp_serial = list()
self.temp_serial = self.find_usb_tty()
for item in self.temp_serial:
if item not in self.list_box_serial:
self.frm_left_listbox.insert("end", item)
for item in self.list_box_serial:
if item not in self.temp_serial:
index = list(self.frm_left_listbox.get(0, self.frm_left_listbox.size())).index(item)
self.frm_left_listbox.delete(index)
self.list_box_serial = self.temp_serial self.thread_findserial = threading.Timer(1, self.find_all_serial)
self.thread_findserial.setDaemon(True)
self.thread_findserial.start()
except Exception as e:
logging.error(e) def Toggle(self):
'''
打开关闭串口
'''
if self.frm_left_btn["text"] == "Open":
try:
self.currentStrCom = self.frm_left_listbox.get(self.frm_left_listbox.curselection())
if platform.system() == "Windows":
self.port = self.currentStrCom.split(":")[0]
elif platform.system() == "Linux":
self.port = self.currentStrCom
self.baudrate = self.frm_left_combobox_baudrate.get()
self.parity = self.frm_left_combobox_parity.get()
self.databit = self.frm_left_combobox_databit.get()
self.stopbit = self.frm_left_combobox_stopbit.get()
self.ser = SerialHelper.SerialHelper(Port=self.port,
BaudRate=self.baudrate,
ByteSize=self.databit,
Parity=self.parity,
Stopbits=self.stopbit)
self.ser.start()
if self.ser.alive:
self.frm_status_label["text"] = "Open [{0}] Successful!".format(self.currentStrCom)
self.frm_status_label["fg"] = "#66CD00"
self.frm_left_btn["text"] = "Close"
self.frm_left_btn["bg"] = "#F08080" self.thread_read = threading.Thread(target=self.SerialRead)
self.thread_read.setDaemon(True)
self.thread_read.start() except Exception as e:
logging.error(e)
try:
self.frm_status_label["text"] = "Open [{0}] Failed!".format(self.currentStrCom)
self.frm_status_label["fg"] = "#DC143C"
except Exception as ex:
logging.error(ex) elif self.frm_left_btn["text"] == "Close":
try:
self.ser.stop()
self.receive_count = 0
except Exception as e:
logging.error(e)
self.frm_left_btn["text"] = "Open"
self.frm_left_btn["bg"] = "#008B8B"
self.frm_status_label["text"] = "Close Serial Successful!"
self.frm_status_label["fg"] = "#8DEEEE" def Open(self, event):
'''
双击列表打开/关闭串口
'''
self.Toggle() def Clear(self):
self.frm_right_receive.delete("0.0", "end")
self.receive_count = 0 def Send(self):
'''
向已打开的串口发送数据
如果为Hex发送,示例:"31 32 33" [即为字符串 "123"]
'''
if self.ser:
try:
# 发送新行
if self.new_line_cbtn_var.get() == 0:
send_data = str(self.frm_right_send.get("0.0", "end").encode("gbk")).strip()
else:
send_data = str(self.frm_right_send.get("0.0", "end")).strip() + "\r\n" # 是否十六进制发送
if self.send_hex_cbtn_var.get() == 1:
self.ser.write(send_data, isHex=True)
else:
self.ser.write(send_data)
except Exception as e:
self.frm_right_receive.insert("end", str(e) + "\n")
logging.error(e) def SerialRead(self):
'''
线程读取串口发送的数据
'''
while self.ser.alive:
try:
n = self.ser.l_serial.inWaiting()
if n:
self.receive_data += self.ser.l_serial.read(n).replace(binascii.unhexlify(""), "")
if self.thresholdValue <= len(self.receive_data):
self.receive_count += 1 # 接收显示是否为Hex
if self.receive_hex_cbtn_var.get() == 1:
self.receive_data = self.space_b2a_hex(self.receive_data)
self.frm_right_receive.insert("end", "[" + str(datetime.datetime.now()) + " - "
+ str(self.receive_count) + "]:\n", "green")
self.frm_right_receive.insert("end", self.receive_data + "\n")
self.frm_right_receive.see("end")
self.receive_data = "" except Exception as e:
logging.error(e)
self.receive_data = ""
self.ser.stop()
self.ser = None def find_usb_tty(self, vendor_id=None, product_id=None):
'''
发现串口设备
'''
tty_devs = list()
for dn in glob.glob('/sys/bus/usb/devices/*') :
try:
vid = int(open(os.path.join(dn, "idVendor" )).read().strip(), 16)
pid = int(open(os.path.join(dn, "idProduct")).read().strip(), 16)
if ((vendor_id is None) or (vid == vendor_id)) and ((product_id is None) or (pid == product_id)) :
dns = glob.glob(os.path.join(dn, os.path.basename(dn) + "*"))
for sdn in dns :
for fn in glob.glob(os.path.join(sdn, "*")) :
if re.search(r"\/ttyUSB[0-9]+$", fn) :
tty_devs.append(os.path.join("/dev", os.path.basename(fn)))
except Exception as ex:
pass
return tty_devs def space_b2a_hex(self, data):
'''
格式化接收到的数据字符串
示例:123 --> 31 32 33
'''
new_data_list = list()
new_data = "" hex_data = binascii.b2a_hex(data)
temp_data = ""
for index,value in enumerate(hex_data):
temp_data += value
if len(temp_data) == 2:
new_data_list.append(temp_data)
temp_data = ""
for index,value in enumerate(new_data_list):
if index%25 == 0 and index != 0:
new_data += "\n"
new_data += value
new_data += " " return new_data if __name__ == '__main__':
'''
main loop
'''
root = tk.Tk()
root.title("Serial Tool")
if SerialTool.g_default_theme == "dark":
root.configure(bg="#292929")
combostyle = ttk.Style()
combostyle.theme_use('alt')
combostyle.configure("TCombobox", selectbackground="#292929", fieldbackground="#292929",
background="#292929", foreground="#FFFFFF")
MainSerialToolUI(master=root)
root.resizable(False, False)
root.mainloop()

项目地址:Serial-Tool

仅根据自己需要写的串口工具,需要其他功能的话请自行添加,或者告知我添加。