前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Python Qt GUI设计:做一款串口调试助手(实战篇—1)

Python Qt GUI设计:做一款串口调试助手(实战篇—1)

作者头像
不脱发的程序猿
发布于 2022-01-13 04:25:55
发布于 2022-01-13 04:25:55
6.4K00
代码可运行
举报
运行总次数:0
代码可运行

目录

1、UI设计

2、将UI文件转换为Py文件

3、逻辑功能实现

3.1、初始化程序

3.2、串口检测程序

3.3、 设置及打开串口程序

3.4、定时发送数据程序

3.5、发送数据程序

3.6、接收数据程序

3.7、保存日志程序

3.8、加载日志程序

3.9、打开博客、公众号程序

3.10、清除发送和接收数据显示程序

3.11、关闭串口程序

Python Qt GUI设计系列博文终于到了实战篇,本篇博文将贯穿之前的基础知识点实现一款串口调试助手。

1、UI设计

UI设计使用Qt Creator实现,组件布局如下所示:

2、将UI文件转换为Py文件

这里使用Python脚本的方式将UI文件转换为Python文件,代码如下所示:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import os
import os.path
 
dir ='./' #文件所在的路径
 
#找出路径下所有的.ui文件
def listUiFile():
    list = []
    files = os.listdir(dir)
    for filename in files:
        #print(filename)
        if os.path.splitext(filename)[1] == '.ui':
            list.append(filename)
    
    return list
 
#把扩展名未.ui的转换成.py的文件
def transPyFile(filename):
    return os.path.splitext(filename)[0] + '.py'
 
#通过命令把.ui文件转换成.py文件
def runMain():
    list = listUiFile()
    for uifile in list:
        pyfile = transPyFile(uifile)
        cmd = 'pyuic5 -o {pyfile} {uifile}'.format(pyfile=pyfile, uifile=uifile)
        os.system(cmd)
        
if __name__ =="__main__":
    runMain()

3、逻辑功能实现

3.1、初始化程序

首先初始化一些组件和标志位的状态,设置信号与槽的关系,实现代码如下所示:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    # 初始化程序
    def __init__(self):
        super(Pyqt5_Serial, self).__init__()
        
        self.setupUi(self)
        
        self.init()
        
        self.ser = serial.Serial()
        self.port_check()
        
        # 设置Logo和标题
        self.setWindowIcon(QIcon('Com.png'))
        self.setWindowTitle("串口调试助手 【公众号】美男子玩编程")
        # 设置禁止拉伸窗口大小
        self.setFixedSize(self.width(), self.height())
        
        # 发送数据和接收数据数目置零
        self.data_num_sended = 0
        self.Lineedit2.setText(str(self.data_num_sended))
        self.data_num_received = 0
        self.Lineedit3.setText(str(self.data_num_received))

        # 串口关闭按钮使能关闭
        self.Pushbuttom3.setEnabled(False)

        # 发送框、文本框清除
        self.Text1.setText("")
        self.Text2.setText("")
        
    # 建立控件信号与槽关系
    def init(self):
        # 串口检测按钮
        self.Pushbuttom2.clicked.connect(self.port_check)
        # 串口打开按钮
        self.Pushbuttom1.clicked.connect(self.port_open)
        # 串口关闭按钮
        self.Pushbuttom3.clicked.connect(self.port_close)

        # 定时发送数据
        self.timer_send = QTimer()
        self.timer_send.timeout.connect(self.data_send)
        self.Checkbox7.stateChanged.connect(self.data_send_timer)
        
        # 发送数据按钮
        self.Pushbuttom6.clicked.connect(self.data_send)

        # 加载日志
        self.Pushbuttom4.clicked.connect(self.savefiles)
        # 加载日志
        self.Pushbuttom5.clicked.connect(self.openfiles)
        
        # 跳转链接
        self.commandLinkButton1.clicked.connect(self.link)

        # 清除发送按钮
        self.Pushbuttom7.clicked.connect(self.send_data_clear)

        # 清除接收按钮
        self.Pushbuttom8.clicked.connect(self.receive_data_clear)

3.2、串口检测程序

检测电脑上所有串口,实现代码如下所示:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    # 串口检测
    def port_check(self):
        # 检测所有存在的串口,将信息存储在字典中
        self.Com_Dict = {}
        port_list = list(serial.tools.list_ports.comports())
        
        self.Combobox1.clear()
        for port in port_list:
            self.Com_Dict["%s" % port[0]] = "%s" % port[1]
            self.Combobox1.addItem(port[0])
            
        # 无串口判断
        if len(self.Com_Dict) == 0:
            self.Combobox1.addItem("无串口")

3.3、 设置及打开串口程序

检测到串口后进行配置,打开串口,并且启动定时器一直接收用户输入,实现代码如下所示:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    # 打开串口
    def port_open(self):
        self.ser.port        = self.Combobox1.currentText()      # 串口号
        self.ser.baudrate    = int(self.Combobox2.currentText()) # 波特率

        flag_data = int(self.Combobox3.currentText())  # 数据位
        if flag_data == 5:
            self.ser.bytesize = serial.FIVEBITS
        elif flag_data == 6:
            self.ser.bytesize = serial.SIXBITS
        elif flag_data == 7:
            self.ser.bytesize = serial.SEVENBITS
        else:
            self.ser.bytesize = serial.EIGHTBITS

        flag_data = self.Combobox4.currentText()  # 校验位
        if flag_data == "None":
            self.ser.parity = serial.PARITY_NONE
        elif flag_data == "Odd":
            self.ser.parity = serial.PARITY_ODD
        else:
            self.ser.parity = serial.PARITY_EVEN

        flag_data = int(self.Combobox5.currentText()) # 停止位
        if flag_data == 1:
            self.ser.stopbits = serial.STOPBITS_ONE
        else:
            self.ser.stopbits = serial.STOPBITS_TWO

        flag_data = self.Combobox6.currentText()  # 流控
        if flag_data == "No Ctrl Flow":
            self.ser.xonxoff = False  #软件流控
            self.ser.dsrdtr  = False  #硬件流控 DTR
            self.ser.rtscts  = False  #硬件流控 RTS
        elif flag_data == "SW Ctrl Flow":
            self.ser.xonxoff = True  #软件流控
        else:         
            if self.Checkbox3.isChecked():
                self.ser.dsrdtr = True  #硬件流控 DTR
            if self.Checkbox4.isChecked():
                self.ser.rtscts = True  #硬件流控 RTS
        try:
            time.sleep(0.1)
            self.ser.open()
        except:
            QMessageBox.critical(self, "串口异常", "此串口不能被打开!")
            return None

        # 串口打开后,切换开关串口按钮使能状态,防止失误操作        
        if self.ser.isOpen():
            self.Pushbuttom1.setEnabled(False)
            self.Pushbuttom3.setEnabled(True)
            self.formGroupBox1.setTitle("串口状态(开启)")

        # 定时器接收数据
        self.timer = QTimer()
        self.timer.timeout.connect(self.data_receive)
        # 打开串口接收定时器,周期为1ms
        self.timer.start(1)

3.4、定时发送数据程序

通过定时器,可支持1ms至30s之间数据定时,实现代码如下所示:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    # 定时发送数据
    def data_send_timer(self):
        try:
            if 1<= int(self.Lineedit1.text()) <= 30000:  # 定时时间1ms~30s内
                if self.Checkbox7.isChecked():
                    self.timer_send.start(int(self.Lineedit1.text()))
                    self.Lineedit1.setEnabled(False)
                else:
                    self.timer_send.stop()
                    self.Lineedit1.setEnabled(True)
            else:
                QMessageBox.critical(self, '定时发送数据异常', '定时发送数据周期仅可设置在30秒内!')
        except:
            QMessageBox.critical(self, '定时发送数据异常', '请设置正确的数值类型!')

3.5、发送数据程序

可以发送ASCII字符和十六进制类型数据,并且可以在数据前显示发送的时间,在数据后进行换行,发送一个字节,TX标志会自动累加,实现代码如下所示:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    # 发送数据
    def data_send(self):
        if self.ser.isOpen():
            input_s = self.Text2.toPlainText()

            # 判断是否为非空字符串
            if input_s != "":
                # 时间显示
                if self.Checkbox5.isChecked():
                    self.Text1.insertPlainText((time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())) + " ")
                    
                # HEX发送
                if self.Checkbox1.isChecked():  
                    input_s = input_s.strip()
                    send_list = []
                    while input_s != '':
                        try:
                            num = int(input_s[0:2], 16)
                        except ValueError:
                            QMessageBox.critical(self, '串口异常', '请输入规范十六进制数据,以空格分开!')
                            return None
                        
                        input_s = input_s[2:].strip()
                        send_list.append(num)
                        
                    input_s = bytes(send_list)
                # ASCII发送
                else:  
                    input_s = (input_s).encode('utf-8')
                    
                # HEX接收显示
                if self.Checkbox2.isChecked():  
                    out_s = ''
                    for i in range(0, len(input_s)):
                        out_s = out_s + '{:02X}'.format(input_s[i]) + ' '
                        
                    self.Text1.insertPlainText(out_s)
                # ASCII接收显示
                else:  
                    self.Text1.insertPlainText(input_s.decode('utf-8')) 

                # 接收换行              
                if self.Checkbox6.isChecked():
                    self.Text1.insertPlainText('\r\n')

                # 获取到Text光标
                textCursor = self.Text1.textCursor()
                # 滚动到底部
                textCursor.movePosition(textCursor.End)
                # 设置光标到Text中去
                self.Text1.setTextCursor(textCursor)
            
                # 统计发送字符数量
                num = self.ser.write(input_s)
                self.data_num_sended += num
                self.Lineedit2.setText(str(self.data_num_sended))
        else:
            pass

3.6、接收数据程序

可以接收ASCII字符和十六进制类型数据,并且可以在数据前显示发送的时间,在数据后进行换行,接收一个字节,RX标志会自动累加,实现代码如下所示:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    # 接收数据
    def data_receive(self):
        try:
            num = self.ser.inWaiting()
            
            if num > 0:
                time.sleep(0.1)
                num = self.ser.inWaiting()  #延时,再读一次数据,确保数据完整性
        except:
            QMessageBox.critical(self, '串口异常', '串口接收数据异常,请重新连接设备!')
            self.port_close()
            return None
        
        if num > 0:
            data = self.ser.read(num)
            num = len(data)
            
            # 时间显示
            if self.Checkbox5.isChecked():
                self.Text1.insertPlainText((time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())) + " ")
                
            # HEX显示数据
            if self.Checkbox2.checkState():
                out_s = ''
                for i in range(0, len(data)):
                    out_s = out_s + '{:02X}'.format(data[i]) + ' '
                    
                self.Text1.insertPlainText(out_s)
            # ASCII显示数据
            else:
                self.Text1.insertPlainText(data.decode('utf-8'))

            # 接收换行              
            if self.Checkbox6.isChecked():
                self.Text1.insertPlainText('\r\n')
                    
            # 获取到text光标
            textCursor = self.Text1.textCursor()
            # 滚动到底部
            textCursor.movePosition(textCursor.End)
            # 设置光标到text中去
            self.Text1.setTextCursor(textCursor)

            # 统计接收字符的数量
            self.data_num_received += num
            self.Lineedit3.setText(str(self.data_num_received))
        else:
            pass

3.7、保存日志程序

将接收框中收发的数据保存到TXT文本中,实现代码如下所示:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    # 保存日志
    def savefiles(self):
        dlg = QFileDialog()
        filenames = dlg.getSaveFileName(None, "保存日志文件", None, "Txt files(*.txt)")

        try:
            with open(file = filenames[0], mode='w', encoding='utf-8') as file:
                file.write(self.Text1.toPlainText())
        except:
            QMessageBox.critical(self, '日志异常', '保存日志文件失败!')

3.8、加载日志程序

加载保存到TXT文本中的数据信息到发送框中,实现代码如下所示:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    # 加载日志
    def openfiles(self):
        dlg = QFileDialog()
        filenames = dlg.getOpenFileName(None, "加载日志文件", None, "Txt files(*.txt)")

        try:
            with open(file = filenames[0], mode='r', encoding='utf-8') as file:
                self.Text2.setPlainText(file.read())
        except:
            QMessageBox.critical(self, '日志异常', '加载日志文件失败!')

3.9、打开博客、公众号程序

点击按钮,打开我的公众号二维码和博客主页,实现代码如下所示:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    # 打开博客链接和公众号二维码
    def link(self):
        dialog = QDialog()
        label_img = QLabel()
            
        label_img.setAlignment(Qt.AlignCenter)    
        label_img.setPixmap(QPixmap("./img.jpg"))

        vbox = QVBoxLayout()
        vbox.addWidget(label_img)
        dialog.setLayout(vbox)
        
        dialog.setWindowTitle("快扫码关注公众号吧~")
        dialog.setWindowModality(Qt.ApplicationModal)
        dialog.exec_()
		
        webbrowser.open('https://blog.csdn.net/m0_38106923')

3.10、清除发送和接收数据显示程序

清除发送数据框和接收数据框的内容和计数次数,实现代码如下所示:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    # 清除发送数据显示
    def send_data_clear(self):
        self.Text2.setText("")

        self.data_num_sended = 0
        self.Lineedit2.setText(str(self.data_num_sended))

    # 清除接收数据显示
    def receive_data_clear(self):
        self.Text1.setText("")

        self.data_num_received = 0
        self.Lineedit3.setText(str(self.data_num_received))

3.11、关闭串口程序

关闭串口,停止定时器,重置组件和标志状态,实现代码如下所示:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    # 关闭串口
    def port_close(self):
        try:
            self.timer.stop()
            self.timer_send.stop()
            
            self.ser.close()
        except:
            QMessageBox.critical(self, '串口异常', '关闭串口失败,请重启程序!')
            return None

        # 切换开关串口按钮使能状态和定时发送使能状态
        self.Pushbuttom1.setEnabled(True)
        self.Pushbuttom3.setEnabled(False)
        self.Lineedit1.setEnabled(True)
        
        # 发送数据和接收数据数目置零
        self.data_num_sended = 0
        self.Lineedit2.setText(str(self.data_num_sended))
        self.data_num_received = 0
        self.Lineedit3.setText(str(self.data_num_received))
        
        self.formGroupBox1.setTitle("串口状态(关闭)")
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022/01/04 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
【云原生】在 React Native 中使用 AWS Textract 实现文本提取
Amazon Textract 是 Amazon 推出的一项机器学习服务,可将扫描文档、PDF 和图像中的文本、手写文字提取到文本文档中,然后可以将其存储在任何类型的存储服务中,例如 DynamoDB、s3 等。
前端修罗场
2023/10/07
4550
【云原生】在 React Native 中使用 AWS Textract 实现文本提取
Serverless|Framework——图文玩转 AWS Lambda
| 好看请赞,养成习惯 你有一个思想,我有一个思想,我们交换后,一个人就有两个思想 If you can NOT explain it simply, you do NOT understand i
用户4172423
2020/10/23
2.6K0
Serverless|Framework——图文玩转 AWS Lambda
AWS Lambda 快速入门
但以上的几个方法都需要关注服务器的存储和计算资源,以便随时调整以满足更高的性能,并且高并发的请求也是分时段的,配置了更高性能的服务器在访问量变低的时候也是资源浪费。
goodspeed
2020/12/22
2.8K0
AWS Lambda  快速入门
深入理解Serverless架构:构建无服务器应用的完全指南
Serverless架构是一种现代化的云计算范式,它允许开发者构建应用程序而无需管理服务器基础架构。本文将深入探讨Serverless架构的关键概念,为您提供一份全面的指南,并提供带有实际代码示例的技巧,以帮助您构建出色的无服务器应用。
海拥
2023/09/19
1.1K0
深入理解Serverless架构:构建无服务器应用的完全指南
Serverless Land:AWS Serverless 学习资源汇集地
近日,发现了一个 AWS Lambda 相关的资源网站:Serverless Land。
donghui
2021/05/13
2.4K0
Serverless Land:AWS Serverless 学习资源汇集地
搬运向 | 浅析serverless架构与实践
Serverless ,不是没有server,而是不用去担心维护server 这件事, 不管是在部署还是开发,都是以一个个function 为单位, 这带来了程式码上的高度decoupling,但同时
Rainbond开源
2018/05/31
2.6K0
多国语言在线客服系统源码+软件下载二合一集成
  本文分三部分系统介绍如何开发一套在线客服系统聊天源码,该源码基于ThinkPHP,代码完全开源。   首先,我们只使用@auth指令。   其次,我们添加一个带有参数的订阅类型。   第三,我们更新@auth指令和订阅类型。   完整源码:kf.zxkfym.top   1 使用@auth指令并执行身份验证   添加和使用身份验证
全栈程序员站长
2022/09/09
1.4K0
多国语言在线客服系统源码+软件下载二合一集成
开发者:Serverless 从懵比到实战
作者介绍:陌小路,哔哩哔哩前端 GitHub:https://github.com/STDSuperman 本文选自「掘金x腾讯云征文|万物皆可 Serverless」 原文链接:https://juejin.cn/post/6895346770177687566 Serverless 是一种执行模型(execution model)。在这种模型中,云服务商负责通过动态地分配资源来执行一段代码。云服务商仅仅收取执行这段代码所需要资源的费用。代码通常会被运行在一个无状态的容器内,并且可被多种事件触发(htt
腾讯云serverless团队
2021/01/05
1.1K0
用AWS、Slack和树莓派构建物联网原型项目
IoT-AWS-Slack-and-a-Raspberry-Pi-1-1068x656-1.jpg
用户4122690
2020/06/08
2.9K0
用AWS、Slack和树莓派构建物联网原型项目
AWS 15 年(1):从 Serverful 到 Serverless
2006年,AWS发布了其第一个Serverless存储服务S3和第一个Serverful计算服务EC2,这也是AWS正式发布的前两个服务,开启了云计算波澜壮阔的旅程。2014年,AWS发布了业界第一个Serverless计算服务AWS Lambda。在今年(2021年)的AWS re:Invent大会上,AWS又发布三个Serverless新品:Redshift Serverless、EMR Serverless和MSK Serverless。AWS的15年发展史(2006到2021年),也是一部AWS创造和深耕Serverless的历史,一部从Serverful不断向Serverless演进的历史。
SammyLiu
2022/01/04
1.5K0
AWS 15 年(1):从 Serverful 到 Serverless
分布式系统开发实战:实战,使用AWS平台实现Serverless架构
·全球所有玩家的持久化信息(包括用户基本信息、等级、装备、进度等状态信息)都保存在中心站点。玩家统一通过HTTP(S)登录中心站点并获取状态信息。
IT大咖说
2021/06/15
1.8K0
分布式系统开发实战:实战,使用AWS平台实现Serverless架构
What is Serverless Web Application Development?
What is Serverless Web Application Development? Serverless web application development is an emergin
用户4822892
2019/08/20
5960
What is Serverless Web Application Development?
Serverless 微服务架构案例无服务器架构 (Serverless Architectures) 简介 AWS Lambda 的编程模型Amazon API Gateway + AWS Lamb
Serverless 架构最早可以追溯到 Ken Fromm 发表的文章《Why The Future Of Software And Apps Is Serverless》。在这篇文章里, Ken Fromm 描述了未来云计算基础设施成熟的条件下应用程序是不需要服务器端的。在无武器场景下构建应用程序的时候。开发人员和运维人员无需担心服务器如何安装配置,如何设置网络和负载均衡,无需监控状态,甚至不再会出现服务器相关的工作内容。这样可以让原本建设机房的时间成本和货币成本从按年计算缩短至按秒计算。
顾宇
2018/08/17
2.4K0
2020年AWS,Microsoft和Google应进行的云收购
主要的云提供商提供了广泛的服务,但还远非完美。以下是AWS,Microsoft和Google在2020年应该进行的收购,以巩固其平台。
CloudBest
2020/07/23
6.8K0
【Other】What is the Serverless architecture
Source What is the Serverless architecture? - Java Stack Flow Technology is rapidly growing day by d
阿东
2023/09/14
2830
如何将传统 Web 框架部署到 Serverless
因为 Serverless 的“无服务器架构”应用相比于传统应用有很多优点,比如:无需关心服务器、免运维、弹性伸缩、按需付费、开发可以更加关注业务逻辑等等,所以现在 Serverless 应用已经逐渐广泛起来。
政采云前端团队
2022/12/01
2.7K0
如何将传统 Web 框架部署到 Serverless
BaaS、FaaS、Serverless都是什么馅儿?
本文编译自What’s Serverless?(O’Reilly电子书)作者:Mike Roberts,John Chapin 软件行业是一个飞速发展的行业,不断推出新技术,以及令人目不暇接的概念和术语。厘清各种概念和术语的含义,对于分析技术发展趋势,决定是否需要及时入坑很有必要。今天就来说一说被热烈讨论的Serverless,以及与之相关的两个概念BaaS及FaaS。 国内外的各大云厂商 Amazon、微软、Google、IBM、阿里云、腾讯云相继推出Serverless产品,Serverless实际
用户1682855
2018/06/08
4.1K0
Serverless 应用开发指南:基于 Serverless 与 Lambda 的微信公共平台
Serverless 在事件驱动方面具有天然的优势,其中之一就是聊天机器人。可要做聊天机器人不是一件容易的事,微信和 QQ 都只能用 Hack 的方式进行。
Phodal
2018/01/29
4.3K0
云开发:构建强大应用的云原生开发指南
云开发是一种基于云原生架构的开发方法,它允许开发者构建应用程序,利用云服务的强大功能,如存储、数据库、身份验证和部署,无需管理底层基础架构。本文将深入探讨云开发的关键概念,为您提供一份全面的指南,并提供带有实际代码示例的技巧,以帮助您构建出色的云原生应用。
海拥
2023/09/19
6400
云开发:构建强大应用的云原生开发指南
Serverless 架构与事件规范
基础服务架构 本篇内容主要讨论的是 Serverless架构与其事件规范的基础原则。 首先,我们先来了解下在 HTTP/Web 场景下我们的典型的WEB场景是怎样的: 基础架构 这里,我们不难看出典型的Web场景其实是由三大块内容,客户端,服务器,数据库组成。客户端在服务器侧通过类型apache,nginx等代理服务器来请求数据,代理服务器又通过数据库来写入或拉取数据资料。这个很简单,也是我们最常用的Web场景。 这里面服务器中可能涉及路由规则,鉴权逻辑以及其他各类复杂的业务代码,同时,开发团队要付出
腾讯云serverless团队
2020/04/26
1.3K0
推荐阅读
相关推荐
【云原生】在 React Native 中使用 AWS Textract 实现文本提取
更多 >
LV.1
这个人很懒,什么都没有留下~
目录
  • 目录
  • 1、UI设计
  • 2、将UI文件转换为Py文件
  • 3、逻辑功能实现
    • 3.1、初始化程序
    • 3.2、串口检测程序
    • 3.3、 设置及打开串口程序
    • 3.4、定时发送数据程序
    • 3.5、发送数据程序
    • 3.6、接收数据程序
    • 3.7、保存日志程序
    • 3.8、加载日志程序
    • 3.9、打开博客、公众号程序
    • 3.10、清除发送和接收数据显示程序
    • 3.11、关闭串口程序
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档