使用Python串列埠實時顯示資料並繪圖的例子
使用pyserial進行串列埠傳輸
一、安裝pyserial以及基本用法
在cmd下輸入命令pip install pyserial
注:升級pip後會出現 "‘E:\Anaconda3\Scripts\pip-script.py' is not present."錯誤
使用 easy_install pip命令就能解決,換一條重新能執行安裝的命令
常用方法:
ser = serial.Serial(0) 是開啟第一個串列埠
print ser.portstr 能看到第一個串列埠的標識,windows下是COM1
ser.write(“hello") 就是往串口裡面寫資料
ser.close() 就是關閉ser表示的串列埠
ser.open() 會開啟這個串列埠
ser = serial.Serial(‘COM1',115200) 來設定波特率,當然還有專門的函式
data = ser.read()可以讀一個字元
data = ser.read(20) 是讀20個字元
data = ser.readline() 是讀一行,以/n結束,要是沒有/n就一直讀,阻塞。
data = ser.readlines()和ser.xreadlines()都需要設定超時時間
ser.baudrate = 9600 設定波特率
ser 來檢視當前串列埠的狀態
ser.isOpen() 看看這個串列埠是否已經被開啟
序列口的屬性:
name:裝置名字 portstr:已廢棄,用name代替 port:讀或者寫埠 baudrate:波特率
bytesize:位元組大小 parity:校驗位 stopbits:停止位 timeout:讀超時設定
writeTimeout:寫超時 xonxoff:軟體流控 rtscts:硬體流控 dsrdtr:硬體流控
interCharTimeout:字元間隔超時
二、最基本的串列埠程式碼
import serial portx="COM5" bps=9600 timex=5 #串列埠執行到這已經開啟 再用open命令會報錯 ser = serial.Serial(portx,int(bps),timeout=1,parity=serial.PARITY_NONE,stopbits=1) if (ser.isOpen()): print("open success") # 向埠些資料 字串必須譯碼 ser.write("hello".encode()) while (True): line = ser.readline() if(line): print(line) line=0 else: print("open failed") ser.close()#關閉埠 )
三、pyqtgraph的使用
pip install pyqtgraph#顯示波形的介面
pip install PyQt5#介面要Qt的支援
pyqtgraph是Python平臺上一種功能強大的2D/3D繪相簿,相對於matplotlib庫,由於內部實現方式上,使用了高速計算的numpy訊號處理庫以及Qt的GraphicsView框架,因此,它在大資料量的數字處理和快速顯示方面有著巨大的優勢,它適合於需要快速繪圖更新、視訊或實時互動性的操作場合。另外,它不僅為各種資料提供了快速可互動式的圖形顯示,同時也提供了用於快速開發應用程式的各種小工具,如屬性樹、流程圖等小部件,在數學、科學和工程領域都有著廣泛的應用。
import pyqtgraph as pg import numpy as np import array app = pg.mkQApp()#建立app win = pg.GraphicsWindow()#建立視窗 win.setWindowTitle(u'pyqtgraph逐點畫波形圖') win.resize(800,500)#小視窗大小 data = array.array('d') #可動態改變陣列的大小,double型陣列 historyLength = 100#橫座標長度 p = win.addPlot()#把圖p加入到視窗中 p.showGrid(x=True,y=True)#把X和Y的表格開啟 p.setRange(xRange=[0,historyLength],yRange=[-1.2,1.2],padding=0) p.setLabel(axis='left',text='y / V')#靠左 p.setLabel(axis='bottom',text='x / point') p.setTitle('y = sin(x)')#表格的名字 curve = p.plot()#繪製一個圖形 idx = 0 def plotData(): global idx#內部作用域想改變外部域變數 tmp = np.sin(np.pi / 50 * idx) if len(data)<historyLength: data.append(tmp) else: data[:-1] = data[1:]#前移 data[-1] = tmp curve.setData(data) idx += 1 timer = pg.QtCore.QTimer() timer.timeout.connect(plotData)#定時呼叫plotData函式 timer.start(50)#多少ms呼叫一次 app.exec_()
四、通過多執行緒實現串列埠資料的實時繪圖import pyqtgraph as pg
主要是開了一個執行緒去處理串列埠 剩下的和上面內容一樣 就不過多解釋了 直接上程式碼
import array import serial import threading import numpy as np import time i = 0 def Serial(): while(True): n = mSerial.inWaiting() if(n): if data!=" ": dat = int.from_bytes(mSerial.readline(1),byteorder='little') # 格式轉換 n=0 global i; if i < historyLength: data[i] = dat i = i+1 else: data[:-1] = data[1:] data[i-1] = dat def plotData(): curve.setData(data) if __name__ == "__main__": app = pg.mkQApp() # 建立app win = pg.GraphicsWindow() # 建立視窗 win.setWindowTitle(u'pyqtgraph逐點畫波形圖') win.resize(800,500) # 小視窗大小 data = array.array('i') # 可動態改變陣列的大小,double型陣列 historyLength = 200 # 橫座標長度 a = 0 data=np.zeros(historyLength).__array__('d')#把陣列長度定下來 p = win.addPlot() # 把圖p加入到視窗中 p.showGrid(x=True,y=True) # 把X和Y的表格開啟 p.setRange(xRange=[0,yRange=[0,255],padding=0) p.setLabel(axis='left',text='y / V') # 靠左 p.setLabel(axis='bottom',text='x / point') p.setTitle('semg') # 表格的名字 curve = p.plot() # 繪製一個圖形 curve.setData(data) portx = 'COM24' bps = 19200 # 串列埠執行到這已經開啟 再用open命令會報錯 mSerial = serial.Serial(portx,int(bps)) if (mSerial.isOpen()): print("open success") mSerial.write("hello".encode()) # 向埠些資料 字串必須譯碼 mSerial.flushInput() # 清空緩衝區 else: print("open failed") serial.close() # 關閉埠 th1 = threading.Thread(target=Serial)#目標函式一定不能帶()被這個BUG搞了好久 th1.start() timer = pg.QtCore.QTimer() timer.timeout.connect(plotData) # 定時重新整理資料顯示 timer.start(50) # 多少ms呼叫一次 app.exec_()
效果如圖
五、與下位機通訊實現波形實時監測
在這裡與第四階段基本相同,需要注意的是,如果收資料直接畫圖的話,波形會出現問題。所以串列埠傳輸資料時使用迴圈佇列(先進先出),資料來之後先進佇列,之後再定時器呼叫函式,出佇列,更新圖。理論上重新整理資料的時間需要大於下位機發送資料的間隔時間,否則佇列會越來越大,而且圖的重新整理不連貫。再就是有一個小問題,因為正弦波有負值,我又沒找到很好的把Byte轉為char的方法,所以只能手動程式碼處理,先轉成int型別,再把第八位(符號位)清零,得到絕對值。然後再取負,得到我們需要的資料。但發現Python無法進行移位操作,python是int型別是無精度型別,不會發生溢位而進行擷取的情況,所以只能先轉為二進位制在移位,太麻煩,直接通過減去一個數的方法來實現了。然後直接上程式碼吧
import pyqtgraph as pg import array import serial import threading import numpy as np from queue import Queue import time i = 0 q = Queue(maxsize=0) def Serial(): global i; global q; while(True): n = mSerial.inWaiting() if(n): dat = int.from_bytes(mSerial.readline(1),byteorder='little') # 格式轉換 if(dat>>7): dat =256-dat dat =0-dat q.put(dat) def plotData(): global i; if i < historyLength: data[i] = q.get() i = i+1 else: data[:-1] = data[1:] data[i-1] = q.get() curve.setData(data) if __name__ == "__main__": app = pg.mkQApp() # 建立app win = pg.GraphicsWindow() # 建立視窗 win.setWindowTitle(u'pyqtgraph逐點畫波形圖') win.resize(800,double型陣列 historyLength = 100 # 橫座標長度 a = 0 data=np.zeros(historyLength).__array__('d')#把陣列長度定下來 p = win.addPlot() # 把圖p加入到視窗中 p.showGrid(x=True,yRange=[-50,50],text='x / point') p.setTitle('semg') # 表格的名字 curve = p.plot() # 繪製一個圖形 curve.setData(data) portx = 'COM25' bps = 19200 # 串列埠執行到這已經開啟 再用open命令會報錯 mSerial = serial.Serial(portx,int(bps)) if (mSerial.isOpen()): dat = 0xff; dat >> 2; print("open success") # 向埠些資料 字串必須譯碼 mSerial.write("hello".encode()) mSerial.flushInput() # 清空緩衝區 else: print("open failed") serial.close() # 關閉埠 th1 = threading.Thread(target=Serial) th1.start() timer = pg.QtCore.QTimer() timer.timeout.connect(plotData) # 定時重新整理資料顯示 timer.start(1) # 多少ms呼叫一次 app.exec_()
以上這篇使用Python串列埠實時顯示資料並繪圖的例子就是小編分享給大家的全部內容了,希望能給大家一個參考,也希望大家多多支援我們。