• Python串口通信助手


      1 # -*- coding: utf-8 -*-
      2 import sys
      3 import serial
      4 import serial.tools.list_ports
      5 import threading
      6 import signal
      7 import binascii
      8 
      9 #import strings_zh as strings
     10 APP_NAME = '串口调试助手'
     11 APP_VER = '1.0'
     12 AUTHOR = 'txqdm'
     13 
     14 recv_buf_text = "接收缓冲区"
     15 text_mode_text = "文本模式"
     16 hex_mode_text = "16进制模式"
     17 clear_recv_text = "清空接收"
     18 send_buf_text = "发送缓冲区"
     19 line_break_text = "换行符:'\r\n'"
     20 clear_send_text = "清空发送"
     21 send_btn_text = "发送数据"
     22 port_lbl_text = "串口:"
     23 baud_lbl_text = "波特率:"
     24 size_lbl_text = "数据位:"
     25 parity_lbl_text = "校验位:"
     26 stopbit_lbl_text = "停止位:"
     27 send_lbl_text = "SEND"
     28 recv_lbl_text = "RECV"
     29 clear_btn_text = "清除"
     30 opening = "已打开"
     31 closed = "已关闭"
     32 select_port = "请选择串口"
     33 start_port_text = "打开串口"
     34 close_port_text = "关闭串口"
     35 
     36 if sys.version_info.major == 2:
     37     import Tkinter as tk
     38     import tkMessageBox as msgbox
     39 elif sys.version_info.major == 3:
     40     import tkinter as tk
     41     from tkinter import messagebox as msgbox
     42 
     43 
     44 WINDOWSIZE = '710x510+50+50'
     45 # Common baudrate
     46 BAUDRATES = (1200, 2400, 4800, 9600, 14400, 19200, 38400, 57600, 115200)
     47 BYTESIZES = (5, 6, 7, 8)
     48 PARITIES = {'None': 'N', 'Even': 'E', 'Odd': 'O', 'Mark': 'M', 'Space': 'S'}
     49 STOPBITS = (1, 1.5, 2)
     50 BYTETYPES = ('1 Byte', '2 Bytes', '4 Bytes')
     51 
     52 TIMEOUT = 0.015
     53 
     54 font = ("宋体", 10, "normal")
     55 font_text = ("Courier", 9, "normal")
     56 font_button = ("黑体", 12, "normal")
     57 
     58 
     59 def format_data(data):
     60         li = data.split(' ')
     61         result = []
     62         k = 0
     63         for each in li:
     64             if len(each) <= 2:
     65                 result.append(each)
     66 
     67             if len(each) > 2:
     68                 while k < len(each):
     69                     result.append(each[k: k + 2])
     70                     k = k + 2
     71                 k = 0
     72 
     73         for i in range(len(result)):
     74             if len(result[i]) == 1:
     75                 result[i] = '0' + result[i]
     76 
     77         return result
     78 
     79 
     80 def getAvailabelSerialPort():
     81     available_ports = []
     82     coms = serial.tools.list_ports.comports()
     83     if coms is not None:
     84         for com in coms:
     85             if sys.platform == 'win32':
     86                 available_ports.append(com.device)
     87             elif sys.platform == 'linux2':
     88                 if com[2] != 'n/a':
     89                     available_ports.append(com[0])
     90     return tuple(available_ports)
     91 
     92 
     93 if sys.platform == 'win32':
     94     PORTS = sorted(getAvailabelSerialPort(), key=lambda n: int(n[3:]))
     95 else:
     96     PORTS = getAvailabelSerialPort()
     97 
     98 
     99 class SerialAssistantGUI(object):
    100     def __init__(self):
    101         self.root = tk.Tk()
    102         self.root.title('%s v%s by %s' % (APP_NAME, APP_VER,
    103                                           AUTHOR))
    104         self.root.geometry(WINDOWSIZE)
    105         self.root.resizable(width=False, height=False)
    106 
    107         self.__recv_area()
    108         self.__send_area()
    109         self.__cmd_area()
    110         self.__opt_area()
    111 
    112         self.root.mainloop()
    113 
    114     def __recv_area(self):
    115         recv_lframe = tk.LabelFrame(self.root,
    116                                     text=recv_buf_text,
    117                                     height=250)
    118         recv_lframe.pack(fill=tk.X, padx=5)
    119 
    120         recv_optframe = tk.Frame(recv_lframe)
    121         recv_txtframe = tk.Frame(recv_lframe)
    122         recv_optframe.pack(fill=tk.Y, side=tk.LEFT, padx=5, pady=5)
    123         recv_txtframe.pack(fill=tk.Y, side=tk.RIGHT, padx=5, pady=5)
    124 
    125         self.recv_mode = tk.IntVar()
    126         self.recv_mode.set(0)
    127         recv_radbtn1 = tk.Radiobutton(recv_optframe,
    128                                       text=text_mode_text,
    129                                       font=font,
    130                                       variable=self.recv_mode, value=0)
    131         recv_radbtn2 = tk.Radiobutton(recv_optframe,
    132                                       text=hex_mode_text,
    133                                       font=font,
    134                                       variable=self.recv_mode, value=1)
    135         recv_clrbtn = tk.Button(recv_optframe, width=15,
    136                                 text=clear_recv_text,
    137                                 font=font,
    138                                 command=self.clear_received)
    139         recv_radbtn1.pack(anchor=tk.W)
    140         recv_radbtn2.pack(anchor=tk.W)
    141         recv_clrbtn.pack(fill=tk.X)
    142 
    143         self.recv_txtarea = tk.Text(recv_txtframe, height=15, width=74,
    144                                     font=font_text)
    145         self.recv_txtarea.pack(side=tk.LEFT, fill=tk.X)
    146         recv_scrbar = tk.Scrollbar(recv_txtframe)
    147         recv_scrbar.pack(side=tk.RIGHT, fill=tk.Y)
    148         self.recv_txtarea['yscrollcommand'] = recv_scrbar.set
    149         recv_scrbar['command'] = self.recv_txtarea.yview
    150 
    151     def __send_area(self):
    152         send_lframe = tk.LabelFrame(self.root,
    153                                     text=send_buf_text,
    154                                     height=100)
    155         send_lframe.pack(fill=tk.X, padx=5)
    156 
    157         send_optframe = tk.Frame(send_lframe)
    158         send_txtframe = tk.Frame(send_lframe)
    159         send_optframe.pack(fill=tk.Y, side=tk.LEFT, padx=5, pady=5)
    160         send_txtframe.pack(fill=tk.Y, side=tk.RIGHT, padx=5, pady=5)
    161 
    162         self.send_mode = tk.IntVar()
    163         self.send_mode.set(0)
    164         send_radbtn1 = tk.Radiobutton(send_optframe,
    165                                       text=text_mode_text,
    166                                       font=font,
    167                                       variable=self.send_mode, value=0)
    168         send_radbtn2 = tk.Radiobutton(send_optframe,
    169                                       text=hex_mode_text,
    170                                       font=font,
    171                                       variable=self.send_mode, value=1)
    172         self.linebreak = tk.IntVar()
    173         if sys.platform == 'win32':
    174             self.linebreak.set(1)
    175         elif sys.platform == 'linux2':
    176             self.linebreak.set(0)
    177         send_chkbtn = tk.Checkbutton(send_optframe,
    178                                      text=line_break_text,
    179                                      font=font,
    180                                      variable=self.linebreak)
    181         send_clrbtn = tk.Button(send_optframe,
    182                                 text=clear_send_text,
    183                                 font=font,
    184                                 width=15,
    185                                 command=self.clear_sent)
    186         send_radbtn1.pack(anchor=tk.W)
    187         send_radbtn2.pack(anchor=tk.W)
    188         send_chkbtn.pack(anchor=tk.W)
    189         send_clrbtn.pack(fill=tk.X)
    190 
    191         self.send_txtarea = tk.Text(send_txtframe, height=7, width=74,
    192                                     font=font_text)
    193         self.send_txtarea.pack(side=tk.LEFT, fill=tk.X)
    194         send_scrbar = tk.Scrollbar(send_txtframe)
    195         send_scrbar.pack(side=tk.RIGHT, fill=tk.Y)
    196         self.send_txtarea['yscrollcommand'] = send_scrbar.set
    197         send_scrbar['command'] = self.send_txtarea.yview
    198 
    199     def __cmd_area(self):
    200         cmd_frame = tk.Frame(self.root)
    201         cmd_frame.pack(fill=tk.X, padx=5, pady=5)
    202         #cmd_btn = tk.Button(cmd_frame,
    203         #                    text=send_btn_text,
    204         #                    font=font,
    205         #                    command=self.send_data)
    206         #cmd_btn.pack(side=tk.LEFT)
    207         
    208     def __opt_area(self):
    209         opt_frame = tk.Frame(self.root)
    210         opt_frame.pack(fill=tk.X, padx=5, pady=5)
    211 
    212         # Serial port setting
    213         port_label = tk.Label(opt_frame,
    214                               text=port_lbl_text,
    215                               font=font)
    216 
    217         self.port_var = tk.StringVar()
    218         self.port_var.set(select_port)
    219 
    220         if len(PORTS) == 0:
    221             port_opmenu = tk.OptionMenu(opt_frame, self.port_var, '')
    222         else:
    223             port_opmenu = tk.OptionMenu(opt_frame, self.port_var, *PORTS)
    224         port_opmenu.config(anchor=tk.W,
    225                            width=10,
    226                            font=font)
    227         port_label.pack(side=tk.LEFT)
    228         port_opmenu.pack(side=tk.LEFT)
    229 
    230         # Baudrate setting
    231         brt_label = tk.Label(opt_frame,
    232                              text=baud_lbl_text,
    233                              font=font)
    234         self.brt_var = tk.StringVar()
    235         self.brt_var.set(BAUDRATES[3])
    236         brt_opmenu = tk.OptionMenu(opt_frame, self.brt_var, *BAUDRATES)
    237         brt_opmenu.config(anchor=tk.W,
    238                           width=6,
    239                           font=font)
    240         brt_label.pack(side=tk.LEFT)
    241         brt_opmenu.pack(side=tk.LEFT)
    242 
    243         # Bytesize setting
    244         size_label = tk.Label(opt_frame,
    245                               text=size_lbl_text,
    246                               font=font)
    247         self.size_var = tk.StringVar()
    248         self.size_var.set(BYTESIZES[3])
    249         size_opmenu = tk.OptionMenu(opt_frame, self.size_var, *BYTESIZES)
    250         size_opmenu.config(anchor=tk.W,
    251                            width=3,
    252                            font=font)
    253         size_label.pack(side=tk.LEFT)
    254         size_opmenu.pack(side=tk.LEFT)
    255 
    256         # Parity setting
    257         parity_label = tk.Label(opt_frame,
    258                                 text=parity_lbl_text,
    259                                 font=font)
    260         self.parity_var = tk.StringVar()
    261         self.parity_var.set('None')
    262         parity_opmenu = tk.OptionMenu(opt_frame, self.parity_var,
    263                                       *PARITIES)
    264         parity_opmenu.config(anchor=tk.W,
    265                              width=4,
    266                              font=font)
    267         parity_label.pack(side=tk.LEFT)
    268         parity_opmenu.pack(side=tk.LEFT)
    269 
    270         # Stopbit setting
    271         stop_label = tk.Label(opt_frame,
    272                               text=stopbit_lbl_text,
    273                               font=font)
    274         self.stop_var = tk.StringVar()
    275         self.stop_var.set(STOPBITS[0])
    276         stop_opmenu = tk.OptionMenu(opt_frame, self.stop_var, *STOPBITS)
    277         stop_opmenu.config(anchor=tk.W,
    278                            width=3,
    279                            font=font)
    280         stop_label.pack(side=tk.LEFT)
    281         stop_opmenu.pack(side=tk.LEFT)
    282 
    283         # Set buttons
    284         control_frame = tk.Frame(self.root, width=300)
    285         status_frame = tk.Frame(self.root, width=300)
    286         control_frame.pack(side=tk.LEFT)
    287         status_frame.pack(side=tk.RIGHT)
    288 
    289         start_btn = tk.Button(control_frame,
    290                               text=start_port_text,
    291                               width=12,font=font_button,
    292                               command=self.start_port)
    293         close_btn = tk.Button(control_frame,
    294                               text=close_port_text,
    295                               width=12,font=font_button,
    296                               command=self.close_port)
    297         cmd_btn = tk.Button(control_frame,
    298                            text=send_btn_text,
    299                             width=12,font=font_button,
    300                             command=self.send_data)
    301         start_btn.pack(side=tk.LEFT, padx=5)
    302         close_btn.pack(side=tk.LEFT, padx=5)
    303         cmd_btn.pack(side=tk.LEFT, padx=5)
    304         self.state_lbl = tk.Label(control_frame, text='')
    305         self.state_lbl.pack(side=tk.LEFT, padx=5)
    306 
    307         # Status frame widgets
    308         send_cnt_label = tk.Label(status_frame,
    309                                   text=send_lbl_text,
    310                                   font=font)
    311         self.send_cnt = tk.StringVar()
    312         self.send_cnt.set(self.TX)
    313         send_cnt_entry = tk.Entry(status_frame,
    314                                   textvariable=self.send_cnt,
    315                                   width=10,font=font,
    316                                   relief=tk.SUNKEN,
    317                                   state=tk.DISABLED,
    318                                   justify=tk.RIGHT)
    319         send_cnt_label.pack(side=tk.LEFT)
    320         send_cnt_entry.pack(side=tk.LEFT)
    321 
    322         recv_cnt_label = tk.Label(status_frame,
    323                                   text=recv_lbl_text,
    324                                   font=font)
    325         self.recv_cnt = tk.StringVar()
    326         self.recv_cnt.set(self.RX)
    327         recv_cnt_entry = tk.Entry(status_frame,
    328                                   textvariable=self.recv_cnt,
    329                                   width=10,font=font,
    330                                   relief=tk.SUNKEN,
    331                                   state=tk.DISABLED,
    332                                   justify=tk.RIGHT)
    333         recv_cnt_label.pack(side=tk.LEFT)
    334         recv_cnt_entry.pack(side=tk.LEFT)
    335 
    336         clr_btn = tk.Button(status_frame,
    337                             text=clear_btn_text,
    338                             width=12,font=font_button,
    339                             command=self.clear_count)
    340         #clr_btn.pack()
    341         clr_btn.pack(side=tk.LEFT, padx=10)
    342 
    343     def clear_received(self):
    344         self.recv_txtarea.delete(0.0, tk.END)
    345 
    346     def clear_sent(self):
    347         self.send_txtarea.delete(0.0, tk.END)
    348 
    349     def clear_count(self):
    350         pass
    351 
    352     def start_port(self):
    353         pass
    354 
    355     def send_data(self):
    356         pass
    357 
    358     def recv_data(self):
    359         pass
    360 
    361 
    362 class SerialAssistant(SerialAssistantGUI):
    363 
    364     portisopen = 0
    365     TX = 0
    366     RX = 0
    367 
    368     def __init__(self):
    369         super(SerialAssistant, self).__init__()
    370 
    371     def clear_count(self):
    372         self.RX = 0
    373         self.TX = 0
    374         self.send_cnt.set(self.RX)
    375         self.recv_cnt.set(self.TX)
    376 
    377     def start_port(self):
    378         port = self.port_var.get()
    379         baudrate = int(self.brt_var.get())
    380         bytesize = int(self.size_var.get())
    381         parity = PARITIES[self.parity_var.get()]
    382         stopbits = float(self.stop_var.get())
    383 
    384         try:
    385             self.s = serial.Serial(port=port,
    386                                    baudrate=baudrate,
    387                                    bytesize=bytesize,
    388                                    parity=parity,
    389                                    stopbits=stopbits,
    390                                    timeout=TIMEOUT)
    391         except serial.SerialException as e:
    392             msgbox.showerror("OpenError", e)
    393         except serial.SerialTimeoutException as e:
    394             msgbox.showerror("OpenError", e)
    395         else:
    396             self.portisopen = 1
    397             self.state_lbl.config(background='green',
    398                                   text=port + opening)
    399             self.th = threading.Thread(target=self.recv_data)
    400             self.th.daemon = True
    401             self.th.start()
    402 
    403     def send_data(self):
    404         if self.portisopen:
    405             data_fmt = []
    406             data = self.send_txtarea.get(0.0, tk.END)
    407 
    408             if len(data) == 1:
    409                 return
    410 
    411             if self.send_mode.get():
    412                 if data[-1] == 'x0a':
    413                     data = data[0:-1]
    414                 data_fmt = format_data(data)
    415                 for each in data_fmt:
    416                     try:
    417                         x = binascii.a2b_hex(each)
    418                     except TypeError:
    419                         x = 'x00'
    420 
    421                     self.s.write(x)
    422                     self.TX += 1
    423             else:
    424                 if data[-1] == '
    ':
    425                     data = data[0:-1]
    426                 if self.linebreak.get():
    427                     data = data.replace('
    ', '
    ')
    428 
    429                 self.s.write(data.encode('utf-8'))
    430                 self.TX += len(data)
    431             self.send_cnt.set(self.TX)
    432         else:
    433             msgbox.showerror("Error", "Port NOT open!")
    434             return
    435 
    436     def recv_data(self):
    437         while self.portisopen:
    438             data = self.s.read()
    439             if len(data) != 0:
    440                 if self.recv_mode.get() == 1:
    441                     data = binascii.b2a_hex(data)
    442                     if sys.version_info.major == 3:
    443                         data += b' '
    444                     elif sys.version_info.major == 2:
    445                         data += ' '
    446                     self.RX += 1
    447                 else:
    448                     self.RX += len(data)
    449             self.recv_cnt.set(self.RX)
    450             if data != 'x0d':
    451                 self.recv_txtarea.insert(tk.END, data)
    452                 self.recv_txtarea.see(tk.END)
    453         return
    454 
    455     def close_port(self):
    456         if self.portisopen:
    457             self.portisopen = 0
    458             self.s.close()
    459             self.state_lbl.config(background='red',
    460                                   text=self.port_var.get() + closed)
    461         else:
    462             return
    463 
    464     def handler(self, signum, frame):
    465         self.portisopen = 0
    466         self.th.join()
    467 
    468     def __del__(self):
    469         self.close_port()
    470         signal.signal(signal.SIGINT, self.handler)
    471 
    472 
    473 def main():
    474     SerialAssistant()
    475 
    476 
    477 if __name__ == '__main__':
    478     main()
  • 相关阅读:
    快速傅立叶变换
    回文树
    gcc 编译c文件的几个过程
    linux quota---mount
    linux device driver3 读书笔记(一)
    linux驱动开发(十一)linux内核信号量、互斥锁、自旋锁
    linux驱动开发(十)——misc杂散设备
    linux驱动(九)platform驱动模型详解,以及基于platform驱动模型的led驱动
    (转)__ATTRIBUTE__ 你知多少?
    linux驱动(八)驱动设备模型
  • 原文地址:https://www.cnblogs.com/txqdm/p/13787102.html
Copyright © 2020-2023  润新知