大家好,我是痞子衡,是正經(jīng)搞技術(shù)的痞子。今天痞子衡給大家介紹的是串口調(diào)試工具pzh-py-com誕生之串口功能實現(xiàn)。
串口調(diào)試助手是最核心的當然是串口數(shù)據(jù)收發(fā)與顯示的功能,pzh-py-com借助的是pySerial庫實現(xiàn)串口收發(fā)功能,今天痞子衡為大家介紹pySerial是如何在pzh-py-com發(fā)揮功能的。
一、pySerial簡介
pySerial是一套基于python實現(xiàn)serial port訪問的庫,該庫的設(shè)計者為Chris Liechti,該庫從2001年開始推出,一直持續(xù)更新至今,pzh-py-com使用的是pySerial 3.4?! ySerial的使用非常簡單,可在其官網(wǎng)瀏覽一遍其提供的API:https://pythonhosted.org/pyserial/pyserial_api.html,下面痞子衡整理了比較常用的API如下:
class Serial(SerialBase):
# 初始化串口參數(shù)
def __init__(self, *args, **kwargs):
# 打開串口
def open(self):
# 關(guān)閉串口
def close(self):
# 獲取串口打開狀態(tài)
def isOpen(self):
# 設(shè)置input_buffer/output_buffer大小
def set_buffer_size(self, rx_size=4096, tx_size=None):
# 獲取input_buffer(接收緩沖區(qū))里的byte數(shù)據(jù)個數(shù)
def inWaiting(self):
# 從串口讀取size個byte數(shù)據(jù)
def read(self, size=1):
# 清空input_buffer
def reset_input_buffer(self):
# 向串口寫入data里所有數(shù)據(jù)
def write(self, data):
# 等待直到output_buffer里的數(shù)據(jù)全部發(fā)送出去
def flush(self):
# 清空output_buffer
def reset_output_buffer(self):
pySerial常用參數(shù)整理如下,需要特別強調(diào)的是任何運行時刻對如下參數(shù)進行修改,均是直接應(yīng)用生效的,不需要重新調(diào)用open()和close()去激活,因為參數(shù)的修改在pySerial內(nèi)部是通過與參數(shù)同名的方法實現(xiàn)的,而這些方法均調(diào)用了Serial里的一個叫_reconfigure_port()的方法實現(xiàn)的。
二、JaysPyCOM串口功能實現(xiàn)
串口功能代碼實現(xiàn)主要分為三大部分:配置功能實現(xiàn)、接收功能實現(xiàn)、發(fā)送功能實現(xiàn)。在實現(xiàn)這些功能之前首先需要import兩個module,分別是serial、threading,serial就是pySerial庫;threading是python自帶線程庫,其具體作用下面代碼里會介紹。 除此以外還定義兩個全局變量,s_serialPort和s_recvInterval,s_serialPort是串口設(shè)備object實例,s_recvInterval是線程間隔時間。
import serial
import threading
s_serialPort = serial.Serial()
s_recvInterval = 0.5
2.1串口配置功能
串口配置里主要就是實現(xiàn)GUI界面上"Open"按鈕的回調(diào)函數(shù),即openClosePort(),軟件剛打開時所有可用Port默認是Close狀態(tài),如果用戶選定了配置參數(shù)(串口號、波特率...),并點擊了"Open"按鈕,此時便會觸發(fā)openClosePort()的執(zhí)行,在openClosePort()里我們需要配置s_serialPort的參數(shù)并打開指定的串口設(shè)備。
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指定的串口設(shè)備
s_serialPort.open()
self.m_button_openClose.SetLabel('Close')
s_serialPort.reset_input_buffer()
s_serialPort.reset_output_buffer()
# 開啟串口接收線程(每0.5秒定時執(zhí)行一次)
threading.Timer(s_recvInterval, self.recvData).start()
上述代碼里需要特別講一下的是串口接收線程,我們知道串口設(shè)備s_serialPort一旦打開之后,只要該串口設(shè)備的RXD信號線上有數(shù)據(jù)傳輸,pySerial底層會自動將其存入s_serialPort對應(yīng)的input_buffer里,但并不會主動通知我們。那我們怎么知道input_buffer里有沒有數(shù)據(jù)?此時就需要我們開啟一個定時執(zhí)行的線程,線程里會去查看input_buffer里是否有數(shù)據(jù),如果有數(shù)據(jù)便顯示出來,因此在串口設(shè)備打開的同時我們需要創(chuàng)建一個串口接收線程recvData()。
2.2串口接收功能
串口接收功能其實在串口配置里已經(jīng)提到了,主要就是串口接收線程recvData()的實現(xiàn),recvData()實現(xiàn)很簡單,只有一個注意點,那就是threading.Timer()的用法,這是個軟件定時器,它只能超時觸發(fā)一次任務(wù)的執(zhí)行,如果想讓任務(wù)循環(huán)觸發(fā),那么需要在任務(wù)本身里添加threading.Timer()的調(diào)用。
def clearRecvDisplay( self, event ):
self.m_textCtrl_recv.Clear()
def setRecvFormat( self, event ):
event.Skip()
def recvData( self ):
if s_serialPort.isOpen():
# 獲取input_buffer里的數(shù)據(jù)個數(shù)
num = s_serialPort.inWaiting()
if num != 0:
# 獲取input_buffer里的數(shù)據(jù)并顯示在GUI界面的接收顯示框里
data = s_serialPort.read(num)
self.m_textCtrl_recv.write(data)
# 這一句是線程能夠定時執(zhí)行的關(guān)鍵
threading.Timer(s_recvInterval, self.recvData).start()
2.3串口發(fā)送功能
串口發(fā)送功能相比串口接收功能就簡單多了,串口發(fā)送主要就是實現(xiàn)GUI界面上"Send"按鈕的回調(diào)函數(shù),即sendData(),代碼實現(xiàn)比較簡單,不予贅述。
def clearSendDisplay( self, event ):
self.m_textCtrl_send.Clear()
def setSendFormat( self, event ):
event.Skip()
def sendData( self, event ):
if s_serialPort.isOpen():
# 獲取發(fā)送輸入框里的數(shù)據(jù)并通過串口發(fā)送出去
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')
目前串口收發(fā)與顯示實現(xiàn)均是基于字符方式,即發(fā)送輸入框、接收顯示框里僅支持ASCII碼字符串,關(guān)于Char/Hex顯示轉(zhuǎn)換的功能(setRecvFormat()/setSendFormat())并未加上,后續(xù)優(yōu)化里會進一步做。
至此,串口調(diào)試工具pzh-py-com誕生之串口功能實現(xiàn)痞子衡便介紹完畢了,掌聲在哪里~~~