Python模擬串口通信的示例詳解
本次分享利用Python模擬串口通信案例。當(dāng)前編程環(huán)境,并沒(méi)有辦法接好下位機(jī)平臺(tái),需要模擬出一個(gè)串口,不斷發(fā)送、接收信息的過(guò)程。
串行通信端口(cluster communication port ),簡(jiǎn)稱串口,即COM口。
pySerial 是 Python 中用于操作串口的第三方模塊,它支持 Windows、Linux、OSX、BSD等多個(gè)平臺(tái)。
1.win 下載虛擬串口
下載: sourceforge.net/projects/com0com/files/latest/download
下載安裝完成后,會(huì)在設(shè)備管理器中新增兩個(gè)com。
這兩個(gè)串口是互相接通的,一個(gè)com 可以當(dāng)作上位機(jī),一個(gè)com可以當(dāng)作下位機(jī)。創(chuàng)建的一對(duì)虛擬串口。

或者利用虛擬串口的軟件創(chuàng)建,VSPD(Virtual Serial Port Driver)
2、確定串口號(hào)
pyserial模塊封裝了python對(duì)串口的訪問(wèn),為多平臺(tái)的使用提供了統(tǒng)一的接口。
import serial
import serial.tools.list_ports
# 獲取所有串口設(shè)備實(shí)例。
port_list = list(serial.tools.list_ports.comports())
def show_all_com():
# 如果找到串口設(shè)備,則依次輸出每個(gè)設(shè)備對(duì)應(yīng)的串口號(hào)和描述信息。
port_list_name = []
if len(port_list) <= 0:
print("the serial port can't find!")
else:
for itms in port_list:
print(list(itms)[0], list(itms)[1])
port_list_name.append(itms.device)
return port_list_name
運(yùn)行結(jié)果
COM1 通信端口 (COM1)
COM3 com0com - serial port emulator (COM3)
COM4 com0com - serial port emulator (COM4)
['COM1', 'COM3', 'COM4']
3、配置串口
import serial
# 打開(kāi) COM3,將波特率配置為115200,數(shù)據(jù)位為7,停止位為2,無(wú)校驗(yàn)位,讀超時(shí)時(shí)間為0.5秒。
ser = serial.Serial(port="COM3",
baudrate=115200,
bytesize=serial.SEVENBITS,
parity=serial.PARITY_NONE,
stopbits=serial.STOPBITS_TWO,
timeout=0.5)
常用的參數(shù)如下:
port - 串口設(shè)備名或 None。
baudrate - 波特率,可以是50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800, 9600, 19200, 38400, 57600, 115200, 230400, 460800, 500000, 576000, 921600, 1000000, 1152000, 1500000, 2000000, 2500000, 3000000, 3500000, 4000000。
bytesize - 數(shù)據(jù)位,可取值為:FIVEBITS, SIXBITS, SEVENBITS, EIGHTBITS。
parity - 校驗(yàn)位,可取值為:PARITY_NONE, PARITY_EVEN, PARITY_ODD, PARITY_MARK, PARITY_SPACE。
stopbits - 停止位,可取值為:STOPBITS_ONE, STOPBITS_ONE_POINT_FIVE, STOPBITS_TOW。
xonxoff - 軟件流控,可取值為 True, False。
rtscts - 硬件(RTS/CTS)流控,可取值為 True, False。
dsr/dtr - 硬件(DSR/DTR)流控,可取值為 True, False。
timeout - 讀超時(shí)時(shí)間,可取值為 None, 0 或者其他具體數(shù)值(支持小數(shù))。當(dāng)設(shè)置為 None 時(shí),表示阻塞式讀取,一直讀到期望的所有數(shù)據(jù)才返回;當(dāng)設(shè)置為 0 時(shí),表示非阻塞式讀取,無(wú)論讀取到多少數(shù)據(jù)都立即返回;當(dāng)設(shè)置為其他數(shù)值時(shí),表示設(shè)置具體的超時(shí)時(shí)間(以秒為單位),如果在該時(shí)間內(nèi)沒(méi)有讀取到所有數(shù)據(jù),則直接返回。
write_timeout: 寫(xiě)超時(shí)時(shí)間,可取值為 None, 0 或者其他具體數(shù)值(支持小數(shù))。參數(shù)值起到的效果參考 timeout 參數(shù)。
4、串口通信示例
python 實(shí)現(xiàn)向一個(gè)串口內(nèi)寫(xiě)數(shù)據(jù)(發(fā)送端),另一個(gè)串口內(nèi)接受數(shù)據(jù)(接收端)
1.串口類工具
串口類功能函數(shù)組成:打開(kāi)、關(guān)閉、發(fā)送數(shù)據(jù)、接受數(shù)據(jù)、解析保存數(shù)據(jù)功能
import serial
from time import sleep
import queue
import time
from datetime import datetime
q = queue.Queue()
class SerialPort:
def __init__(self, port, buand):
self.port = serial.Serial(port, buand)
self.port.close()
if not self.port.isOpen():
self.port.open()
def port_open(self):
if not self.port.isOpen():
self.port.open()
def port_close(self):
self.port.close()
#發(fā)送數(shù)據(jù)
def send_data(self):
"""
#write() 方法只能發(fā)送 bytes 類型的數(shù)據(jù),所以需要對(duì)字符串進(jìn)行 encode 編碼。
# write() 方法執(zhí)行完成后,會(huì)將發(fā)送的字節(jié)數(shù)作為返回值。
"""
while True: # 循環(huán)發(fā)送數(shù)據(jù)
date = datetime.now().strftime('%H:%M:%S.%f')[:-3]
print("send:", date)
self.port.write(date.encode())
time.sleep(1)
# 讀取數(shù)據(jù)
def read_data(self):
"""
# read()方法默認(rèn)一次讀取一個(gè)字節(jié),可以通過(guò)傳入?yún)?shù)指定每次讀取的字節(jié)數(shù);
read() 方法會(huì)將讀取的內(nèi)容作為返回值,類型為 bytes。
"""
while True:
count = self.port.inWaiting()
if count != 0:
recv = self.port.read(count)
self.port.flushInput()
q.put(recv.decode())
print("receive:",recv.decode())
sleep(0.5)
#解析保存數(shù)據(jù)
def save_json(self):
while True:
if q.empty():
pass
else:
print("隊(duì)列長(zhǎng)度",q.qsize())
data = q.get()
print(data)
sleep(0.1)
2.發(fā)送端
開(kāi)啟一個(gè)線程定時(shí)發(fā)送數(shù)據(jù)
from tools.LoRaSerial import SerialPort
import threading
from time import sleep
if __name__=='__main__':
baunRate = 115200
serialPort_w = "COM3"
mSerial_w = SerialPort(serialPort_w, baunRate)
t1 = threading.Thread(target=mSerial_w.send_data)
t1.daemon = True
t1.start()
while True:
sleep(10)
3.接收端
****接收端開(kāi)啟兩個(gè)線程接收數(shù)據(jù):讀取數(shù)據(jù)和解析存儲(chǔ)數(shù)據(jù)。
from tools.LoRaSerial import SerialPort
import threading
from time import sleep
if __name__=='__main__':
threads=[]
baunRate = 115200
serialPort_r = "COM4"
mSerial_r = SerialPort(serialPort_r, baunRate)
t2 = threading.Thread(target=mSerial_r.read_data)
threads.append(t2)
t3 = threading.Thread(target=mSerial_r.save_json)
threads.append(t3)
for t in threads:
t.start()
while True:
sleep(10)
5.運(yùn)行結(jié)果

從一個(gè)線程向另一個(gè)線程發(fā)送數(shù)據(jù)最安全的方式可能就是使用 queue 庫(kù)中的隊(duì)列了。創(chuàng)建一個(gè)被多個(gè)線程共享的 Queue 對(duì)象,這些線程通過(guò)使用put() 和 get() 操作來(lái)向隊(duì)列中添加或者刪除元素。
**當(dāng)終端發(fā)送數(shù)據(jù)量較大時(shí),其數(shù)據(jù)解析也是比較耗時(shí),可以用消息隊(duì)列緩存接收到的發(fā)送端數(shù)據(jù),當(dāng)接收線程進(jìn)行IO監(jiān)聽(tīng)時(shí),負(fù)責(zé)解析線程去消息隊(duì)列取消息并解析。如下圖,將解析過(guò)程時(shí)間延遲由0.1至2s。
**

為了方便模擬傳遞數(shù)據(jù)變化效果,這里用時(shí)間函數(shù)代替的,實(shí)際上設(shè)備傳遞具體消息可解析為具體的json數(shù)據(jù)格式****
| 消息類別 | Ori_ID****發(fā)送端設(shè)備ID | des_ID****接收端設(shè)備ID | CMD****消息類別 | VALUE****數(shù)組 | 消息方向 |
|---|---|---|---|---|---|
| 上線消息 | 1 | 123 | Online | [] | 終端—網(wǎng)關(guān) |
| 心跳消息 | 1 | 123 | Heart | [{“battery”:”60”}] | 終端—網(wǎng)關(guān) |
| 環(huán)境信息 | 1 | 123 | Env | [{“temp”:”35”},{“hum”:”66”}] | 終端—網(wǎng)關(guān) |
| 控制指令 | 1 | 123 | Alarm | [{“light”:”on”},{“pump”:”Stop”}] | 網(wǎng)關(guān)—終端 |
| 報(bào)警消息 | 123 | 1 | Control | [] | 終端—網(wǎng)關(guān) |
備注:
1、 上線消息-------終端啟動(dòng)時(shí)給網(wǎng)關(guān)發(fā)送上線的消息,網(wǎng)關(guān)返回該終端的各種數(shù)據(jù)及運(yùn)行狀態(tài)
2、 心跳消息--------終端定期發(fā)送心跳消息給網(wǎng)關(guān)
3、 環(huán)境信息--------終端定期上報(bào)各種環(huán)境參數(shù)
4、 控制指令-------網(wǎng)關(guān)發(fā)送指令給終端,實(shí)現(xiàn)對(duì)終端的控制,如開(kāi)燈、關(guān)燈等
5、 報(bào)警消息-------設(shè)備監(jiān)測(cè)到報(bào)警信息,發(fā)送報(bào)警信息給網(wǎng)關(guān)
以上就是Python模擬串口通信的示例詳解的詳細(xì)內(nèi)容,更多關(guān)于Python串口通信的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Python光學(xué)仿真從Maxwell方程組到波動(dòng)方程矢量算法理解學(xué)習(xí)
這篇文章主要為大家介紹了Python光學(xué)仿真從Maxwell方程組到波動(dòng)方程算法的理解學(xué)習(xí),有需要的朋友可以借鑒參考下,希望能夠有所幫助2021-10-10
np.concatenate()函數(shù)數(shù)組序列參數(shù)的實(shí)現(xiàn)
本文主要介紹了np.concatenate()函數(shù)數(shù)組序列參數(shù)的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-03-03
淺談python數(shù)據(jù)類型及類型轉(zhuǎn)換
這篇文章主要介紹了淺談python數(shù)據(jù)類型及類型轉(zhuǎn)換,介紹了python中的數(shù)據(jù)類型,以及數(shù)據(jù)的不可變性,還有字符串,列表等相關(guān)內(nèi)容,具有一定借鑒價(jià)值,需要的朋友可以參考下。2017-12-12
Springboo如何t動(dòng)態(tài)修改配置文件屬性
這篇文章主要介紹了Springboo如何t動(dòng)態(tài)修改配置文件屬性問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-09-09
python matplotlib工具欄源碼探析三之添加、刪除自定義工具項(xiàng)的案例詳解
這篇文章主要介紹了python matplotlib工具欄源碼探析三之添加、刪除自定義工具項(xiàng)的案例詳解,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-02-02

