首頁 > 軟體

Python應用開發之實現串列埠通訊

2022-11-03 14:01:18

前言

在嵌入式開發中我們經常會用到串列埠,串列埠通訊簡單,使用起來方便,且適用場景多,因此串列埠常常用來輸出偵錯Log或者跟其他外設進行通訊,也可以用作上位機和下位機之間的通訊。那這一講我就簡單介紹一下如何用Python編寫一個串列埠收發程式。

1.環境搭建

Python的環境這裡就不具體介紹了,網上教學也很多,我主要介紹一下我們這一講用到的類庫以及當前的版本。

packageversion
time注:python標準庫,無需安裝
pyserialv3.5

注:不懂如何安裝庫的同學請自行查閱資料。

特別說明:本文舉的例子皆是基於windows系統下python3來實現的,其他平臺不一定完全適配。

2.硬體準備

我們要通過電腦的USB介面傳送串列埠資料,在硬體上首先得保證有可用的串列埠裝置接入,並且正確的安裝了驅動。

我這裡用的是一個CH340的串列埠轉TTL的模組來測試的。

可以用兩個這種模組相互收發,也可以單個模組自發自收,或者接入其他嵌入式裝置也行。

硬體接入之後我們可以在裝置管理器看到裝置的埠號,如下圖所示:

3.程式碼編寫與測試

3.1 簡單測一下串列埠收發

範例程式碼如下:

import serial #匯入模組

try:
    # 埠號,根據自己實際情況輸入,可以在裝置管理器檢視
    port = "COM6"
    # 串列埠波特率,根據自己實際情況輸入
    bps = 9600
    # 超時時間,None:永遠等待操作,0為立即返回請求結果,其他值為等待超時時間(單位為秒)
    time = 5
    # 開啟串列埠,並返回串列埠物件
    uart = serial.Serial(port, bps, timeout = time)

    # 串列埠傳送一個字串
    len = uart.write("hello world".encode('utf-8')) 
    print("send len: ", len)

    # 串列埠接收一個字串
    str = ''
    for i in range(len):
        str += uart.read().decode("utf-8")
    print("receive data: ", str)

    # 關閉串列埠
    uart.close()

except Exception as result:
    print("******error******:", result)

執行測試:

我這裡是自發自收,如果執行沒有出錯並且成功傳送和接收到正確的資料,說明串列埠通訊是走通了,那麼接下來就可以繼續完善這個流程。
如果出現其他問題,則需要檢查硬體和軟體,確保所有設定都沒問題才能繼續進行下一步。

3.2 補充細節

1、串列埠傳送各種不同型別的資料。

串列埠資料常用字串和十六進位制(hex)表示。下面列舉了一些例子,可以作為一種參考。

範例如下:

data1 = "hello world"        # 字串
data2 = b"hello world"       # bytes
data3 = "你好"               # 中文字串
data4 = 0x0A                 # 整形(以16進位製表示)
data5 = [0x10, 0x11, 0x12]   # 列表/陣列(以16進位製表示)

len = uart.write(data1.encode('utf-8'))         # 傳送字串"hello world"
len = uart.write(data2)                         # 傳送字串"hello world"
len = uart.write(data3.encode('utf-8'))         # 以utf-8編碼方式傳送字串"你好"(6位元組)
len = uart.write(data3.encode('gbk'))           # 以gbk編碼方式傳送字串"你好"(4位元組)
len = uart.write(chr(data4.encode("utf-8"))     # 傳送16進位制資料0x0A(1位元組)
for x in data5:                                 # 遍歷列表/陣列的所有元素並依次傳送
    len = uart.write(chr(x).encode("utf-8")) 

2、完善串列埠接收流程

串列埠接收跟傳送一樣,接收資料也是常用字串和十六進位制(hex)表示。

可以根據以下兩種方式接收資料:

str = uart.read(uart.in_waiting).decode("utf-8")   # 以字串接收
str = uart.read().hex()                            # 以16進位制(hex)接收

接收的時間很短,大部分時間其實是在等待接收,所以我們需要加一個死迴圈或者回圈執行緒來確保串列埠一直在等待接收。

範例如下:

while True:
    if uart.in_waiting:
        # str = uart.read(uart.in_waiting).decode("utf-8")   # 以字串接收
        str = uart.read().hex()                            # 以16進位制(hex)接收
        print(str)                                         # 列印資料

3、掃描埠

在不知道串列埠埠號的情況下可以先掃描一下可用的埠。

範例如下:

import serial 
import serial.tools.list_ports

port_list = list(serial.tools.list_ports.comports())
print(port_list)
if len(port_list) == 0:
   print('無可用串列埠')
else:
    for i in range(0,len(port_list)):
        print(port_list[i])

3.3 完善整個收發流程

根據上面舉的一些例子,我們把整個流程補充完整。

範例如下:

# 匯入模組
import threading
import time
import serial
import serial.tools.list_ports

# 自定義變數
port = "COM6"  # 埠號,根據自己實際情況輸入,可以在裝置管理器檢視
bps = 9600     # 串列埠波特率,根據自己實際情況輸入
timeout = 5       # 超時時間,None:永遠等待操作,0為立即返回請求結果,其他值為等待超時時間(單位為秒)
rxdata = ''    # 接收的資料

# 掃描埠
def check_uart_port():
    port_list = list(serial.tools.list_ports.comports())
    # print(port_list)
    if len(port_list) == 0:
        print('can not fine uart port')
        return False
    else:
        for i in range(0,len(port_list)):
            print(port_list[i])
    return True

# 開啟串列埠
def open_uart(port, bps, timeout):
    try:
        # 開啟串列埠,並返回串列埠物件
        uart = serial.Serial(port, bps, timeout=timeout)
        return uart
    except Exception as result:
        print("can not open uart")
        print(result)
        return False

# 傳送資料
def uart_send_data(uart, txbuf):
    len = uart.write(txbuf.encode('utf-8'))  # 寫資料
    return len

# 接收資料
def uart_receive_data(uart):
    if uart.in_waiting:
        rxdata = uart.read(uart.in_waiting).decode("utf-8")   # 以字串接收
        # rxdata = uart.read().hex()  # 以16進位制(hex)接收
        print(rxdata)  # 列印資料

# 關閉串列埠
def close_uart(uart):
    uart.close()

# 建立一個執行緒用來等待串列埠接收資料
class myThread (threading.Thread):   # 繼承父類別threading.Thread
    def __init__(self, uart):
        threading.Thread.__init__(self)
        self.uart = uart
    def run(self):                   # 把要執行的程式碼寫到run函數裡面 執行緒在建立後會直接執行run函數
        while True:
            # print("thread_uart_receive")
            uart_receive_data(self.uart)  # 接收資料
            # time.sleep(0.01)

# 主函數
def main():
    # 掃描埠
    result = check_uart_port()
    if(result == False):
        return

    # 開啟串列埠
    result = open_uart(port, bps, timeout)
    if (result == False):
        return
    else:
        uart1 = result

    # 建立一個執行緒用來接收串列埠資料
    thread_uart = myThread(uart1)
    thread_uart.start()

    while True:
        # 定時傳送資料
        txbuf = "hello world"
        len = uart_send_data(uart1, txbuf)
        print("send len: ", len)
        time.sleep(1)

# 啟動主函數
main()

執行測試:

這裡還是自發自收,但是改成定時1s迴圈傳送一幀資料,如果是實際使用的話就不要短接TX和RX了,串列埠是全雙工,收發是可以同步進行的。

以上就是Python應用開發之實現串列埠通訊的詳細內容,更多關於Python串列埠通訊的資料請關注it145.com其它相關文章!


IT145.com E-mail:sddin#qq.com