用PySide6、QML和PySerial打造并读取ESP32串口数据可视化通信
精通实时数据:用PySide6、QML和PySerial打造ESP32可视化通信QT界面📊
本喵又来写不一样的精品小教程啦
目录
安装Python和相关库 🐍
在我们开始之前,本喵默认你已经安装了python,安装pyserial指令如下~终端输入
pip install pyserial
pip install PySide6
安装我们需要的库
QML简介 🌟
QML是图形编辑用的语言,相当于将Qt编程变成html那么简单的格式,最后将qml文件由pyside库调用,咱们酷酷的界面就出来啦~
设置ESP32开发环境 🔧
在本喵的教程:
🌟【一站式教程】精通ESP32:使用VSCode与PlatformIO构建FreeRTOS项目、WIFI网页智能灯控系统、蓝牙、有趣的小功能 — 从轻松入门到项目实战
中写的很详细啦~
PySerial初探 🔍
PySerial提供了与串口设备通讯的接口。它允许您在Python脚本中打开、读取、写入和关闭串口。
从ESP32读取数据 📈
接下来,我们将编写一个简单的Python脚本来从ESP32通过串口读取数据。请确保您的ESP32已通过USB连接到电脑,并且您知道它的串口名称(例如,Windows上可能是COM3,Linux或Mac上可能是/dev/ttyUSB0)。
创建一个名为read_serial.py的新Python文件,并添加以下代码:
import serial
import time
# 替换以下串口名称与ESP32连接的实际串口名称
# 例如,Windows上可能是 COM3, Linux或Mac上可能是 /dev/ttyUSB0
SERIAL_PORT = 'COM3'
BAUD_RATE = 115200 # 根据ESP32程序设置的波特率调整
def main():
# 初始化串口连接
ser = serial.Serial(SERIAL_PORT, BAUD_RATE, timeout=1)
time.sleep(2) # 等待串口初始化
try:
print("开始从ESP32读取数据...")
while True:
if ser.in_waiting > 0:
# 从串口读取一行数据
line = ser.readline().decode('utf-8').rstrip()
print(f"接收到数据: {line}")
except KeyboardInterrupt:
print("程序被手动中断")
finally:
ser.close() # 确保串口连接被正确关闭
print("串口连接已关闭")
if __name__ == "__main__":
main()
运行脚本:
python read_serial.py
运行结果:
为了完成“构建数据可视化界面”这一部分的内容,我们将创建一个使用PySide6和QML的示例,以实现从ESP32通过串口接收的数据的动态可视化。
##构建数据可视化界面 📊
文件结构 🖌️

本喵的文件结构如上,创建这个
集成QML与Python 🧩
接下来,我们将使用PySide6在Python脚本中加载这个QML界面,并设置一个简单的框架来从串口读取数据并更新界面。
main.py:
import sys
from PySide6.QtCore import QCoreApplication, QObject, QUrl, Signal, Slot
from PySide6.QtGui import QGuiApplication
from PySide6.QtQml import QQmlApplicationEngine
import serial
import threading
# 初始化串口连接
SERIAL_PORT = 'COM3' # 更改为您的ESP32串口号
BAUD_RATE = 9600
ser = serial.Serial(SERIAL_PORT, BAUD_RATE, timeout=0.1)
class Backend(QObject):
dataReceived = Signal(str) # 创建一个信号
def __init__(self):
super().__init__()
self.serial_thread = threading.Thread(target=self.read_from_port)
self.serial_thread.start()
def read_from_port(self):
while True:
if ser.in_waiting > 0:
data = ser.readline().decode('utf-8').strip()
self.dataReceived.emit(data) # 发送信号
if __name__ == "__main__":
app = QGuiApplication(sys.argv)
engine = QQmlApplicationEngine()
backend = Backend()
engine.rootContext().setContextProperty("backend", backend)
engine.load(QUrl("main.qml"))
if not engine.rootObjects():
sys.exit(-1)
sys.exit(app.exec())
main.qml:
import QtQuick 6.5
import QtQuick.Controls 6.5
import Qtcharts
ApplicationWindow {
title: "ESP32 数据可视化"
width: 600
height: 400
visible: true
ChartView {
id: chart
title: "实时数据"
anchors.fill: parent
antialiasing: true
LineSeries {
id: dataSeries
name: "传感器数据"
}
}
Connections {
target: backend
onDataReceived: function(data) {
var newData = JSON.parse(data); // 假设数据以JSON格式传入,需要解析
dataSeries.append(newData.timestamp, newData.value); // 假设数据有时间戳和值
}
}
}
上述Python代码创建了一个后端类,该类在一个单独的线程中不断读取串口数据。当从ESP32接收到数据时,通过信号dataReceived将数据发送出去。
QML文件中,Connections组件用于连接我们的后端(即Python脚本中的Backend类)和QML界面。每当dataReceived信号被触发时,onDataReceived处理函数就会更新文本控件中的文本,显示从串口接收到的最新数据。
动态展示数据 🌈
运行效果~

动态展示图表📈
先上效果~~~
将main.py和main.qml更新为以下样式
main.qml:
import QtQuick 6.5
import QtQuick.Controls 6.5
import QtCharts 2.15
ApplicationWindow {
visible: true
width: 640
height: 480
title: "ESP32 随机数据可视化"
ChartView {
id: chart
anchors.fill: parent
antialiasing: true
DateTimeAxis {
id: axisX
format: "hh:mm:ss"
tickCount: 5 // 根据需要调整
min: new Date()
max: new Date(new Date().getTime() + 20 * 1000) // 设置为当前时间加20秒
}
ValueAxis {
id: axisY
min: 0
max: 100
}
LineSeries {
id: lineSeries
name: "实时数据"
axisX: axisX
axisY: axisY
}
}
Timer {
interval: 1000 // 1秒
repeat: true
running: true
onTriggered: {
let now = new Date();
lineSeries.append(now.getTime(), data); // 使用当前时间戳作为X轴
if (lineSeries.count > 20) { // 保持最近20个数据点
let firstItemTime = lineSeries.at(0).x; // 获取第一个数据点的时间
axisX.min = new Date(now.getTime() - 20 * 1000);
axisX.max = now; // 确保当前点在范围内
lineSeries.remove(0); // 移除最旧的数据点以保持图表清晰
}
}
}
// 这里假设'backend'是已经定义并能够接收数据的组件
// 如果需要从外部设备接收数据,您需要定义这个组件并确保它可以触发'onDataReceived'事件
Connections {
target: backend
onDataReceived: function(data) {
console.log("接收到的数据: " + data);
lineSeries.append(new Date().getTime(), parseInt(data));
// 这里不需要手动调整X轴,因为已经在Timer中处理
}
}
}
main.py:
import sys
import serial
import threading
from PySide6.QtCore import QObject, Signal
from PySide6.QtWidgets import QApplication
from PySide6.QtQml import QQmlApplicationEngine
SERIAL_PORT = 'COM14' # 更改为您的ESP32串口号
BAUD_RATE = 115200
class Backend(QObject):
dataReceived = Signal(int)
def __init__(self, serial_port, baud_rate):
super().__init__()
self.ser = serial.Serial(serial_port, baud_rate, timeout=1)
self.serial_thread = threading.Thread(target=self.read_from_port)
self.serial_thread.daemon = True
self.serial_thread.start()
def read_from_port(self):
while True:
if self.ser.in_waiting > 0:
data = self.ser.readline().decode('utf-8').strip()
if data.isdigit():
self.dataReceived.emit(int(data))
if __name__ == "__main__":
app = QApplication(sys.argv)
engine = QQmlApplicationEngine()
backend = Backend(SERIAL_PORT, BAUD_RATE)
engine.rootContext().setContextProperty("backend", backend)
engine.load("main.qml")
if not engine.rootObjects():
sys.exit(-1)
sys.exit(app.exec())
更多推荐
所有评论(0)