在 Windows 中使用 PyQt 和 PySerial 实现串口数据读取


在 Windows 中使用 PyQt 和 PySerial 实现串口数据读取

简介

串口通信在许多嵌入式和物联网项目中都是一个重要的组成部分。本博客将详细介绍如何使用 Python 的 PyQt 和 PySerial 库,通过创建一个简单的界面,在 Windows 操作系统下实现串口数据的读取,并在界面上实时显示导航模块的经纬度数据。

技术栈

  • PyQt:用于创建桌面应用程序的强大 Python 框架。
  • PySerial:用于串口通信的 Python 库。
  • Python 3.x:我们使用 Python 3.x 版本。

环境搭建

在开始之前,请确保已经安装了 Python、PyQt 和 PySerial。你可以使用以下命令安装这两个库:

pip install pyqt5 pyserial

如果安装速度太慢,可以尝试国内源安装:

pip install -i https://pypi.tuna.tsinghua.edu.cn/simple 包名

界面设计

首先,我们设计一个简单的用户界面,包括串口选择、波特率、数据位、停止位的设置,以及一个按钮用于开始和停止读取。

# 导入必要的库
import sys
import serial
import csv
from PyQt5.QtCore import Qt, QThread, pyqtSignal
from PyQt5.QtWidgets import QApplication, QMainWindow, QLabel, QPushButton, QComboBox, QVBoxLayout, QWidget, QLineEdit, QHBoxLayout
from serial.tools import list_ports

# ...(省略部分代码)

class SerialReader(QMainWindow):
    def __init__(self):
        super().__init__()

        # 界面设计代码省略...

        # 显示经度和纬度的文本框
        self.longitude_label = QLabel("经度:")
        self.longitude_display = QLineEdit(self)
        self.longitude_display.setReadOnly(True)

        self.latitude_label = QLabel("纬度:")
        self.latitude_display = QLineEdit(self)
        self.latitude_display.setReadOnly(True)

        # 界面布局代码省略...

    # ...(省略部分代码)

    def handle_data_received(self, longitude, latitude):
        # Update the displayed coordinates
        self.longitude_display.setText(str(longitude))
        self.latitude_display.setText(str(latitude))

串口数据读取

为了实现串口数据的读取,我们创建了一个继承自 QThread 的 SerialReaderThread 类。在这个类中,我们使用 PySerial 打开串口,并通过 struct 解析二进制数据。

import struct

class SerialReaderThread(QThread):
    data_received = pyqtSignal(float, float)

    def __init__(self, port, baudrate, databits, stopbits):
        super().__init__()
        self.port = port
        self.baudrate = baudrate
        self.databits = databits
        self.stopbits = stopbits
        self.serial = None
        self.running = False

    def run(self):
        try:
            with serial.Serial(self.port, self.baudrate, bytesize=self.databits, stopbits=self.stopbits, timeout=2) as ser:
                self.running = True
                while self.running:
                    # Assuming the data is a binary format, with two 4-byte floats (longitude and latitude)
                    data = ser.read(8)  # Assuming each data point is 8 bytes (adjust accordingly)
                    if data:
                        # Unpack the binary data into two floats
                        longitude, latitude = struct.unpack('ff', data)
                        self.data_received.emit(longitude, latitude)
                        # Save data to CSV file
                        with open('gps_data.csv', 'a', newline='') as csvfile:
                            csv_writer = csv.writer(csvfile)
                            csv_writer.writerow([longitude, latitude])
        except Exception as e:
            print(f"串口读取错误:{str(e)}")

    def stop(self):
        self.running = False
        self.wait()

主界面与线程连接

在主界面中,我们通过按钮连接了开始和停止串口读取的操作,并在串口数据接收时更新了界面上的经纬度数据。

class SerialReader(QMainWindow):
    def __init__(self):
        super().__init__()

        # ...(省略部分代码)

        # 开始和停止读取按钮的点击事件连接
        self.start_button.clicked.connect(self.toggle_serial_reading)

        # ...(省略部分代码)

    def toggle_serial_reading(self):
        if not self.serial_reader_thread or not self.serial_reader_thread.isRunning():
            # Start reading
            port = self.serial_port_combobox.currentText()
            baudrate = int(self.baudrate_combobox.currentText())
            databits = int(self.databits_combobox.currentText())
            stopbits = float(self.stopbits_combobox.currentText())

            self.serial_reader_thread = SerialReaderThread(port, baudrate, databits, stopbits)
            self.serial_reader_thread.data_received.connect(self.handle_data_received)
            self.serial_reader_thread.start()

            self.start_button.setText("停止读取")
        else:
            # Stop reading
            self.serial_reader_thread.stop()
            self.start_button.setText("开始读取")

效果展示:
在这里插入图片描述

总结

通过结合 PyQt 和 PySerial,我们成功实现了一个串口数据读取的应用程序。这个应用程序可以在 Windows 操作系统中选择串口、设置通信参数,并实时显示导航模块的经纬度数据。这为处理实时定位信息提供了一个简单而强大的工具。

在实际应用中,你可能需要根据你的项目需求进一步调整界面设计和串口通信的细节。希望这篇博客能够帮助你入门串口通信的 Python 编程,并激发你进一步探索这个领域的兴趣。

  • 11
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 使用pyqt实现串口数据读取,并在各个edit_line显示出来的步骤如下: 1. 导入pyqt的QtCore库和QtSerialPort模块。 2. 连接串口和打开串口使用QSerialPort类实现。设置串口的波特率、数据位、停止位等参数。 3. 使用QTimer类,定时读取串口数据。将读取到的数据转换为字符串类型,并显示在各个edit_line控件上。 4. 最后,关闭串口连接。 具体实现过程参考如下代码(仅供参考): ```python from PyQt5.QtCore import QObject, QTimer, QIODevice from PyQt5.QtSerialPort import QSerialPort, QSerialPortInfo class SerialPort(QObject): def __init__(self): super(SerialPort, self).__init__() self.port = QSerialPort() self.init_port() def init_port(self): port_list = QSerialPortInfo.availablePorts() for i in port_list: if i.portName() == 'COM3': # 修改为自己的串口 self.port.setPort(i) if self.port.isOpen(): self.port.close() self.port.setBaudRate(QSerialPort.BaudRate(9600)) self.port.setDataBits(QSerialPort.DataBits(8)) self.port.setParity(QSerialPort.Parity(0)) self.port.setStopBits(QSerialPort.StopBits(1)) self.port.setFlowControl(QSerialPort.NoFlowControl) if self.port.open(QIODevice.ReadWrite): self.read_data() def read_data(self): self.timer = QTimer() self.timer.timeout.connect(self.receive_data) self.timer.start(100) # 100毫秒读取一次串口数据 def receive_data(self): data = self.port.readAll().data() if data and data != "": data = str(data, encoding='ascii') # 转换为字符串类型 # 将数据显示在各个edit_line控件,例如:self.lineedit1.setText(data) # 清除串口缓存 self.port.clear() def close_port(self): if self.port.isOpen(): self.port.close() # 关闭串口连接 ``` 在main函数调用SerialPort类并运行程序即可实现串口数据读取,并在各个edit_line显示出来。 ### 回答2: PyQt是Python下的一个GUI编程工具包。如果要实现串口数据读取,并在不同的edit_line控件显示,我们可以用Qt的串口类和PyQt的QTextEdit控件结合起来使用。 首先,在PyQt创建一个QSerialPort对象,设置好串口的波特率、数据位数、校验位、停止位等参数。然后,我们需要连接串口读取数据的信号和槽函数,在槽函数处理读取到的数据,将其转换为字符串并显示到对应的QTextEdit控件。代码如下: ```python import sys from PyQt5.QtWidgets import QApplication, QMainWindow, QTextEdit from PyQt5.QtSerialPort import QSerialPort, QSerialPortInfo class SerialPort(QMainWindow): def __init__(self): super().__init__() # 创建串口对象 self.serial = QSerialPort() self.serial.setPortName("COM1") self.serial.setBaudRate(QSerialPort.Baud9600) self.serial.setDataBits(QSerialPort.Data8) self.serial.setParity(QSerialPort.NoParity) self.serial.setStopBits(QSerialPort.OneStop) # 连接读取数据的信号和槽函数 self.serial.readyRead.connect(self.receive_data) # 创建3个QTextEdit控件用于显示接收到的数据 # 分别是文本、十六进制和ASCII码显示 self.textEdit1 = QTextEdit(self) self.textEdit1.setGeometry(10, 10, 200, 100) self.textEdit2 = QTextEdit(self) self.textEdit2.setGeometry(10, 120, 200, 100) self.textEdit3 = QTextEdit(self) self.textEdit3.setGeometry(10, 230, 200, 100) # 显示窗口 self.setGeometry(100, 100, 220, 340) self.setWindowTitle("Serial Port") self.show() # 读取串口数据的槽函数 def receive_data(self): data = self.serial.readAll() if data != b'': # 将接收到的数据转换为字符串 text = data.decode('gbk') # 在不同的QTextEdit控件显示数据 self.textEdit1.append(text) self.textEdit2.append(' '.join(['{:02X}'.format(x) for x in data])) self.textEdit3.append(' '.join([chr(x) if 32 <= x <= 126 else '.' for x in data])) if __name__ == '__main__': app = QApplication(sys.argv) ex = SerialPort() sys.exit(app.exec_()) ``` 以上代码演示了如何在PyQt使用QSerialPort读取串口数据,并在3个QTextEdit控件显示不同的格式化数据。这里使用了gbk编码来解码接收到的数据,你可以根据实际情况进行修改。另外,需要注意的是,在Windows串口的名称一般是以"COMx"的形式表示,如果是其他操作系统,串口名称可能会不同。 ### 回答3: 在 PyQT ,我们可以使用 PySerial实现串口数据读取。具体来说,我们需要完成以下几个步骤: 1. 导入 PySerial 库:使用 `import serial` 即可。 2. 打开串口使用 `serial.Serial()` 函数打开串口。例如,`ser = serial.Serial(port='COM1', baudrate=9600, bytesize=8, parity='N', stopbits=1, timeout=None)` 表示打开 COM1 端口,波特率为 9600,数据位为 8 位,无奇偶校验,停止位为 1 位,读取数据时没有超时限制。 3. 读取串口数据使用 `ser.readline()` 函数可以从串口读取一行数据,并将其返回为字符串类型。 4. 在 Edit Line 显示数据使用 `edit_line.setText(str)` 函数即可将字符串 str 显示在 Edit Line 。当然,我们可以根据需要使用 `edit_line.clear()` 函数清空 Edit Line 再显示最新的数据。 下面是一个完整的代码示例,可以监听串口 COM1,将每秒读取数据显示在三个 Edit Line : ```python import sys import serial from PyQt5.QtCore import QTimer, Qt from PyQt5.QtGui import QIcon from PyQt5.QtWidgets import QApplication, QWidget, QLabel, QLineEdit, QVBoxLayout class SerialReader(QWidget): def __init__(self): super().__init__() self.initUI() def initUI(self): self.setWindowTitle('Serial Reader') self.setWindowIcon(QIcon('serial.png')) self.label1 = QLabel('Data 1') self.edit1 = QLineEdit() self.edit1.setReadOnly(True) self.label2 = QLabel('Data 2') self.edit2 = QLineEdit() self.edit2.setReadOnly(True) self.label3 = QLabel('Data 3') self.edit3 = QLineEdit() self.edit3.setReadOnly(True) vbox = QVBoxLayout() vbox.addWidget(self.label1) vbox.addWidget(self.edit1) vbox.addWidget(self.label2) vbox.addWidget(self.edit2) vbox.addWidget(self.label3) vbox.addWidget(self.edit3) self.setLayout(vbox) # Open serial port self.ser = serial.Serial(port='COM1', baudrate=9600) # Use a QTimer to periodically read serial data self.timer = QTimer(self) self.timer.timeout.connect(self.readSerial) self.timer.start(1000) # Read every second self.show() def readSerial(self): if self.ser.in_waiting: # Read the next line of data data = self.ser.readline().decode().strip() # Split the data into three parts parts = data.split(',') if len(parts) != 3: return # Show each part of the data in a different Edit Line self.edit1.setText(parts[0]) self.edit2.setText(parts[1]) self.edit3.setText(parts[2]) if __name__ == '__main__': app = QApplication(sys.argv) ex = SerialReader() sys.exit(app.exec_()) ``` 其,`initUI()` 函数用于初始化界面,包括创建三个 Label 和 Edit Line,以及打开串口和启动 QTimer。`readSerial()` 函数用于读取串口数据,并将其显示在 Edit Line 。注意,我们使用 `decode()` 函数将读取的字节数据转换为字符串,使用 `strip()` 函数删除字符串的空格和换行符。同时,我们假设每行数据包含三个部分,使用逗号分隔。 运行程序后,每秒钟程序会从串口读取一行数据,然后将其拆分成三部分,分别显示在三个 Edit Line 。用户可以根据实际需求修改串口参数和数据解析方式。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值