Python實現串口助手 - 03串口功能實現

 串口調試助手是最核心的當然是串口數據收發與顯示的功能,pzh-py-com藉助的是pySerial庫實現串口收發功能,今天痞子衡為大家介紹pySerial是如何在pzh-py-com發揮功能的。

一、pySerial簡介


  pySerial是一套基於python實現serial port訪問的庫,該庫的設計者為Chris Liechti,該庫從2001年開始推出,一直持續更新至今,pzh-py-com使用的是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())並未加上,後續優化裡會進一步做。

  至此,串口調試工具pzh-py-com誕生之串口功能實現便介紹完畢了