Python 3.8 + PyCharm + PyQt5(四)-串口助手
- UI布局
- 代码编写
- 模块加载
- 代码实现
- 线程
- 发送数据
所有后面讲解和记录的源码都会在
GuiHub中,可以自行下载
上节我们讲到通过数字输入框,然后做了一个简单的加法,操作了按钮事件,字符转换等。
这次我们来讲讲实现串口助手,通过串口进行通讯。
UI布局
首先创建pycharm工程建立新的UI,并拖拽QT控件,进行UI的布局,布局如下,当然个人喜好,喜欢怎么放就怎么放。
当然两个按钮分别对应了2个槽:
一个打开串口槽:
一个发送给数据槽:
点击保存后,用PyUIC形成.py文件。
代码编写
模块加载
串口小助手,那么我们就需要对串口进行读写,首先我们在python模块中增加串口模块,这边我们说一个新的增加模块的方法,在前面的讲解中,我们有说到增加模块的方法有2中,现在说第三种:
打开pycharm,下面选择这个选项,打开来发现,这个其实是虚拟环境。这边我们首先输入
pip list
会打印出当前加载好的模块,这边显示的pyserial就是我们需要的串口模块。
可以在这边输入
pip install pyserial
来对串口模块进行安装。
我这边因为已经安装好,所以提示了当前包的版本信息。
代码实现
串口通信,首先我们得得到电脑的串口号,python的串口接口可以获取到电脑设备的串口列表,
COM_List = list(serial.tools.list_ports.comports())
if len(COM_List) == 0:
print('无可用串口')
else:
for i in range(0, len(COM_List)):
print(COM_List[i])
通过这个接口,我们可以看到最终打印可以看到,我们电脑有2个串口,前面是串口编号,后面是串口的名称。
因此,我们需要将这两个放到我们的界面的串口列表中。
这边我们把这部分代码封装成一个函数。
# 获取串口列表
def Get_Com_List():
return list(serial.tools.list_ports.comports())
# 界面UI按键程序重写
class Mywindow(QtWidgets.QMainWindow, Ui_MainWindow):
def __init__(self):
super(Mywindow, self).__init__()
self.setupUi(self)
COM_List = Get_Com_List() # 获取串口列表
for i in range(0, len(COM_List)): # 将列表导入到下拉框
self.Com_Port.addItem(COM_List[i].name)
def Open_Com_Click(self):
print("点击了打开串口按钮")
def Send_Data_Click(self):
print("点击了发送数据按钮")
首先我们重写UI界面,将两个按钮事件进行简单的定义,我们首先完成串口号的获取。
在初始化函数中,我们增加了获取串口号,并且把串口号的名称加入到Com_Port控件中,具体效果是这样的:
串口号中已经可以下拉选择哪个串口。
同理我们把串口波特率也加到下面波特率的下拉框中,效果如图:
我这边就只添加了2种进行测试。代码如下:
self.Com_Band.addItem("9600")
self.Com_Band.addItem("115200")
获取到了串口号了,接下来我们就要来打开串口,发送数据,这边我们需要先知道下拉框选择了哪个串口。
通过接口
self.Com_Port.currentText()
来进行获取当前是COM多少。然后同理选择波特率,然后进行打开串口。:
def Open_Com_Click(self):
global custom_serial # 全局变量,需要加global
global Com_Open_Flag
print("点击了打开串口按钮")
if self.Open_Com.text() == "打开串口":
print(self.Com_Port.currentText())
custom_serial = serial.Serial(self.Com_Port.currentText(), int(self.Com_Band.currentText()), timeout=0.5)
if custom_serial.isOpen():
print("open success")
Com_Open_Flag = True
self.Open_Com.setText("关闭串口")
self.Com_Band.setEnabled(False) # 串口号和波特率变为不可选择
self.Com_Port.setEnabled(False)
else:
print("open failed")
else:
Com_Open_Flag = False
self.Open_Com.setText("打开串口")
custom_serial.close()
self.Com_Band.setEnabled(True) # 串口号和波特率变为可选择
self.Com_Port.setEnabled(True)
这是对打开按钮程序的重写,答题意思我想大家以下就看懂了,首先就是判断当前状态,按钮点击是打开串口还是关闭串口,执行不同的操作,还有打开失败还是成功。大家应该很容易看懂。
接下来就是串口的收发数据了。
数据接收
数据接收部分,有一个比较难搞的地方,就是一旦你串口打开了,那么数据就必须要一直处于接收状态,如果你按照往常的使用while True来使用,你会发现你的显示界面卡着不动了。这边我们需要引入新的知识点:
线程
线程简单应用,就是打开线程,然后一直读串口数据:
import _thread
# 获取串口数据
def Com_Data_Rsv(threadName):
while True:
while Com_Open_Flag:
data = custom_serial.read_all()
if data == b'':
continue
else:
print("receive : ", data)
window.Set_Display_Data(data)
_thread.start_new_thread(Com_Data_Rsv, ("Thread-1",))
然后在UI界面的类中添加方法:
def Set_Display_Data(self, Data):
self.Date_Display.insertPlainText(str(Data, encoding="utf-8")) # 显示数据
打开线程,一直接收串口数据,只是串口处于打开情况下,我们才处理接收数据,最后把数据打印在界面上显示。
具体效果如下:
发送数据
综上所述,分为以下几个步骤
1、按钮事件重写
2、获取发送文本
3、通过串口发送
代码如下:
def Send_Data_Click(self):
print("点击了发送数据按钮")
Data_Need_Send = self.Send_Data_Dsiplay.toPlainText()
if custom_serial.isOpen():
custom_serial.write(Data_Need_Send.encode("gbk"))
else:
print("请先打开串口")
最终效果:
好了,当然还有很多不完善的地方,比如很多代码异常保护等等,大家可以自行增加,自行补充功能。本次讲解就到这。
QT部分其他功能大多都是这样了,大家有什么功能需要增加的,或者不懂的,可以留言,大家一起交流。
最终代码:
# ! /usr/bin/env python
# -*- coding: utf-8 -*-
import serial
import serial.tools.list_ports
import sys
from SerialPortTools import Ui_MainWindow
from PyQt5 import QtWidgets
import _thread
Com_Open_Flag = False # 串口打开标志
COM_Band = {"9600", "115200"}
custom_serial = serial.Serial
# 获取串口列表
def Get_Com_List():
return list(serial.tools.list_ports.comports())
# 获取串口数据
def Com_Data_Rsv(threadName):
while True:
while Com_Open_Flag:
data = custom_serial.read_all()
if data == b'':
continue
else:
print("receive : ", data)
window.Set_Display_Data(data)
# 界面UI按键程序重写
class Mywindow(QtWidgets.QMainWindow, Ui_MainWindow):
def __init__(self):
super(Mywindow, self).__init__()
self.setupUi(self)
COM_List = Get_Com_List() # 获取串口列表
for i in range(0, len(COM_List)): # 将列表导入到下拉框
self.Com_Port.addItem(COM_List[i].name)
self.Com_Band.addItem("9600")
self.Com_Band.addItem("115200")
def Open_Com_Click(self):
global custom_serial # 全局变量,需要加global
global Com_Open_Flag
print("点击了打开串口按钮")
if self.Open_Com.text() == "打开串口":
print(self.Com_Port.currentText())
custom_serial = serial.Serial(self.Com_Port.currentText(), int(self.Com_Band.currentText()), timeout=0.5)
if custom_serial.isOpen():
print("open success")
Com_Open_Flag = True
self.Open_Com.setText("关闭串口")
self.Com_Band.setEnabled(False) # 串口号和波特率变为不可选择
self.Com_Port.setEnabled(False)
else:
print("open failed")
else:
Com_Open_Flag = False
self.Open_Com.setText("打开串口")
custom_serial.close()
self.Com_Band.setEnabled(True) # 串口号和波特率变为可选择
self.Com_Port.setEnabled(True)
def Set_Display_Data(self, Data):
self.Date_Display.insertPlainText(str(Data, encoding="utf-8"))
def Send_Data_Click(self):
print("点击了发送数据按钮")
Data_Need_Send = self.Send_Data_Dsiplay.toPlainText()
if custom_serial.isOpen():
custom_serial.write(Data_Need_Send.encode("gbk"))
else:
print("请先打开串口")
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
window = Mywindow()
window.show()
_thread.start_new_thread(Com_Data_Rsv, ("Thread-1",))
sys.exit(app.exec_())