痞子衡嵌入式:串列埠除錯工具Jays-PyCOM誕生記(3)- 串列埠功能實現(pySerial)

痞子衡發表於2017-05-13

  大家好,我是痞子衡,是正經搞技術的痞子。今天痞子衡給大家介紹的是串列埠除錯工具Jays-PyCOM誕生之串列埠功能實現

  串列埠除錯助手是最核心的當然是串列埠資料收發與顯示的功能,Jays-PyCOM藉助的是pySerial庫實現串列埠收發功能,今天痞子衡為大家介紹pySerial是如何在Jays-PyCOM發揮功能的。

一、pySerial簡介

  pySerial是一套基於python實現serial port訪問的庫,該庫的設計者為Chris Liechti,該庫從2001年開始推出,一直持續更新至今,Jays-PyCOM使用的是pySerial 3.4。
  pySerial的使用非常簡單,可在其官網瀏覽一遍其提供的API: https://pythonhosted.org/pyserial/pyserial_api.html,下面痞子衡整理了比較常用的API如下:

class Serial(SerialBase):
    # 初始化串列埠引數
    def __init__(self, *args, **kwargs):
    # 開啟串列埠
    def open(self):
    # 關閉串列埠
    def close(self):
    # 獲取串列埠開啟狀態
    def isOpen(self):
    # 設定input_buffer/output_buffer大小
    def set_buffer_size(self, rx_size=4096, tx_size=None):

    # 獲取input_buffer(接收緩衝區)裡的byte資料個數
    def inWaiting(self):
    # 從串列埠讀取size個byte資料
    def read(self, size=1):
    # 清空input_buffer
    def reset_input_buffer(self):

    # 向串列埠寫入data裡所有資料
    def write(self, data):
    # 等待直到output_buffer裡的資料全部傳送出去
    def flush(self):
    # 清空output_buffer
    def reset_output_buffer(self):

  pySerial常用引數整理如下,需要特別強調的是任何執行時刻對如下引數進行修改,均是直接應用生效的,不需要重新呼叫open()和close()去啟用,因為引數的修改在pySerial內部是通過與引數同名的方法實現的,而這些方法均呼叫了Serial裡的一個叫_reconfigure_port()的方法實現的。

引數名 功能解釋 備註/可設值
port 裝置名 /dev/ttyUSB0 on GNU/Linux or COM3 on Windows
baudrate (int) 波特率 /
bytesize 資料位bit個數 FIVEBITS, SIXBITS, SEVENBITS, EIGHTBITS
stopbits 停止位 STOPBITS_ONE, STOPBITS_ONE_POINT_FIVE, STOPBITS_TWO
parity 奇偶校驗位 PARITY_NONE, PARITY_EVEN, PARITY_ODD PARITY_MARK, PARITY_SPACE
timeout (float) 接收超時 None:blocking mode
0: non-blocking mode
x: 超時時間x秒
write_timeout (float) 傳送超時 同timeout

二、JaysPyCOM串列埠功能實現

  串列埠功能程式碼實現主要分為三大部分:配置功能實現、接收功能實現、傳送功能實現。在實現這些功能之前首先需要import兩個module,分別是serial、threading,serial就是pySerial庫;threading是python自帶執行緒庫,其具體作用下面程式碼裡會介紹。
  除此以外還定義兩個全域性變數,s_serialPort和s_recvInterval,s_serialPort是串列埠裝置object例項,s_recvInterval是執行緒間隔時間。

import serial
import threading

s_serialPort = serial.Serial()
s_recvInterval = 0.5

2.1串列埠配置功能

  串列埠配置裡主要就是實現GUI介面上"Open"按鈕的回撥函式,即openClosePort(),軟體剛開啟時所有可用Port預設是Close狀態,如果使用者選定了配置引數(串列埠號、波特率...),並點選了"Open"按鈕,此時便會觸發openClosePort()的執行,在openClosePort()裡我們需要配置s_serialPort的引數並開啟指定的串列埠裝置。

class mainWin(win.com_win):

    def setPort ( self ):
        s_serialPort.port = self.m_textCtrl_comPort.GetLineText(0)
    def setBaudrate ( self ):
        index = self.m_choice_baudrate.GetSelection()
        s_serialPort.baudrate = int(self.m_choice_baudrate.GetString(index))
    def setDatabits ( self ):
        # ...
    def setStopbits ( self ):
        # ...
    def setParitybits ( self ):
        # ...

    def openClosePort( self, event ):
        if s_serialPort.isOpen():
            s_serialPort.close()
            self.m_button_openClose.SetLabel('Open')
        else:
            # 獲取GUI配置皮膚裡的輸入值賦給s_serialPort
            self.setPort()
            self.setBaudrate()
            self.setDatabits()
            self.setStopbits()
            self.setParitybits()
            # 開啟s_serialPort指定的串列埠裝置
            s_serialPort.open()
            self.m_button_openClose.SetLabel('Close')
            s_serialPort.reset_input_buffer()
            s_serialPort.reset_output_buffer()
            # 開啟串列埠接收執行緒(每0.5秒定時執行一次)
            threading.Timer(s_recvInterval, self.recvData).start()

  上述程式碼裡需要特別講一下的是串列埠接收執行緒,我們知道串列埠裝置s_serialPort一旦開啟之後,只要該串列埠裝置的RXD訊號線上有資料傳輸,pySerial底層會自動將其存入s_serialPort對應的input_buffer裡,但並不會主動通知我們。那我們怎麼知道input_buffer裡有沒有資料?此時就需要我們開啟一個定時執行的執行緒,執行緒裡會去檢視input_buffer裡是否有資料,如果有資料便顯示出來,因此在串列埠裝置開啟的同時我們需要建立一個串列埠接收執行緒recvData()。

2.2串列埠接收功能

  串列埠接收功能其實在串列埠配置裡已經提到了,主要就是串列埠接收執行緒recvData()的實現,recvData()實現很簡單,只有一個注意點,那就是threading.Timer()的用法,這是個軟體定時器,它只能超時觸發一次任務的執行,如果想讓任務迴圈觸發,那麼需要在任務本身裡新增threading.Timer()的呼叫。

    def clearRecvDisplay( self, event ):
        self.m_textCtrl_recv.Clear()

    def setRecvFormat( self, event ):
        event.Skip()

    def recvData( self ):
        if s_serialPort.isOpen():
            # 獲取input_buffer裡的資料個數
            num = s_serialPort.inWaiting()
            if num != 0:
                # 獲取input_buffer裡的資料並顯示在GUI介面的接收顯示框裡
                data = s_serialPort.read(num)
                self.m_textCtrl_recv.write(data)
            # 這一句是執行緒能夠定時執行的關鍵
            threading.Timer(s_recvInterval, self.recvData).start()

2.3串列埠傳送功能

  串列埠傳送功能相比串列埠接收功能就簡單多了,串列埠傳送主要就是實現GUI介面上"Send"按鈕的回撥函式,即sendData(),程式碼實現比較簡單,不予贅述。

    def clearSendDisplay( self, event ):
        self.m_textCtrl_send.Clear()

    def setSendFormat( self, event ):
        event.Skip()

    def sendData( self, event ):
        if s_serialPort.isOpen():
            # 獲取傳送輸入框裡的資料並通過串列埠傳送出去
            lines = self.m_textCtrl_send.GetNumberOfLines()
            for i in range(0, lines):
                data = self.m_textCtrl_send.GetLineText(i)
                s_serialPort.write(str(data))
        else:
            self.m_textCtrl_send.Clear()
            self.m_textCtrl_send.write('Port is not open')

  目前串列埠收發與顯示實現均是基於字元方式,即傳送輸入框、接收顯示框裡僅支援ASCII碼字串,關於Char/Hex顯示轉換的功能(setRecvFormat()/setSendFormat())並未加上,後續優化裡會進一步做。

  至此,串列埠除錯工具Jays-PyCOM誕生之串列埠功能實現痞子衡便介紹完畢了,掌聲在哪裡~~~

相關文章