python 制作串口工具(一)

個(gè)人博客

所有文章除特別聲明外,均采用 CC BY-NC-SA 4.0 許可協(xié)議。轉(zhuǎn)載請(qǐng)注明來(lái)自 nixgnauhcuy's blog!

如需轉(zhuǎn)載,請(qǐng)標(biāo)明出處!

Life is short, you need Python. —— Bruce Eckel

前言

工作中偶爾會(huì)用到 python 來(lái)制作一些小工具,所以針對(duì)這些小工具,做了些簡(jiǎn)化,移除了一些比較復(fù)雜的功能,拿來(lái)分享。


UI 界面

在實(shí)現(xiàn)具體邏輯之前,我們要先設(shè)計(jì)好串口工具的 UI 界面,這里我直接使用的 Qt Designer 來(lái)設(shè)計(jì)串口界面的布局。

最終效果布置好布局后是這樣的:

image

實(shí)際預(yù)覽效果:

image

實(shí)現(xiàn)

打開 Qt Designer,點(diǎn)擊新建 Main Window 窗體,

image

進(jìn)入項(xiàng)目界面后,我們需要往里面拖入我們需要的控件,先添加兩個(gè) QGroupBox 控件并且設(shè)置文本為串口接收設(shè)置和串口發(fā)送設(shè)置, 一個(gè)作為我們的接收區(qū),一個(gè)作為我們的發(fā)送區(qū)。

image

上面操作完成后,我們先來(lái)布置我們的接收區(qū),先添加 Label 控件,分別設(shè)置文本為串口選擇、波特率、停止位、數(shù)據(jù)位、校驗(yàn)位的五個(gè) Label 控件。

image

然后,我們要增加組合框,方便后面選擇串口的參數(shù),同樣從左邊拖出五個(gè) Combo Box 控件,然后雙擊控件,這里我只拿波特率的組合框來(lái)描述,其他的例如停止位數(shù)據(jù)位還有校驗(yàn)位的操作是一樣的,除了串口選擇的組合框不用設(shè)置外,其他的都要設(shè)置。

image

雙擊波特率的組合框控件后,點(diǎn)擊左下的 + 號(hào),增加我們可選的波特率就可以了。

image

其他的 Combo Box 控件設(shè)置如下:

停止位分別設(shè)置 1、1.5、2 三個(gè)選項(xiàng)

數(shù)據(jù)位分別設(shè)置 8、7、6、5 四個(gè)選項(xiàng)

校驗(yàn)位分別設(shè)置 None、Odd、Even 三個(gè)選項(xiàng)

這樣就把常用的波特率、停止位、數(shù)據(jù)位和校驗(yàn)位的選項(xiàng)框設(shè)置好了。

接下來(lái),我們?cè)黾觾蓚€(gè) RadioButton 和一個(gè) Check Box 控件,分別設(shè)置兩個(gè) RadioButton 文本為 ASCIIHEX,設(shè)置 Check Box 文本為時(shí)間戳

image

最后,增加兩個(gè) Push Button 控件還有一個(gè) TextEdit 控件,Push Button 分別將文本命名為清除接收打開串口

image

這樣基本上接收區(qū)就設(shè)置完畢了。


接下來(lái)是發(fā)送區(qū),發(fā)送區(qū)中 Label、TextEdit、RadioButton、 Push Button 還有 Check Box 上面已經(jīng)說(shuō)過(guò)了,同樣設(shè)置一下就可以了,這里就不占用太多篇幅了。

image

隨后,我們要添加一個(gè) LineEdit 控件,后面可以作為定時(shí)發(fā)送的時(shí)間。

image

這樣,發(fā)送區(qū)也設(shè)置完畢了。


上面的接收區(qū)和發(fā)送區(qū)做完后,我們要將控件擺放整齊,并且設(shè)置控件的 objectName,方便后面編寫程序調(diào)用控件時(shí),一眼就知道編輯的是哪個(gè)控件。

控件的擺放我就不過(guò)多贅述了,無(wú)非就是調(diào)整位置和寬高,這里我標(biāo)注一下我設(shè)置的控件 objectName,不然后面看代碼的時(shí)候就不知道我是對(duì)哪個(gè)控件操作。

image

生成對(duì)應(yīng)的 .py 文件

完成后,我們保存我們做好的 UI 到工程下,這里我將文件命名為 uart_tool_ui.ui 然后保存到后面要編寫串口工具的工程目錄下。保存的 .ui 文件還不能直接使用,要將它轉(zhuǎn)為 .py 文件,方便后續(xù)調(diào)用,這里我使用的編譯器是 vscode,使用 vscode 將 .ui 轉(zhuǎn)為 .py 輸出,vscode 要安裝 pyqt 的擴(kuò)展,這里我就不多說(shuō)了,網(wǎng)上搜一下就可以了,我就直接貼上轉(zhuǎn)化好的 .py 代碼。

uart_tool_ui.py

# -*- coding: utf-8 -*-

# Form implementation generated from reading ui file 'd:\test\my\python_uart_tool\uart_tool_ui.ui'
#
# Created by: PyQt5 UI code generator 5.13.0
#
# WARNING! All changes made in this file will be lost!


from PyQt5 import QtCore, QtGui, QtWidgets


class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(800, 506)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.groupBox = QtWidgets.QGroupBox(self.centralwidget)
        self.groupBox.setGeometry(QtCore.QRect(10, 10, 781, 291))
        self.groupBox.setObjectName("groupBox")
        self.timestamp_check_box = QtWidgets.QCheckBox(self.groupBox)
        self.timestamp_check_box.setGeometry(QtCore.QRect(10, 225, 61, 16))
        self.timestamp_check_box.setObjectName("timestamp_check_box")
        self.label_7 = QtWidgets.QLabel(self.groupBox)
        self.label_7.setGeometry(QtCore.QRect(10, 175, 54, 12))
        self.label_7.setObjectName("label_7")
        self.rec_hex_radio_button = QtWidgets.QRadioButton(self.groupBox)
        self.rec_hex_radio_button.setGeometry(QtCore.QRect(70, 200, 41, 16))
        self.rec_hex_radio_button.setObjectName("rec_hex_radio_button")
        self.com_combo_box = QtWidgets.QComboBox(self.groupBox)
        self.com_combo_box.setGeometry(QtCore.QRect(10, 50, 141, 22))
        self.com_combo_box.setObjectName("com_combo_box")
        self.stopbit_combo_box = QtWidgets.QComboBox(self.groupBox)
        self.stopbit_combo_box.setGeometry(QtCore.QRect(58, 110, 91, 22))
        self.stopbit_combo_box.setObjectName("stopbit_combo_box")
        self.stopbit_combo_box.addItem("")
        self.stopbit_combo_box.addItem("")
        self.stopbit_combo_box.addItem("")
        self.label_6 = QtWidgets.QLabel(self.groupBox)
        self.label_6.setGeometry(QtCore.QRect(10, 145, 54, 12))
        self.label_6.setObjectName("label_6")
        self.baud_combo_box = QtWidgets.QComboBox(self.groupBox)
        self.baud_combo_box.setGeometry(QtCore.QRect(58, 80, 91, 22))
        self.baud_combo_box.setObjectName("baud_combo_box")
        self.baud_combo_box.addItem("")
        self.baud_combo_box.addItem("")
        self.baud_combo_box.addItem("")
        self.baud_combo_box.addItem("")
        self.baud_combo_box.addItem("")
        self.baud_combo_box.addItem("")
        self.baud_combo_box.addItem("")
        self.baud_combo_box.addItem("")
        self.baud_combo_box.addItem("")
        self.baud_combo_box.addItem("")
        self.baud_combo_box.addItem("")
        self.baud_combo_box.addItem("")
        self.baud_combo_box.addItem("")
        self.baud_combo_box.addItem("")
        self.baud_combo_box.addItem("")
        self.baud_combo_box.addItem("")
        self.baud_combo_box.addItem("")
        self.baud_combo_box.addItem("")
        self.baud_combo_box.addItem("")
        self.baud_combo_box.addItem("")
        self.baud_combo_box.addItem("")
        self.baud_combo_box.addItem("")
        self.label_5 = QtWidgets.QLabel(self.groupBox)
        self.label_5.setGeometry(QtCore.QRect(10, 115, 54, 12))
        self.label_5.setObjectName("label_5")
        self.label_4 = QtWidgets.QLabel(self.groupBox)
        self.label_4.setGeometry(QtCore.QRect(10, 85, 54, 12))
        self.label_4.setObjectName("label_4")
        self.checkbit_combo_box = QtWidgets.QComboBox(self.groupBox)
        self.checkbit_combo_box.setGeometry(QtCore.QRect(58, 170, 91, 22))
        self.checkbit_combo_box.setObjectName("checkbit_combo_box")
        self.checkbit_combo_box.addItem("")
        self.checkbit_combo_box.addItem("")
        self.checkbit_combo_box.addItem("")
        self.label_3 = QtWidgets.QLabel(self.groupBox)
        self.label_3.setGeometry(QtCore.QRect(10, 22, 54, 20))
        self.label_3.setObjectName("label_3")
        self.databit_combo_box = QtWidgets.QComboBox(self.groupBox)
        self.databit_combo_box.setGeometry(QtCore.QRect(58, 140, 91, 22))
        self.databit_combo_box.setObjectName("databit_combo_box")
        self.databit_combo_box.addItem("")
        self.databit_combo_box.addItem("")
        self.databit_combo_box.addItem("")
        self.databit_combo_box.addItem("")
        self.uart_en_push_button = QtWidgets.QPushButton(self.groupBox)
        self.uart_en_push_button.setGeometry(QtCore.QRect(10, 250, 141, 23))
        self.uart_en_push_button.setObjectName("uart_en_push_button")
        self.rec_ascii_radio_button = QtWidgets.QRadioButton(self.groupBox)
        self.rec_ascii_radio_button.setGeometry(QtCore.QRect(10, 200, 51, 16))
        self.rec_ascii_radio_button.setObjectName("rec_ascii_radio_button")
        self.uart_rec_show = QtWidgets.QTextEdit(self.groupBox)
        self.uart_rec_show.setGeometry(QtCore.QRect(170, 10, 601, 271))
        self.uart_rec_show.setFocusPolicy(QtCore.Qt.NoFocus)
        self.uart_rec_show.setObjectName("uart_rec_show")
        self.uart_clear_rec_push_button = QtWidgets.QPushButton(self.groupBox)
        self.uart_clear_rec_push_button.setGeometry(QtCore.QRect(70, 220, 71, 23))
        self.uart_clear_rec_push_button.setObjectName("uart_clear_rec_push_button")
        self.groupBox_2 = QtWidgets.QGroupBox(self.centralwidget)
        self.groupBox_2.setGeometry(QtCore.QRect(10, 300, 781, 151))
        self.groupBox_2.setObjectName("groupBox_2")
        self.send_ascii_radio_button = QtWidgets.QRadioButton(self.groupBox_2)
        self.send_ascii_radio_button.setGeometry(QtCore.QRect(10, 20, 51, 16))
        self.send_ascii_radio_button.setObjectName("send_ascii_radio_button")
        self.send_hex_radio_button = QtWidgets.QRadioButton(self.groupBox_2)
        self.send_hex_radio_button.setGeometry(QtCore.QRect(70, 20, 41, 16))
        self.send_hex_radio_button.setObjectName("send_hex_radio_button")
        self.uart_timer_check_box = QtWidgets.QCheckBox(self.groupBox_2)
        self.uart_timer_check_box.setGeometry(QtCore.QRect(10, 47, 47, 16))
        self.uart_timer_check_box.setObjectName("uart_timer_check_box")
        self.uart1_ms_label = QtWidgets.QLabel(self.groupBox_2)
        self.uart1_ms_label.setGeometry(QtCore.QRect(140, 45, 20, 20))
        self.uart1_ms_label.setObjectName("uart1_ms_label")
        self.uart_timer_line_edit = QtWidgets.QLineEdit(self.groupBox_2)
        self.uart_timer_line_edit.setGeometry(QtCore.QRect(70, 45, 61, 20))
        self.uart_timer_line_edit.setObjectName("uart_timer_line_edit")
        self.uart_send_push_button = QtWidgets.QPushButton(self.groupBox_2)
        self.uart_send_push_button.setGeometry(QtCore.QRect(80, 70, 75, 23))
        self.uart_send_push_button.setObjectName("uart_send_push_button")
        self.uart_send_clear_push_button = QtWidgets.QPushButton(self.groupBox_2)
        self.uart_send_clear_push_button.setGeometry(QtCore.QRect(0, 70, 75, 23))
        self.uart_send_clear_push_button.setObjectName("uart_send_clear_push_button")
        self.uart_send_show = QtWidgets.QTextEdit(self.groupBox_2)
        self.uart_send_show.setGeometry(QtCore.QRect(170, 10, 601, 131))
        self.uart_send_show.setFocusPolicy(QtCore.Qt.NoFocus)
        self.uart_send_show.setObjectName("uart_send_show")
        self.label = QtWidgets.QLabel(self.groupBox_2)
        self.label.setGeometry(QtCore.QRect(10, 100, 18, 12))
        self.label.setObjectName("label")
        self.uart_tx_data_count_label = QtWidgets.QLabel(self.groupBox_2)
        self.uart_tx_data_count_label.setGeometry(QtCore.QRect(30, 120, 100, 12))
        self.uart_tx_data_count_label.setObjectName("uart_tx_data_count_label")
        self.uart_rx_data_count_label = QtWidgets.QLabel(self.groupBox_2)
        self.uart_rx_data_count_label.setGeometry(QtCore.QRect(30, 100, 100, 12))
        self.uart_rx_data_count_label.setObjectName("uart_rx_data_count_label")
        self.label_2 = QtWidgets.QLabel(self.groupBox_2)
        self.label_2.setGeometry(QtCore.QRect(10, 120, 18, 12))
        self.label_2.setObjectName("label_2")
        MainWindow.setCentralWidget(self.centralwidget)
        self.statusbar = QtWidgets.QStatusBar(MainWindow)
        self.statusbar.setObjectName("statusbar")
        MainWindow.setStatusBar(self.statusbar)
        self.menuBar = QtWidgets.QMenuBar(MainWindow)
        self.menuBar.setGeometry(QtCore.QRect(0, 0, 800, 23))
        self.menuBar.setObjectName("menuBar")
        self.menu = QtWidgets.QMenu(self.menuBar)
        self.menu.setObjectName("menu")
        MainWindow.setMenuBar(self.menuBar)
        self.actionguanyu = QtWidgets.QAction(MainWindow)
        self.actionguanyu.setObjectName("actionguanyu")
        self.menu.addAction(self.actionguanyu)
        self.menuBar.addAction(self.menu.menuAction())

        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
        self.groupBox.setTitle(_translate("MainWindow", "串口接收設(shè)置"))
        self.timestamp_check_box.setText(_translate("MainWindow", "時(shí)間戳"))
        self.label_7.setText(_translate("MainWindow", "校驗(yàn)位"))
        self.rec_hex_radio_button.setText(_translate("MainWindow", "HEX"))
        self.stopbit_combo_box.setItemText(0, _translate("MainWindow", "1"))
        self.stopbit_combo_box.setItemText(1, _translate("MainWindow", "1.5"))
        self.stopbit_combo_box.setItemText(2, _translate("MainWindow", "2"))
        self.label_6.setText(_translate("MainWindow", "數(shù)據(jù)位"))
        self.baud_combo_box.setItemText(0, _translate("MainWindow", "110"))
        self.baud_combo_box.setItemText(1, _translate("MainWindow", "300"))
        self.baud_combo_box.setItemText(2, _translate("MainWindow", "600"))
        self.baud_combo_box.setItemText(3, _translate("MainWindow", "1200"))
        self.baud_combo_box.setItemText(4, _translate("MainWindow", "2400"))
        self.baud_combo_box.setItemText(5, _translate("MainWindow", "4800"))
        self.baud_combo_box.setItemText(6, _translate("MainWindow", "9600"))
        self.baud_combo_box.setItemText(7, _translate("MainWindow", "14400"))
        self.baud_combo_box.setItemText(8, _translate("MainWindow", "19200"))
        self.baud_combo_box.setItemText(9, _translate("MainWindow", "38400"))
        self.baud_combo_box.setItemText(10, _translate("MainWindow", "43000"))
        self.baud_combo_box.setItemText(11, _translate("MainWindow", "57600"))
        self.baud_combo_box.setItemText(12, _translate("MainWindow", "76800"))
        self.baud_combo_box.setItemText(13, _translate("MainWindow", "115200"))
        self.baud_combo_box.setItemText(14, _translate("MainWindow", "128000"))
        self.baud_combo_box.setItemText(15, _translate("MainWindow", "230400"))
        self.baud_combo_box.setItemText(16, _translate("MainWindow", "256000"))
        self.baud_combo_box.setItemText(17, _translate("MainWindow", "460800"))
        self.baud_combo_box.setItemText(18, _translate("MainWindow", "921600"))
        self.baud_combo_box.setItemText(19, _translate("MainWindow", "1000000"))
        self.baud_combo_box.setItemText(20, _translate("MainWindow", "2000000"))
        self.baud_combo_box.setItemText(21, _translate("MainWindow", "3000000"))
        self.label_5.setText(_translate("MainWindow", "停止位"))
        self.label_4.setText(_translate("MainWindow", "波特率"))
        self.checkbit_combo_box.setItemText(0, _translate("MainWindow", "None"))
        self.checkbit_combo_box.setItemText(1, _translate("MainWindow", "Odd"))
        self.checkbit_combo_box.setItemText(2, _translate("MainWindow", "Even"))
        self.label_3.setText(_translate("MainWindow", "串口選擇"))
        self.databit_combo_box.setItemText(0, _translate("MainWindow", "8"))
        self.databit_combo_box.setItemText(1, _translate("MainWindow", "7"))
        self.databit_combo_box.setItemText(2, _translate("MainWindow", "6"))
        self.databit_combo_box.setItemText(3, _translate("MainWindow", "5"))
        self.uart_en_push_button.setText(_translate("MainWindow", "打開串口"))
        self.rec_ascii_radio_button.setText(_translate("MainWindow", "ASCII"))
        self.uart_clear_rec_push_button.setText(_translate("MainWindow", "清除接收"))
        self.groupBox_2.setTitle(_translate("MainWindow", "串口發(fā)送設(shè)置"))
        self.send_ascii_radio_button.setText(_translate("MainWindow", "ASCII"))
        self.send_hex_radio_button.setText(_translate("MainWindow", "HEX"))
        self.uart_timer_check_box.setText(_translate("MainWindow", "定時(shí)"))
        self.uart1_ms_label.setText(_translate("MainWindow", "ms"))
        self.uart_send_push_button.setText(_translate("MainWindow", "發(fā)送數(shù)據(jù)"))
        self.uart_send_clear_push_button.setText(_translate("MainWindow", "清除發(fā)送"))
        self.label.setText(_translate("MainWindow", "R:"))
        self.uart_tx_data_count_label.setText(_translate("MainWindow", "0"))
        self.uart_rx_data_count_label.setText(_translate("MainWindow", "0"))
        self.label_2.setText(_translate("MainWindow", "T:"))
        self.menu.setTitle(_translate("MainWindow", "幫助"))
        self.actionguanyu.setText(_translate("MainWindow", "關(guān)于"))

查看效果

在工程中編寫我們的 main.py,運(yùn)行看看效果,

main.py 代碼如下

import os
import sys

from Ui_uart_tool_ui import Ui_MainWindow
from PyQt5.QtWidgets import (QApplication, QMainWindow)


class MyPyQT_Form(QMainWindow, Ui_MainWindow):
    def __init__(self):
        super().__init__()
        self.setupUi(self)

if __name__ == '__main__':
    
    app = QApplication(sys.argv)
    my_pyqt_form = MyPyQT_Form()
    my_pyqt_form.show()
    sys.exit(app.exec_())

然后運(yùn)行效果如下:

image

結(jié)語(yǔ)

python 串口邏輯代碼的編寫,得留到下一篇了,平時(shí)工作忙不是特別有空,等我空閑的時(shí)候再補(bǔ)上!我本身不是學(xué) python 的,所以難免會(huì)有出錯(cuò)或者你認(rèn)為代碼不合理的地方,這些也希望多多諒解和指教,我會(huì)及時(shí)修改的!

關(guān)于本篇的相關(guān)代碼我也上傳到 github 和 csdn 上去了,有興趣的可以訪問(wèn) github csdn 查看,后面的代碼也會(huì)在這個(gè)倉(cāng)庫(kù)中補(bǔ)充,不介意也可以點(diǎn)個(gè) star。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容