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

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

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

预览图:

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

项目结构:

COM

--SerialHelper.py

UI

--Adaptive.py

--SerialTool.py

--PyTkinter.py

main.py

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

COM文件夹

SerialHelper.py 串口通讯帮助类

 1 #! /usr/bin/env python

 2 # -*- coding: utf-8 -*-

 3 

 4 '''

 5 Serial设备通讯帮助类

 6 '''

 7 __author__ = "jakey.chen"

 8 __version__ = "v1.0"

 9 

10 import sys

11 import threading

12 import time

13 import serial

14 import binascii

15 import logging

16 

17 class SerialHelper(object):

18     def __init__(self, Port="COM6", BaudRate="9600", ByteSize="8", Parity="N", Stopbits="1"):

19         '''

20         初始化一些参数

21         '''

22         self.l_serial = None

23         self.alive = False

24         self.port = Port

25         self.baudrate = BaudRate

26         self.bytesize = ByteSize

27         self.parity = Parity

28         self.stopbits = Stopbits

29         self.thresholdValue = 64

30         self.receive_data = ""

31 

32     def start(self):

33         '''

34         开始,打开串口

35         '''

36         self.l_serial = serial.Serial()

37         self.l_serial.port = self.port

38         self.l_serial.baudrate = self.baudrate

39         self.l_serial.bytesize = int(self.bytesize)

40         self.l_serial.parity = self.parity

41         self.l_serial.stopbits = int(self.stopbits)

42         self.l_serial.timeout = 2

43         

44         try:

45             self.l_serial.open()

46             if self.l_serial.isOpen():

47                 self.alive = True

48         except Exception as e:

49             self.alive = False

50             logging.error(e)

51 

52     def stop(self):

53         '''

54         结束,关闭串口

55         '''

56         self.alive = False

57         if self.l_serial.isOpen():

58             self.l_serial.close()

59 

60     def read(self):

61         '''

62         循环读取串口发送的数据

63         '''

64         while self.alive:

65             try:

66                 number = self.l_serial.inWaiting()

67                 if number:

68                     self.receive_data += self.l_serial.read(number).replace(binascii.unhexlify("00"), "")

69                     if self.thresholdValue <= len(self.receive_data):

70                         self.receive_data = ""

71             except Exception as e:

72                 logging.error(e)

73 

74     def write(self, data, isHex=False):

75         '''

76         发送数据给串口设备

77         '''

78         if self.alive:

79             if self.l_serial.isOpen():

80                 if isHex:

81                     # data = data.replace(" ", "").replace("\n", "")

82                     data = binascii.unhexlify(data)

83                 self.l_serial.write(data)

84 

85 if __name__ == '__main__':

86     import threading

87     ser = SerialHelper()

88     ser.start()

89 

90     ser.write("123", isHex=False)

91     thread_read = threading.Thread(target=ser.read)

92     thread_read.setDaemon(True)

93     thread_read.start()

94     import time

95     time.sleep(25)

96     ser.stop()
View Code

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

UI文件夹

Adaptive.py 防止错位

 1 #! /usr/bin/env python

 2 # -*- coding: utf-8 -*-

 3 

 4 import platform

 5 

 6 g_systemName = platform.system()

 7 g_systemInfo = platform.platform()

 8 g_pyVersion = platform.python_version()

 9 size_dict = dict()

10 

11 # System will be Linux and python == 2.7

12 if g_systemName == "Linux" and g_pyVersion[:3] == "2.7":

13     if "Ubuntu" in g_systemInfo:

14         size_dict = {

15                         "list_box_height": 20,

16                         "send_text_height": 12,

17                         "receive_text_height": 15,

18                         "reset_label_width": 24,

19                         "clear_label_width": 22

20                     }

21 

22     # raspberry pi

23     elif "armv6l" in g_systemInfo:

24         size_dict = {

25                         "list_box_height": 19,

26                         "send_text_height": 12,

27                         "receive_text_height": 15,

28                         "reset_label_width": 24,

29                         "clear_label_width": 22

30                     }

31 else:

32     if g_systemInfo[:9]== "Windows-8":

33         size_dict = {

34                         "list_box_height": 14,

35                         "send_text_height": 6,

36                         "receive_text_height": 18,

37                         "reset_label_width": 7,

38                         "clear_label_width": 5

39                      }

40 

41     elif g_systemInfo[:9]== "Windows-7":

42         size_dict = {

43                         "list_box_height": 13,

44                         "send_text_height": 12,

45                         "receive_text_height": 15,

46                         "reset_label_width": 7,

47                         "clear_label_width": 5

48                      }

49 

50     elif g_systemInfo[:10]== "Windows-XP":

51         size_dict = {

52                         "list_box_height": 20,

53                         "send_text_height": 12,

54                         "receive_text_height": 22,

55                         "reset_label_width": 7,

56                         "clear_label_width": 5

57                      }

58 

59 # font

60 monaco_font = ('Monaco', 12)
View Code

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

  1 #! /usr/bin/env python

  2 # -*- coding: utf-8 -*-

  3 

  4 '''

  5 Tkinter控件初始化配置(默认为深色)

  6 '''

  7 __author__ = "jakey.chen"

  8 __version__ = "v1.0"

  9 

 10 

 11 import Tkinter as tk

 12 

 13 g_default_theme = "dark"

 14 # g_default_theme = "default"

 15 

 16 class PyButton(tk.Button):

 17     '''

 18     Button

 19     '''

 20     def __init__(self, master, theme=g_default_theme, **kv):

 21         self.theme = theme

 22         self.kv = kv

 23         self.temp = dict()

 24         self.choose_theme()

 25         tk.Button.__init__(self, master, self.temp)

 26 

 27     def choose_theme(self):

 28         if self.theme == "dark":

 29             dark_theme_dict = {

 30                                 "activebackground": "#00B2EE",

 31                                 "activeforeground": "#E0EEEE",

 32                                 "bg": "#008B8B",

 33                                 "fg": "#FFFFFF"

 34                               }

 35             for key,value in dark_theme_dict.items():

 36                 self.temp[key] = value

 37 

 38             for key,value in self.kv.items():

 39                 self.temp[key] = value

 40 

 41 class PyLabel(tk.Label):

 42     '''

 43     Label

 44     '''

 45     def __init__(self, master, theme=g_default_theme, **kv):

 46         self.theme = theme

 47         self.kv = kv

 48         self.temp = dict()

 49         self.choose_theme()

 50         tk.Label.__init__(self, master, self.temp)

 51 

 52     def choose_theme(self):

 53         if self.theme == "dark":

 54             dark_theme_dict = {

 55                                 "bg": "#292929",

 56                                 "fg": "#E0EEEE"

 57                               }

 58             for key,value in dark_theme_dict.items():

 59                 self.temp[key] = value

 60 

 61             for key,value in self.kv.items():

 62                 self.temp[key] = value

 63 

 64 class PyLabelFrame(tk.LabelFrame):

 65     '''

 66     Frame

 67     '''

 68     def __init__(self, master, theme=g_default_theme, **kv):

 69         self.theme = theme

 70         self.kv = kv

 71         self.temp = dict()

 72         self.choose_theme()

 73         tk.LabelFrame.__init__(self, master, self.temp)

 74 

 75     def choose_theme(self):

 76         if self.theme == "dark":

 77             dark_theme_dict = {

 78                                 "bg": "#292929",

 79                                 "fg": "#1E90FF"

 80                               }

 81             for key,value in dark_theme_dict.items():

 82                 self.temp[key] = value

 83 

 84             for key,value in self.kv.items():

 85                 self.temp[key] = value

 86 

 87 class PyListbox(tk.Listbox):

 88     '''

 89     Listbox

 90     '''

 91     def __init__(self, master, theme=g_default_theme, **kv):

 92         self.theme = theme

 93         self.kv = kv

 94         self.temp = dict()

 95         self.choose_theme()

 96         tk.Listbox.__init__(self, master, self.temp)

 97 

 98     def choose_theme(self):

 99         if self.theme == "dark":

100             dark_theme_dict = {

101                                 "bg": "#292929",

102                                 "fg": "#1E90FF",

103                                 "selectbackground": "#00B2EE"

104                               }

105             for key,value in dark_theme_dict.items():

106                 self.temp[key] = value

107 

108             for key,value in self.kv.items():

109                 self.temp[key] = value

110 

111 class PyText(tk.Text):

112     '''

113     Text

114     '''

115     def __init__(self, master, theme=g_default_theme, **kv):

116         self.theme = theme

117         self.kv = kv

118         self.temp = dict()

119         self.choose_theme()

120         tk.Text.__init__(self, master, self.temp)

121 

122     def choose_theme(self):

123         if self.theme == "dark":

124             dark_theme_dict = {

125                                 "bg": "#292929",

126                                 "fg": "#1E90FF"

127                               }

128             for key,value in dark_theme_dict.items():

129                 self.temp[key] = value

130 

131             for key,value in self.kv.items():

132                 self.temp[key] = value

133 

134 class PyCheckbutton(tk.Checkbutton):

135     '''

136     Checkbutton

137     '''

138     def __init__(self, master, theme=g_default_theme, **kv):

139         self.theme = theme

140         self.kv = kv

141         self.temp = dict()

142         self.choose_theme()

143         tk.Checkbutton.__init__(self, master, self.temp)

144 

145     def choose_theme(self):

146         if self.theme == "dark":

147             dark_theme_dict = {

148                                 "bg": "#292929",

149                                 "fg": "#FFFFFF",

150                                 "activebackground": "#292929",

151                                 "activeforeground": "#FFFFFF",

152                                 "selectcolor": "#292929"

153                               }

154             for key,value in dark_theme_dict.items():

155                 self.temp[key] = value

156 

157             for key,value in self.kv.items():

158                 self.temp[key] = value

159 

160 class PyRadiobutton(tk.Radiobutton):

161     '''

162     Radiobutton

163     '''

164     def __init__(self, master, theme=g_default_theme, **kv):

165         self.theme = theme

166         self.kv = kv

167         self.temp = dict()

168         self.choose_theme()

169         tk.Radiobutton.__init__(self, master, self.temp) 

170 

171     def choose_theme(self):

172         if self.theme == "dark":

173             dark_theme_dict = {

174                                 "bg": "#292929",

175                                 "fg": "#FFFFFF",

176                                 "activebackground": "#292929",

177                                 "selectcolor": "#292929"

178                               }

179             for key,value in dark_theme_dict.items():

180                 self.temp[key] = value

181 

182             for key,value in self.kv.items():

183                 self.temp[key] = value

184 

185 

186 class PyEntry(tk.Entry):

187     '''

188     Entry

189     '''

190     def __init__(self, master, theme=g_default_theme, **kv):

191         self.theme = theme

192         self.kv = kv

193         self.temp = dict()

194         self.choose_theme()

195         tk.Entry.__init__(self, master, self.temp)

196 

197     def choose_theme(self):

198         if self.theme == "dark":

199             dark_theme_dict = {

200                                 "bg": "#292929",

201                                 "fg": "#E0EEEE",

202                                 "insertbackground": "#E0EEEE"

203                               }

204             for key,value in dark_theme_dict.items():

205                 self.temp[key] = value

206 

207             for key,value in self.kv.items():

208                 self.temp[key] = value

209 

210 if __name__ == '__main__':

211     root = tk.Tk()

212     root.configure(bg="#292929")

213     PyButton(root, text="1234", font=("Monaco", 12)).pack()

214     PyLabel(root, text="123", font=("Monaco", 15)).pack()

215     PyCheckbutton(root, text="123", font=("Monaco", 15)).pack()

216     PyEntry(root, font=("Monaco", 15)).pack()

217     PyText(root, font=("Monaco", 15), height=2, width=20).pack()

218     listbox_0 = PyListbox(root, height=2, font=("Monaco", 15))

219     listbox_0.pack()

220     for i in range(2):

221         listbox_0.insert("end", i)

222     radio_intvar = tk.IntVar()

223     PyRadiobutton(root, text="001", variable=radio_intvar, value=0, font=("Monaco", 15)).pack()

224     PyRadiobutton(root, text="002", variable=radio_intvar, value=1, font=("Monaco", 15)).pack()

225     radio_intvar.set(1)

226 

227     root.mainloop()
View Code

SerialTool.py 主界面

  1 #! /usr/bin/env python

  2 # -*- coding: utf-8 -*-

  3 

  4 import Tkinter as tk

  5 import ttk

  6 import PyTkinter as pytk

  7 import Adaptive

  8 

  9 font = Adaptive.monaco_font

 10 size_dict = Adaptive.size_dict

 11 g_default_theme = pytk.g_default_theme

 12 

 13 

 14 class SerialToolUI(object):

 15     def __init__(self, master=None):

 16         self.root = master

 17         self.create_frame()

 18         self.thresholdValue = 1

 19 

 20     def create_frame(self):

 21         '''

 22         新建窗口,分为上下2个部分,下半部分为状态栏

 23         '''

 24         self.frm = pytk.PyLabelFrame(self.root)

 25         self.frm_status = pytk.PyLabelFrame(self.root)

 26 

 27         self.frm.grid(row=0, column=0, sticky="wesn")

 28         self.frm_status.grid(row=1, column=0, sticky="wesn")

 29 

 30         self.create_frm()

 31         self.create_frm_status()

 32 

 33     def create_frm(self):

 34         '''

 35         上半部分窗口分为左右2个部分

 36         '''

 37         self.frm_left = pytk.PyLabelFrame(self.frm)

 38         self.frm_right = pytk.PyLabelFrame(self.frm)

 39 

 40         self.frm_left.grid(row=0, column=0, padx=5, pady=5, sticky="wesn")

 41         self.frm_right.grid(row=0, column=1, padx=5, pady=5, sticky="wesn")

 42 

 43         self.create_frm_left()

 44         self.create_frm_right()

 45 

 46     def create_frm_left(self):

 47         '''

 48         上半部分左边窗口:

 49         Listbox显示可用的COM口

 50         Button按钮点击连接设备

 51         '''

 52         self.frm_left_label = pytk.PyLabel(self.frm_left, 

 53                                            text="Serial Ports",

 54                                            font=font)

 55         self.frm_left_listbox = pytk.PyListbox(self.frm_left,

 56                                                height=size_dict["list_box_height"],

 57                                                font=font)

 58         self.frm_left_serial_set = pytk.PyLabelFrame(self.frm_left)

 59         self.frm_left_btn = pytk.PyButton(self.frm_left, 

 60                                           text="Open",

 61                                           font=font,

 62                                           command=self.Toggle)

 63 

 64         self.frm_left_label.grid(row=0, column=0, padx=5, pady=5, sticky="w")

 65         self.frm_left_listbox.grid(row=1, column=0, padx=5, pady=5, sticky="wesn")

 66         self.frm_left_serial_set.grid(row=2, column=0, padx=5, pady=5, sticky="wesn")

 67         self.frm_left_btn.grid(row=3, column=0, padx=5, pady=5, sticky="wesn")

 68 

 69         self.frm_left_listbox.bind("<Double-Button-1>", self.Open)

 70         self.create_frm_left_serial_set()

 71 

 72     def create_frm_left_serial_set(self):

 73         '''

 74         串口配置,比如波特率,奇偶校验等

 75         '''

 76         setting_label_list = ["BaudRate :", "Parity :", "DataBit :", "StopBit :"]

 77         baudrate_list = ["1200", "2400", "4800", "9600", "14400", "19200", "38400",

 78                          "43000", "57600", "76800", "115200", "12800"]

 79         # PARITY_NONE, PARITY_EVEN, PARITY_ODD PARITY_MARK, PARITY_SPACE

 80         parity_list = ["N", "E", "O", "M", "S"]

 81         bytesize_list = ["5", "6", "7", "8"]

 82         stopbits_list = ["1", "1.5", "2"]

 83         for index,item in enumerate(setting_label_list):

 84             frm_left_label_temp = pytk.PyLabel(self.frm_left_serial_set, 

 85                                                text=item,

 86                                                font=('Monaco', 10))

 87             frm_left_label_temp.grid(row=index, column=0, padx=1, pady=2, sticky="e")

 88         self.frm_left_combobox_baudrate = ttk.Combobox(self.frm_left_serial_set,

 89                                                        width=15,

 90                                                        values=baudrate_list)

 91         self.frm_left_combobox_parity = ttk.Combobox(self.frm_left_serial_set,

 92                                                        width=15,

 93                                                        values=parity_list)

 94         self.frm_left_combobox_databit = ttk.Combobox(self.frm_left_serial_set,

 95                                                        width=15,

 96                                                        values=bytesize_list)

 97         self.frm_left_combobox_stopbit = ttk.Combobox(self.frm_left_serial_set,

 98                                                        width=15,

 99                                                        values=stopbits_list)

100         self.frm_left_combobox_baudrate.grid(row=0, column=1, padx=2, pady=2, sticky="e")

101         self.frm_left_combobox_parity.grid(row=1, column=1, padx=2, pady=2, sticky="e")

102         self.frm_left_combobox_databit.grid(row=2, column=1, padx=2, pady=2, sticky="e")

103         self.frm_left_combobox_stopbit.grid(row=3, column=1, padx=2, pady=2, sticky="e")

104 

105         self.frm_left_combobox_baudrate.current(3)

106         self.frm_left_combobox_parity.current(0)

107         self.frm_left_combobox_databit.current(3)

108         self.frm_left_combobox_stopbit.current(0)

109 

110     def create_frm_right(self):

111         '''

112         上半部分右边窗口:

113         分为4个部分:

114         1、Label显示和重置按钮和发送按钮

115         2、Text显示(发送的数据)

116         3、Label显示和十六进制选择显示和清除接收信息按钮

117         4、Text显示接收到的信息

118         '''

119         self.frm_right_reset = pytk.PyLabelFrame(self.frm_right)

120         self.frm_right_send = pytk.PyText(self.frm_right,

121                                           width=50, 

122                                           height=size_dict["send_text_height"],

123                                           font=("Monaco", 9))

124         self.frm_right_clear = pytk.PyLabelFrame(self.frm_right)

125         self.frm_right_receive = pytk.PyText(self.frm_right,

126                                              width=50, 

127                                              height=size_dict["receive_text_height"],

128                                              font=("Monaco", 9))

129 

130         self.frm_right_reset.grid(row=0, column=0, padx=1, sticky="wesn")

131         self.frm_right_send.grid(row=1, column=0, padx=1, sticky="wesn")

132         self.frm_right_clear.grid(row=2, column=0, padx=1, sticky="wesn")

133         self.frm_right_receive.grid(row=3, column=0, padx=1, sticky="wesn")

134 

135         self.frm_right_receive.tag_config("green", foreground="#228B22")

136 

137         self.create_frm_right_reset()

138         self.create_frm_right_clear()

139 

140     def create_frm_right_reset(self):

141         '''

142         1、Label显示和重置按钮和发送按钮

143         '''

144         self.frm_right_reset_label = pytk.PyLabel(self.frm_right_reset,

145                                                   text="Data Send" + " "*size_dict["reset_label_width"],

146                                                   font=font)

147         self.new_line_cbtn_var = tk.IntVar()

148         self.send_hex_cbtn_var = tk.IntVar()

149         self.frm_right_reset_newLine_checkbtn = pytk.PyCheckbutton(self.frm_right_reset,

150                                                                    text="New Line",

151                                                                    variable=self.new_line_cbtn_var,

152                                                                    font=font)

153         self.frm_right_reset_hex_checkbtn = pytk.PyCheckbutton(self.frm_right_reset,

154                                                                text="Hex",

155                                                                variable=self.send_hex_cbtn_var,

156                                                                font=font)

157         self.frm_right_reset_btn = pytk.PyButton(self.frm_right_reset, 

158                                                  text="Reset",

159                                                  width=10,

160                                                  font=font,

161                                                  command=self.Reset)

162         self.frm_right_send_btn = pytk.PyButton(self.frm_right_reset, 

163                                                 text="Send",

164                                                 width=10,

165                                                 font=font,

166                                                 command=self.Send)

167 

168         self.frm_right_reset_label.grid(row=0, column=0, sticky="w")

169         self.frm_right_reset_newLine_checkbtn.grid(row=0, column=1, sticky="wesn")

170         self.frm_right_reset_hex_checkbtn.grid(row=0, column=2, sticky="wesn")

171         self.frm_right_reset_btn.grid(row=0, column=3, padx=5, pady=5, sticky="wesn")

172         self.frm_right_send_btn.grid(row=0, column=4, padx=5, pady=5, sticky="wesn")

173 

174     def create_frm_right_clear(self):

175         '''

176         3、Label显示和十六进制显示和清除接收信息按钮

177         '''

178         self.receive_hex_cbtn_var = tk.IntVar()

179         self.frm_right_clear_label = pytk.PyLabel(self.frm_right_clear,

180                                                   text="Data Received"+ " "*size_dict["clear_label_width"],

181                                                   font=font)

182         self.frm_right_threshold_label = pytk.PyLabel(self.frm_right_clear,

183                                                       text="Threshold:",

184                                                       font=font)

185         self.thresholdStr = tk.StringVar()

186         self.frm_right_threshold_entry = pytk.PyEntry(self.frm_right_clear,

187                                                       textvariable=self.thresholdStr,

188                                                       width=6,

189                                                       font=font)

190         self.frm_right_hex_checkbtn = pytk.PyCheckbutton(self.frm_right_clear,

191                                                          text="Hex",

192                                                          variable=self.receive_hex_cbtn_var,

193                                                          relief="flat",

194                                                          font=font)

195         self.frm_right_clear_btn = pytk.PyButton(self.frm_right_clear, 

196                                                  text="Clear",

197                                                  width=10,

198                                                  font=font,

199                                                  command=self.Clear)

200 

201         self.frm_right_clear_label.grid(row=0, column=0, padx=5, pady=5, sticky="w")

202         self.frm_right_threshold_label.grid(row=0, column=1, padx=5, pady=5, sticky="wesn")

203         self.frm_right_threshold_entry.grid(row=0, column=2, padx=5, pady=5, sticky="wesn")

204         self.frm_right_hex_checkbtn.grid(row=0, column=3, padx=5, pady=5, sticky="wesn")

205         self.frm_right_clear_btn.grid(row=0, column=4, padx=5, pady=5, sticky="wesn")

206 

207         self.thresholdStr.set(1)

208         self.thresholdStr.trace('w', self.GetThresholdValue)

209 

210     def create_frm_status(self):

211         '''

212         下半部分状态栏窗口

213         '''

214         self.frm_status_label = pytk.PyLabel(self.frm_status, 

215                                              text="Ready",

216                                              font=font)

217         self.frm_status_label.grid(row=0, column=0, padx=5, pady=5, sticky="wesn")

218 

219     def Toggle(self):

220         pass

221 

222     def Open(self, event):

223         pass

224 

225     def Reset(self):

226         self.frm_right_send.delete("0.0", "end")

227 

228     def Send(self):

229         pass

230 

231     def Clear(self):

232         self.frm_right_receive.delete("0.0", "end")

233 

234     def GetThresholdValue(self, *args):

235         try:

236             self.thresholdValue = int(self.thresholdStr.get())

237         except:

238             pass

239 

240 

241 if __name__ == '__main__':

242     '''

243     main loop

244     '''

245     root = tk.Tk()

246     if g_default_theme == "dark":

247         root.configure(bg="#292929")

248         combostyle = ttk.Style()

249         combostyle.theme_use('alt')

250         combostyle.configure("TCombobox", selectbackground="#292929", fieldbackground="#292929",

251                                           background="#292929", foreground="#FFFFFF")

252     root.title("Serial-Tool")

253     SerialToolUI(master=root)

254     root.resizable(False, False)

255     root.mainloop()
View Code

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

界面逻辑主程序

main.py

  1 #! /usr/bin/env python

  2 # -*- coding: utf-8 -*-

  3 

  4 import time

  5 import datetime

  6 import threading

  7 import binascii

  8 import platform

  9 import logging

 10 

 11 from UI import SerialTool

 12 from COM import SerialHelper

 13 

 14 if platform.system() == "Windows":

 15     from  serial.tools import list_ports

 16 elif platform.system() == "Linux":

 17     import glob, os, re

 18 

 19 import Tkinter as tk

 20 import ttk

 21 

 22 logging.basicConfig(level=logging.DEBUG,

 23                     format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s',

 24                     datefmt='%a, %d %b %Y %H:%M:%S')

 25 

 26 class MainSerialToolUI(SerialTool.SerialToolUI):

 27     def __init__(self, master=None):

 28         super(MainSerialToolUI, self).__init__()

 29         self.ser = None

 30         self.receive_count = 0

 31         self.receive_data = ""

 32         self.list_box_serial = list()

 33         self.find_all_serial()

 34 

 35     def __del__(self):

 36         if platform.system() == "Linux":

 37             try:

 38                 self.ser.SetStopEvent()

 39             except:

 40                 pass

 41 

 42     def find_all_serial(self):

 43         '''

 44         获取到串口列表

 45         '''

 46         if platform.system() == "Windows":

 47             try:

 48                 self.temp_serial = list()

 49                 for com in list_ports.comports():

 50                     strCom = com[0] + ": " + com[1][:-7].decode("gbk").encode("utf-8")

 51                     self.temp_serial.append(strCom)

 52                 for item in self.temp_serial:

 53                     if item not in self.list_box_serial:

 54                         self.frm_left_listbox.insert("end", item)

 55                 for item in self.list_box_serial:

 56                     if item not in self.temp_serial:

 57                         index = list(self.frm_left_listbox.get(0, self.frm_left_listbox.size())).index(item)

 58                         self.frm_left_listbox.delete(index)

 59 

 60                 self.list_box_serial = self.temp_serial

 61 

 62                 self.thread_findserial = threading.Timer(1, self.find_all_serial)

 63                 self.thread_findserial.setDaemon(True)

 64                 self.thread_findserial.start()

 65             except Exception as e:

 66                 logging.error(e)

 67         elif platform.system() == "Linux":

 68             try:

 69                 self.temp_serial = list()

 70                 self.temp_serial = self.find_usb_tty()

 71                 for item in self.temp_serial:

 72                     if item not in self.list_box_serial:

 73                         self.frm_left_listbox.insert("end", item)

 74                 for item in self.list_box_serial:

 75                     if item not in self.temp_serial:

 76                         index = list(self.frm_left_listbox.get(0, self.frm_left_listbox.size())).index(item)

 77                         self.frm_left_listbox.delete(index)

 78                 self.list_box_serial = self.temp_serial

 79 

 80                 self.thread_findserial = threading.Timer(1, self.find_all_serial)

 81                 self.thread_findserial.setDaemon(True)

 82                 self.thread_findserial.start()

 83             except Exception as e:

 84                 logging.error(e)

 85 

 86     def Toggle(self):

 87         '''

 88         打开关闭串口

 89         '''

 90         if self.frm_left_btn["text"] == "Open":

 91             try:

 92                 self.currentStrCom = self.frm_left_listbox.get(self.frm_left_listbox.curselection())

 93                 if platform.system() == "Windows":

 94                     self.port = self.currentStrCom.split(":")[0]

 95                 elif platform.system() == "Linux":

 96                     self.port = self.currentStrCom

 97                 self.baudrate = self.frm_left_combobox_baudrate.get()

 98                 self.parity = self.frm_left_combobox_parity.get()

 99                 self.databit = self.frm_left_combobox_databit.get()

100                 self.stopbit = self.frm_left_combobox_stopbit.get()

101                 self.ser = SerialHelper.SerialHelper(Port=self.port,

102                                                      BaudRate=self.baudrate,

103                                                      ByteSize=self.databit,

104                                                      Parity=self.parity,

105                                                      Stopbits=self.stopbit)

106                 self.ser.start()

107                 if self.ser.alive:

108                     self.frm_status_label["text"] = "Open [{0}] Successful!".format(self.currentStrCom)

109                     self.frm_status_label["fg"] = "#66CD00"

110                     self.frm_left_btn["text"] = "Close"

111                     self.frm_left_btn["bg"] = "#F08080"

112 

113                     self.thread_read = threading.Thread(target=self.SerialRead)

114                     self.thread_read.setDaemon(True)

115                     self.thread_read.start()

116 

117             except Exception as e:

118                 logging.error(e)

119                 try:

120                     self.frm_status_label["text"] = "Open [{0}] Failed!".format(self.currentStrCom)

121                     self.frm_status_label["fg"] = "#DC143C"

122                 except Exception as ex:

123                     logging.error(ex)

124 

125         elif self.frm_left_btn["text"] == "Close":

126             try:

127                 self.ser.stop()

128                 self.receive_count = 0

129             except Exception as e:

130                 logging.error(e)

131             self.frm_left_btn["text"] = "Open"

132             self.frm_left_btn["bg"] = "#008B8B"

133             self.frm_status_label["text"] = "Close Serial Successful!"

134             self.frm_status_label["fg"] = "#8DEEEE"

135 

136     def Open(self, event):

137         '''

138         双击列表打开/关闭串口

139         '''

140         self.Toggle()

141 

142     def Clear(self):

143         self.frm_right_receive.delete("0.0", "end")

144         self.receive_count = 0

145 

146     def Send(self):

147         '''

148         向已打开的串口发送数据

149         如果为Hex发送,示例:"31 32 33" [即为字符串 "123"]

150         '''

151         if self.ser:

152             try:

153                 # 发送新行

154                 if self.new_line_cbtn_var.get() == 0:

155                     send_data = str(self.frm_right_send.get("0.0", "end").encode("gbk")).strip()

156                 else:

157                     send_data = str(self.frm_right_send.get("0.0", "end")).strip() + "\r\n"  

158                 

159                 # 是否十六进制发送

160                 if self.send_hex_cbtn_var.get() == 1:

161                     self.ser.write(send_data, isHex=True)

162                 else:

163                     self.ser.write(send_data)

164             except Exception as e:

165                 self.frm_right_receive.insert("end", str(e) + "\n")

166                 logging.error(e)

167 

168     def SerialRead(self):

169         '''

170         线程读取串口发送的数据

171         '''

172         while self.ser.alive:

173             try:

174                 n = self.ser.l_serial.inWaiting()

175                 if n:

176                     self.receive_data += self.ser.l_serial.read(n).replace(binascii.unhexlify("00"), "")

177                     if self.thresholdValue <= len(self.receive_data):

178                         self.receive_count += 1

179 

180                         # 接收显示是否为Hex

181                         if self.receive_hex_cbtn_var.get() == 1:

182                             self.receive_data = self.space_b2a_hex(self.receive_data)

183                         self.frm_right_receive.insert("end", "[" + str(datetime.datetime.now()) + " - "

184                                                       + str(self.receive_count) + "]:\n", "green")

185                         self.frm_right_receive.insert("end", self.receive_data + "\n")

186                         self.frm_right_receive.see("end")

187                         self.receive_data = ""

188 

189             except Exception as e:

190                 logging.error(e)

191                 self.receive_data = ""

192                 self.ser.stop()

193                 self.ser = None

194 

195     def find_usb_tty(self, vendor_id=None, product_id=None):

196         '''

197         发现串口设备

198         '''

199         tty_devs = list()

200         for dn in glob.glob('/sys/bus/usb/devices/*') :

201             try:

202                 vid = int(open(os.path.join(dn, "idVendor" )).read().strip(), 16)

203                 pid = int(open(os.path.join(dn, "idProduct")).read().strip(), 16)

204                 if  ((vendor_id is None) or (vid == vendor_id)) and ((product_id is None) or (pid == product_id)) :

205                     dns = glob.glob(os.path.join(dn, os.path.basename(dn) + "*"))

206                     for sdn in dns :

207                         for fn in glob.glob(os.path.join(sdn, "*")) :

208                             if  re.search(r"\/ttyUSB[0-9]+$", fn) :

209                                 tty_devs.append(os.path.join("/dev", os.path.basename(fn)))

210             except Exception as ex:

211                 pass

212         return tty_devs

213 

214     def space_b2a_hex(self, data):

215         '''

216         格式化接收到的数据字符串

217         示例:123 --> 31 32 33

218         '''

219         new_data_list = list()

220         new_data = ""

221 

222         hex_data = binascii.b2a_hex(data)

223         temp_data = ""

224         for index,value in enumerate(hex_data): 

225             temp_data += value

226             if len(temp_data) == 2:

227                 new_data_list.append(temp_data)

228                 temp_data = ""

229         for index,value in enumerate(new_data_list):

230             if index%25 == 0 and index != 0:

231                 new_data += "\n"

232             new_data += value

233             new_data += " "

234 

235         return new_data

236 

237 if __name__ == '__main__':

238     '''

239     main loop

240     '''

241     root = tk.Tk()

242     root.title("Serial Tool")

243     if SerialTool.g_default_theme == "dark":

244         root.configure(bg="#292929")

245         combostyle = ttk.Style()

246         combostyle.theme_use('alt')

247         combostyle.configure("TCombobox", selectbackground="#292929", fieldbackground="#292929",

248                                           background="#292929", foreground="#FFFFFF")

249     MainSerialToolUI(master=root)

250     root.resizable(False, False)

251     root.mainloop()
View Code

项目地址:Serial-Tool

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

你可能感兴趣的:(python2.7)