【python上位机开发】5、串口相关的功能
一、环境安装
串口相关的功能是这次上位机的核心也是基础,所以第五章先总结一下这部分吧。
安装串口相关的库函数,pip install pyserial 或者直接软件包里面安装即可,版本任意,不过最好新一些。(我这边使用的是3.5版本)
pip install pyserial
二、逻辑分析
为了保证我们串口工具的正常使用,我们需要做到:
1、如果有新的串口接入pc,我们要做及时的更新
2、要获取电脑已连接的串口名称
3、串口打开/关闭
4、串口接收数据
5、串口发送数据
以上这些就是我们要去实现的串口相关的功能,接下来针对每一项功能去做实现,写对应的功能代码。
三、更新串口号和获取已经连接的串口名称
为了使得整体逻辑更清晰,会按照逻辑顺序的序号编写。
1、创建一个串口类(class serial_class)
class serial_class
2、定义构造函数,实例化一个py.serial类,定义一个列表,用于存放串口号。
class serial_class:
def __init__(self):
self.Serial_Next_Port_Number = []
self.serial = serial.Serial()
3、扫描当前的串口号
def serial_port_scan():
serial_port_list = list(serial.tools.list_ports.comports())
now_port = []
for number in serial_port_list:
now_port.append(number.device)
return now_port
4、判断串口是否变化,执行相关的函数,如果串口一致,就执行pass语句。若不一致,且串口是打开状态,说明串口被拔掉了,则弹窗提示,并且对应的按钮使能。
def serial_is_change(self):
now_port = self.con.serial_class.serial_port_scan() # 获取当前的串口号
if now_port == self.con.serial_class.Serial_Next_Port_Number: # 如果两个列表一致,说明串口没有发生改变,不做处理,执行pass语句
pass
else:
try:
if self.con.serial_class.Serial_Next_Port_Number != now_port and self.con.serial_class.serial.is_open:
QMessageBox.information(self,"错误","串口已拔出",QMessageBox.Yes,QMessageBox.Yes) # 如果是打开的情况下拔出串口,则弹出警告弹窗
self.con.serial_class.serial.close() # 承上逻辑,关闭串口
self.con.ui.ui.close_uart_pushButton.setEnabled(True) # 且“关闭按钮”使能
self.con.ui.ui.open_uart_pushButton.setEnabled(True)# “打开按钮”使能
except Exception as error:
print(error)
finally:
self.con.ui.ui.uart_number_comboBox.clear() # 清空串口号显示
self.con.ui.ui.uart_number_comboBox.addItems(now_port) # 重新载入新的串口号
self.con.serial_class.Serial_Next_Port_Number = now_port # 将获取到的串口号载入为最新
self.con.ui.ui.baud_comboBox.setEnabled(True) # 波特率显示框使能
self.con.ui.ui.stop_bit_comboBox.setEnabled(True) # 停止位显示使能
self.con.ui.ui.check_bit_comboBox.setEnabled(True)# 校验位显示使能
self.con.ui.ui.uart_number_comboBox.setEnabled(True)# 串口号显示使能
self.con.ui.ui.data_bit_comboBox.setEnabled(True) # 数据位显示使能
5、保持持续执行。如果是按照从上到下的代码执行顺序,对应的函数只执行一次,我们需要在程序启动的时候,一直的去扫描,持续的监控。这时候就需要用到一个定时器,定时的去执行我们的检测函数,保证每一次的串口变化都可以及时的更新。(ps:定时器在主控制类定义和实例化哦)
self.timer.timeout.connect(self.serial_con.serial_is_change)
四、串口打开/关闭
串口的打开需要我们定义,串口号、波特率、校验位、数据位、停止位。我们可以从ui页面的combox的数据中获取

那我们要怎么去获取这些方框内的值呢?利用以下方法:
ui.ui.uart_number_comboBox.currentText()
QT的comboBox有一个currenText()方法,就是获取里面的值。
所以这个功能的实现为:
1、获取对应comboBox里面的值
2、将1中获取的值,给serial打开的所需数据赋值
3、实例化对应的类,最后串口即可打开成功
4、串口关闭的话,使用close()方法
(ps:下面的函数是打开串口的槽函数,会涉及到其他功能点,看不懂的可以先不管,看上半部分的逻辑即可)
@Slot()
def pushbutton_serial_open_slot(self):
stop_bit = (1, 1.5, 2)
check_bit = ('N', 'O', 'E') # 'N' 无校验 'O' 奇校验 'E'偶校验
choice_serial_port_number = self.con.ui.ui.uart_number_comboBox.currentText()
choice_serial_baud_rate = int(self.con.ui.ui.baud_comboBox.currentText())
choice_serial_data_bit = int(self.con.ui.ui.data_bit_comboBox.currentText())
choice_serial_check_bit = self.con.ui.ui.check_bit_comboBox.currentIndex()
choice_serial_stop_bit = self.con.ui.ui.stop_bit_comboBox.currentIndex()
try:
self.con.serial_class.serial = serial.Serial(port=choice_serial_port_number,
baudrate=choice_serial_baud_rate,
bytesize=choice_serial_data_bit,
parity=check_bit[choice_serial_check_bit],
stopbits=stop_bit[choice_serial_stop_bit])
if self.con.serial_class.serial.is_open:
self.con.ui.ui.uart_number_comboBox.setEnabled(False)
self.con.ui.ui.baud_comboBox.setEnabled(False)
self.con.ui.ui.data_bit_comboBox.setEnabled(False)
self.con.ui.ui.check_bit_comboBox.setEnabled(False)
self.con.ui.ui.stop_bit_comboBox.setEnabled(False)
self.con.ui.ui.open_uart_pushButton.setEnabled(False)
self.con.ui.ui.close_uart_pushButton.setEnabled(True)
self.con.ui.ui.pushButton.setEnabled(True)
self.con.ui.ui.checkBox.setEnabled(False)
QMessageBox.information(self, "小赖提示", self.con.serial_class.serial.name + "打开成功" , QMessageBox.Ok, QMessageBox.Ok)
except Exception as error:
if "拒绝访问" in str(error):
QMessageBox.information(self, "小赖提示", "串口拒绝访问", QMessageBox.Yes, QMessageBox.Yes)
else:
QMessageBox.information(self, "小赖提示", "打开失败", QMessageBox.Yes, QMessageBox.Yes)
self.con.ui.ui.open_uart_pushButton.setEnabled(True)
print(error)
if self.con.serial_class.serial.is_open and (not self.Serial_Open_state): # 串口打开成功
self.con.serial_con.Serial_Data_RX_Thread.start()
self.Serial_Open_state = True
五、串口接收数据
调用串口的read相关的方法,这里使用readline,读取整行数据(详情在后续的接收数据槽函数当中详细解答)
六、串口发送数据
调用串口的write方法,写入数据(详细在后续的发送数据槽函数当中详细解答)
七、结束语
串口相关的功能就到这边了,后续还会继续更新,其中的一些部分也有借鉴网上一些大佬的思路,若有一些错误的地方,烦请指正。
未完待续。。。。。
作者:重生之我在厦门做测试