PyQt5编程实现串口助手

环境搭建

本项目在windows10下开发,用到的开发软件是Pycharm

  1. 电脑安装python3以上版本,具体安装过程此处略过。
  2. 安装相关库pip install PyQt5,pip install pyserial。
  3. Pycharm中配置QtDesigner以及PyUIC。此处有详细的配置教程

通过QtDesigner设计界面

  1. 在pycharm中新建好项目后即可打开QtDesigner设计我们的程序界面了。

  2. 选中项目文件夹后右击,选择“Tools”–“External Tools”,即可打开我们关联的QtDesigner。

  3. 附上我的界面设计样板。
    由于是需求开发所以会有些特别,大家可以自行修改自己的界面

  4. 设计完后保存当前设计好的*.ui文件到我们的项目路径下。选中*.ui文件右击选择“Tools”–“External Tools”–“PyUIC”,即可将*.ui文件转化为*.py文件。

  5. 至此你肯定迫不及待想要运行显示你的界面查看效果了。同级目录下创建Main_Com.py文件。添加以下代码即可运行。

import sys                                              # 导入程序运行必须模块
from PyQt5.QtWidgets import QApplication, QMainWindow   # PyQt5中使用的基本控件都在PyQt5.QtWidgets模块中
from myCom import Ui_Form                               # 导入designer工具生成的*.py模块中的类
from PyQt5.QtWidgets import QApplication, QWidget, QInputDialog, QLineEdit
from PyQt5 import QtGui
from PyQt5.QtCore import *
import serial                                           # 导入串口模块
import os
import time

class MyMainForm(QMainWindow, Ui_Form):
    def __init__(self, parent=None):
        super(MyMainForm, self).__init__(parent)
        self.setupUi(self)
if __name__ ==  "__main__" :
    app = QApplication(sys.argv)
    # 初始化
    myWin = MyMainForm()
    # 将窗口控件显示在屏幕上
    myWin.show()
    # 程序运行,sys.exit方法确保程序完整退出。
    sys.exit(app.exec_())

定义信号与槽函数

这里我就不打算详细说了,直接上代码,注意这是应用型程序,大家在我程序基础上增删改即可。

# Author:Guo_zq
# Date:2020-09-29
# UseFor:检查烧录版本是否正确

import sys                                              # 导入程序运行必须模块
from PyQt5.QtWidgets import QApplication, QMainWindow   # PyQt5中使用的基本控件都在PyQt5.QtWidgets模块中
from myCom import Ui_Form                               # 导入designer工具生成的myCom模块
from PyQt5.QtWidgets import QApplication, QWidget, QInputDialog, QLineEdit
from PyQt5 import QtGui
from PyQt5.QtCore import *
import serial                                           # 导入串口模块
import os
import time

pass_Num = 0
fail_Num = 0
enable = 0                                              # 标识串口开闭
class MyMainForm(QMainWindow, Ui_Form):
    def __init__(self, parent=None):
        super(MyMainForm, self).__init__(parent)
        self.setupUi(self)
        self.com_Name.setText("COM8")                   # 设置默认串口
        self.send_Content1.setText("F1")                # 设置默认发送字符一
        self.send_Content2.setText("81")                # 设置默认发送字符二

        '''
        初始化获取LCD显示值,用于计数 
        ---start---
        '''
        global fail_Num
        global pass_Num
        if os.path.exists("result") == False:                                                          # 先确保存在目录result
            os.mkdir("result")
        open("result/" + time.strftime("%Y_%m_%d", time.localtime()) + ".txt", 'a')                    # 再确保存在文件
        if (os.path.getsize("result/" + time.strftime("%Y_%m_%d", time.localtime()) + ".txt") == 0):   # 再判断文件是否有内容,若无则初始写入
            with open("result/"+time.strftime("%Y_%m_%d", time.localtime())+".txt",'w') as f:
                f.write("PASS:"+str(pass_Num)+"\t"+"FAIL:"+str(fail_Num))
        else:                                                                                          # 若有则提取数值显示,同时全局变量中的pass_Num与fail_Num也被同步
            with open("result/"+time.strftime("%Y_%m_%d", time.localtime())+".txt",'r') as f:
                res_line = f.readline()
                pass_Num = int(res_line.split("\t")[0].split(":")[1])
                fail_Num = int(res_line.split("\t")[1].split(":")[1])
                self.pass_lcd.display(pass_Num)
                self.fail_lcd.display(fail_Num)

        '''
        ---end---
        '''

        '''
        添加按钮信号和槽函数
        '''
        self.open_button.clicked.connect(lambda: self.openSerial(self.com_Name.text(), enable))

        self.send_button1.clicked.connect(lambda: self.sendData(self.send_Content1.text(), "1"))

        self.send_button2.clicked.connect(lambda: self.sendData(self.send_Content2.text(), "2"))

        self.clean_button.clicked.connect(self.show_dialog)

        self.cancle_button.clicked.connect(self.close)
    '''
    设置初始化灰色图片
    '''
    def setInitImg(self):
        self.light.setPixmap(QtGui.QPixmap("img/init.png"))

    def openSerial(self, com, flag):
        global t
        global enable
        flag = enable
        if flag == 0:
            try:
                t = serial.Serial(com, 9600, timeout=5)
                t.bytesize = 8                                                          # 8位数据位
                t.parity = serial.PARITY_EVEN                                           # 此处设置为偶校验(无校验:serial.PARITY_NONE奇校验serial.PARITY_ODD)
                t.stopbits = 1                                                          # 停止位为1
                t.rtscts                                                                # 硬件流控 ser.dsrdtr  软件流控 ser.xonxoff
                t.flushInput()                                                          # 清空缓冲区
                if t:
                    self.showContext.append("%s串口已打开" % (self.com_Name.text()))
                    self.open_button.setText("关闭串口")
                    enable = 1
            except Exception as exc:
                self.showContext.append("检查串口软硬件设置是否正确!!!error:%s"%exc)
        else:
            try:
                serial.Serial.close(t)
                enable=0
                self.open_button.setText("打开串口")
                self.showContext.append("%s串口已关闭"% (self.com_Name.text()))
            except Exception as exc:
                self.showContext.append("检查串口状态是否正确!!!error:%s"%exc)

    def sendData(self, command, flag):
        global pass_Num
        global fail_Num
        if flag == "1":
            try:
                self.send_button2.setEnabled(True)                                  # 当第一个按钮被按下,将第二个按钮置为可用
                t.write(bytes.fromhex(command))                                     # 以hex写入串口
                time.sleep(0.5)                                                     # time.sleep() 与 inWaiting() 最好配对使用
                t.inWaiting()
                data = t.read_all().hex()                                           # 将接收缓冲区中数据读取到data中
                if data != "" and int(data) > 0:                                    # 判空以及去除接收到00字符的干扰字符
                    now = str(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()))
                    self.showContext.append(now+"::"+data)                          # 显示当前时间+获取到的串口数据
                    if data[-2:] == "83":                                           # 去除收到形如000083的字符串,直接取倒数两位值做判断
                        self.send_button1.setEnabled(False)                         # 获取到83即刻将按钮置为不可用,防止持续发送串口命令
                        self.light.setPixmap(QtGui.QPixmap("img/testing.png"))      # 接收到83字符则显示黄色图片
                    else:
                        self.send_button2.setEnabled(False)                         # 先将第二个按钮置为不可用,防止检测继续进行下去
                        self.light.setPixmap(QtGui.QPixmap("img/fail.png"))         # 接收到除83以外其他字符则显示红色图片
                        fail_Num = fail_Num+1                                       # 更新全局变量fail_Num的值
                        with open("result/" + time.strftime("%Y_%m_%d", time.localtime()) + ".txt", 'w') as f:    # 对记录PASS数量及FAIL数量的文件进行更新
                            f.write("PASS:" + str(pass_Num) + "\t" + "FAIL:" + str(fail_Num))
                        with open("result/" + time.strftime("%Y_%m_%d", time.localtime()) + "_fail.txt",'a') as fr:# 对记录Fail详细数据的文件进行写入
                            fr.write(now+"::"+data+"\n")
                        self.fail_lcd.display(fail_Num)                             # 计数LCD显示值刷新
                        self.show_dialog()                                          # 弹出提示框锁存当前错误状态,直至输入密码正确后方可复位清屏
                        QTimer.singleShot(5000, self.setInitImg)                    # 定时器,指定5秒后将红色图片替换为灰色图片,恢复初始状态
            except Exception as exc:
                self.showContext.append("请先确认串口连接成功:%s" % exc)
        elif flag == "2":
            self.send_button1.setEnabled(True)                                      # 当第二个按钮被按下,解禁第一个按钮
            try:
                t.write(bytes.fromhex(command))                                     # 以hex写入串口
                time.sleep(0.5)                                                     # sleep() 与 inWaiting() 最好配对使用
                n = t.inWaiting()
                if n:
                    data_hex = t.read(n).hex()                                      # 读取缓冲区的数据,将bytes字符串转16进制
                    now = str(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()))
                    self.showContext.append(now+"::"+data_hex)                      # 将接收到的字符放入内容显示框
                    if data_hex <= bytes.fromhex("80").hex():                       # 将转16进制后的结果与16进制的80进行比较大小
                        self.light.setPixmap(QtGui.QPixmap("img/fail.png"))         # 接收到16进制数小于等于80则将图片置为红色
                        fail_Num = fail_Num+1                                       # 更新全局变量中fail_Num的值
                        with open("result/" + time.strftime("%Y_%m_%d", time.localtime()) + ".txt", 'w') as f:     # 对记录PASS以及FAIL数量的文件进行更新
                            f.write("PASS:" + str(pass_Num) + "\t" + "FAIL:" + str(fail_Num))
                        with open("result/" + time.strftime("%Y_%m_%d", time.localtime()) + "_fail.txt",'a') as fr:# 对记录Fail数据的文件进行写入
                            fr.write(now+"::"+data+"\n")
                        self.fail_lcd.display(fail_Num)                             # 计数LCD显示值刷新
                        self.show_dialog()                                          # 弹出提示框锁存当前错误状态,直至输入密码正确后方可复位清屏
                        QTimer.singleShot(5000, self.setInitImg)                    # 定时器,指定5秒后将红色图片替换为灰色图片,恢复初始状态
                    else:
                        self.send_button2.setEnabled(False)                         # 接收到大于80的十六进制数据将第二个按钮置为不可用
                        self.light.setPixmap(QtGui.QPixmap("img/success.png"))      # 否则置于绿色图片 该测试机通过
                        pass_Num = pass_Num+1                                       # 更新全局变量pass_Num的值
                        with open("result/" + time.strftime("%Y_%m_%d", time.localtime()) + ".txt", 'w') as f:
                            f.write("PASS:" + str(pass_Num) + "\t" + "FAIL:" + str(fail_Num))
                        self.pass_lcd.display(pass_Num)                             # 计数LCD显示值刷新
                        QTimer.singleShot(5000, self.clean)                         # 清理显示框,PASS测试机文本框内值保存5秒
                        QTimer.singleShot(5000, self.setInitImg)                    # 定时器,指定5秒后将绿色图片替换为灰色图片,恢复初始状态
            except Exception as exc:
                self.showContext.append("请先确认串口连接成功:%s" % exc)
    '''
    显示提示框
    '''
    def show_dialog(self):
        text, okPressed = QInputDialog.getText(self, "Dialog", "清屏密码:", QLineEdit.Password) # 密码提示框
        if okPressed and text == "112233":
            self.clean()
            self.send_button1.setEnabled(True)
            self.send_button2.setEnabled(True)
        else:
            self.show_dialog()
    '''
    清除显示文本框内的文本
    '''
    def clean(self):
        self.showContext.clear()

if __name__ ==  "__main__" :
    app = QApplication(sys.argv)
    # 初始化
    myWin = MyMainForm()
    # 将窗口控件显示在屏幕上
    myWin.show()
    # 程序运行,sys.exit方法确保程序完整退出。
    sys.exit(app.exec_())

最后附上运行效果图

这里我没有连接硬件串口,点击清屏需要锁存状态,输入密码方可清屏

  • 8
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值