开发环境搭建
1. 编辑工具 vscode 安装,vscode 下载网址。Linux 安装运行以下命令:
sudo snap install --classic code
2.管理python环境 anaconda 工具 工具安装,Linux Anconda 安装脚本下载anconda地址(清华源),在末尾查找对应服务器的最新版本号。Linux 安装运行以下命令:
wget https://mirrors.tuna.tsinghua.edu.cn/anaconda/archive/Anaconda3-5.3.1-Linux-x86_64.sh
安装 anaconda
bash Anaconda3-5.3.1-Linux-x86_64.sh
使用 anconda 搭建python 的 虚拟运行环境
1, windows 环境下,运行在 "开始菜单下" --> "所有应用" --> "Anaconda3(64-bit)目录下"--> “Anaconda Powershell Prompt”,进入终端界面。
2.设置 Anconda Python pip 为国内的下载源,清华镜像源。
conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/
conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main/
conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/pytorch/
conda config --set show_channel_urls yes
pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple
3. 安装对应的python 版本,并创建对应的python 运行环境,我的python 版本 Python 3.11.8。
conda create -n env_name python=3.11 # 创建一个名为env_name,版本为3.11的python虚拟环境
4. 查看主机中存在的虚拟环境
conda env list
5. 激活虚拟环境conda activate env_name
6. 删除虚拟环境
conda remove --name <env_name> --all
安装 Pyside6, pySerial 库
1. 激活创建的虚拟环境
conda activate env_name
2. 安装 PySide6, pySerial库
pip install PySide6
使用 Pyside6,pySerial 库练习搭建 串口调试助手
from PySide6.QtWidgets import *
from PySide6.QtCore import *
from PySide6.QtGui import *
import serial.tools.list_ports
baud_rates = [115200, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800, 9600, 19200, 38400, 57600]
parity_options = ["None", "Even", "Odd"]
data_bits_options = [8, 7, 6, 5]
stop_bits_options = [1, 1.5, 2]
class SerialThread(QThread):
received_data = Signal(bytes)
def __init__(self, serial):
super().__init__()
self.serial = serial
self.running = True
def run(self):
while self.running and self.serial.isOpen():
data = self.serial.read(1024)
if data:
self.received_data.emit(data)
def stop(self):
self.running = False
class SerialPort:
def __init__(self, device, description, manufacturer, hwid):
self.device = device
self.description = description
self.manufacturer = manufacturer
self.hwid = hwid
class IndicatorLed(QAbstractButton):
def __init__(self, parent=None):
super(IndicatorLed, self).__init__(parent)
self.initUI()
def initUI(self):
self.setMinimumSize(24, 24)
self.setCheckable(True) # 设置可选中
self.colorOn = QColor(0, 240, 0) # 绿色
self.colorOff = QColor(240, 0, 0) # 红色
def mousePressEvent(self, event):
pass # 禁用鼠标点击事件
def paintEvent(self, event):
painter = QPainter(self)
painter.setRenderHint(QPainter.Antialiasing, True)
painter.setPen(Qt.NoPen)
# 绘制外圈
outerRadius = min(self.width(), self.height())
outerRect = QRectF(0, 0, outerRadius, outerRadius)
gradient = QRadialGradient(outerRect.center(), outerRadius, outerRect.center())
gradient.setColorAt(0, Qt.white)
gradient.setColorAt(1, self.colorOn if self.isChecked() else self.colorOff)
painter.setBrush(gradient)
painter.drawEllipse(outerRect)
# 绘制内圈
innerRadius = outerRadius * 0.6
innerRect = QRectF((outerRadius - innerRadius) / 2, (outerRadius - innerRadius) / 2, innerRadius, innerRadius)
painter.setBrush(self.colorOn if self.isChecked() else self.colorOff)
painter.drawEllipse(innerRect)
class MainWindow(QMainWindow):
received_data = Signal(bytes)
def __init__(self):
super().__init__()
self.setWindowTitle("串口调试助手")
# 定义成员变量用于存储用户选择的串口参数
self.selected_port = "COM1"
self.selected_baud_rate = 9600 # 默认波特率
self.selected_parity = 'N' # 默认奇偶校验位
self.selected_data_bits = 8 # 默认数据位
self.selected_stop_bits = 1 # 默认停止位
# 创建串口对象
self.serial = None
self.serial_thread = None
# 创建文本
self.text_display = QTextEdit()
self.text_display.setReadOnly(True)
self.text_display.setStyleSheet("background-color: black; color: white;") # 设置样式表
# 创建文本输入框
self.text_input = QTextEdit()
self.text_input.setMinimumHeight(50) # 设置最小高度
self.text_input.setMaximumHeight(100) # 设置最大高度
# 创建发送和清除按钮
send_button = QPushButton("发送")
clear_button = QPushButton("清除")
send_button.setMinimumHeight(45) # 设置按钮高度
clear_button.setMinimumHeight(45) # 设置按钮高度
# 创建下拉串口选择框
self.serial_combo_box = QComboBox()
self.buad_combo_box = QComboBox()
self.parity_combo_box = QComboBox()
self.data_bits_combo_box = QComboBox()
self.stop_bits_combo_box = QComboBox()
# 遍历波特率列表并添加到下拉选择框的选项中
for baud_rate in baud_rates:
self.buad_combo_box.addItem(str(baud_rate))
# 添加奇偶校验位选项
self.parity_combo_box.addItems(parity_options)
# 添加数据位选项
self.data_bits_combo_box.addItems([str(bits) for bits in data_bits_options])
# 添加停止位选项
self.stop_bits_combo_box.addItems([str(bits) for bits in stop_bits_options])
# 创建下拉选择框水平布局
combox_layout = QHBoxLayout()
combox_layout.addWidget(send_button)
combox_layout.addWidget(clear_button)
# 创建按钮布局
button_layout = QVBoxLayout()
button_layout.addWidget(send_button)
button_layout.addWidget(clear_button)
# 创建文本输入框和按钮的水平布局
input_layout = QHBoxLayout()
input_layout.addWidget(self.text_input)
input_layout.addLayout(button_layout)
# 将文本显示框放入滚动区域
scroll_area = QScrollArea()
scroll_area.setWidgetResizable(True)
scroll_area.setWidget(self.text_display)
# 创建串口操作 水平布局
serial_operation_layout = QHBoxLayout()
serial_operation_label = QLabel("串口操作: ")
self.led = IndicatorLed()
self.led.setChecked(False) # 设置为灭
self.connect_button = QPushButton("Connect")
serial_operation_layout.addWidget(serial_operation_label)
serial_operation_layout.addWidget(self.connect_button)
serial_operation_layout.addWidget(self.led)
# 创建主布局
layout = QHBoxLayout()
# 创建左侧布局
left_layout = QVBoxLayout()
# 创建右侧布局
right_layout = QVBoxLayout()
# 创建串口选择框布局
serial_layout = QHBoxLayout()
serial_label = QLabel("串口选择:")
serial_layout.addWidget(serial_label)
serial_layout.addWidget(self.serial_combo_box)
# 创建波特率选择框布局
buad_layout = QHBoxLayout()
buad_label = QLabel("波特率选择:")
buad_layout.addWidget(buad_label)
buad_layout.addWidget(self.buad_combo_box)
# 创建奇偶校验位选择框布局
parity_layout = QHBoxLayout()
parity_label = QLabel("奇偶校验位:")
parity_layout.addWidget(parity_label)
parity_layout.addWidget(self.parity_combo_box)
# 创建数据位选择框布局
data_bits_layout = QHBoxLayout()
data_bits_label = QLabel("数据位:")
data_bits_layout.addWidget(data_bits_label)
data_bits_layout.addWidget(self.data_bits_combo_box)
# 创建停止位选择框布局
stop_bits_layout = QHBoxLayout()
stop_bits_label = QLabel("停止位:")
stop_bits_layout.addWidget(stop_bits_label)
stop_bits_layout.addWidget(self.stop_bits_combo_box)
left_layout = QVBoxLayout()
left_layout.setSpacing(10) # 设置固定的垂直间距为10像素
left_layout.addLayout(serial_layout)
left_layout.addLayout(buad_layout)
left_layout.addLayout(parity_layout)
left_layout.addLayout(data_bits_layout)
left_layout.addLayout(stop_bits_layout)
left_layout.addLayout(serial_operation_layout)
left_layout.addStretch(1) # 添加一个伸缩项,占据剩余空间
# 创建一个QFrame对象
frame = QFrame()
frame.setFrameShape(QFrame.Panel) # 设置边框形状为Panel
frame.setFrameShadow(QFrame.Raised) # 设置边框阴影效果为Raised
frame.setStyleSheet("border: 2px solid blue;") # 设置边框样式为蓝色实线边框
# 将QVBoxLayout添加到QFrame中
frame.setLayout(left_layout)
right_layout.addWidget(scroll_area)
right_layout.addLayout(input_layout)
layout.addWidget(frame)
layout.addLayout(right_layout)
# 创建主部件并设置布局
main_widget = QWidget()
main_widget.setLayout(layout)
self.setCentralWidget(main_widget)
# 连接发送按钮的clicked信号到槽函数
send_button.clicked.connect(self.on_send_button_clicked)
# 连接清除按钮的clicked信号到槽函数
clear_button.clicked.connect(self.on_clear_button_clicked)
# 串口连接操作按钮
self.connect_button.clicked.connect(self.handleConnectButton)
# 创建定时器
self.timer = QTimer()
self.timer.setInterval(1000) # 设置定时器的时间间隔为1秒
self.timer.timeout.connect(self.update_serial_ports) # 连接定时器的timeout信号到更新串口列表的函数
self.timer.start() # 启动定时器
# 更新串口列表和下拉选择框
self.update_serial_ports()
# 发送按钮点击时触发的槽函数
def on_send_button_clicked(self):
text = self.text_input.toPlainText() # 获取文本输入框的内容
# 获取当前时间并格式化为字符串
current_time = QDateTime.currentDateTime().toString("yyyy-MM-dd hh:mm:ss.zzz")
# 添加时间前缀
text_with_time = f"[{current_time}] {text}"
# 设置文本颜色为微蓝色
color = QColor(0, 0, 255) # 微蓝色
self.text_display.setTextColor(color)
# 在文本显示框中添加带有时间前缀的文本
self.text_display.append(text_with_time)
# 将光标移动到文本末尾
cursor = self.text_display.textCursor()
cursor.movePosition(QTextCursor.End)
self.text_display.setTextCursor(cursor)
# 清除按钮点击时触发的槽函数
def on_clear_button_clicked(self):
self.text_display.clear() # 清空文本显示框的内容
# 更新串口列表和下拉选择框
def update_serial_ports(self):
# 获取电脑上所有的串口列表
ports = serial.tools.list_ports.comports()
# 获取当前选中的串口
current_port = self.serial_combo_box.currentText()
# 清空下拉选择框的选项
self.serial_combo_box.clear()
# 遍历串口列表并更新下拉选择框的选项
for port in ports:
device = port.device
self.serial_combo_box.addItem(device)
# 恢复之前选中的串口
if current_port:
index = self.serial_combo_box.findText(current_port)
if index != -1:
self.serial_combo_box.setCurrentIndex(index)
def start_listening(self):
if self.serial is not None and self.serial.isOpen():
self.serial_thread = SerialThread(self.serial)
self.serial_thread.received_data.connect(self.handle_received_data)
self.serial_thread.start()
def closeEvent(self, event):
if self.serial_thread is not None and self.serial_thread.isRunning():
self.serial_thread.stop()
self.serial_thread.wait()
event.accept()
def handleConnectButton(self):
self.selected_port = self.serial_combo_box.currentText()
self.selected_baud_rate = int(self.buad_combo_box.currentText())
pos = self.parity_combo_box.currentIndex()
if pos == 0:
self.selected_parity = 'N' # 默认无校验位
elif pos == 1:
self.selected_parity = 'E' # 默认奇校验位
elif pos == 2:
self.selected_parity = 'O' # 默认奇校验位
self.selected_data_bits = int(self.data_bits_combo_box.currentText())
self.selected_stop_bits = float(self.stop_bits_combo_box.currentText())
if self.connect_button.text() == "Connect":
try:
# 创建串口连接
self.serial = serial.Serial(
port=self.selected_port,
baudrate=self.selected_baud_rate,
# parity=self.selected_parity,
# bytesize=self.selected_data_bits,
# stopbits=self.selected_stop_bits,
timeout=0.5,
# xonxoff=0, # enable software flow control
# rtscts=0, # enable RTS/CTS flow control
)
print(self.serial)
# 启动监听线程
self.start_listening()
# 设置连接按钮和指示灯的状态
self.connect_button.setText("Disconnect")
self.led.setChecked(True)
except serial.SerialException as e:
self.serial.close()
QMessageBox.warning(self, "警告", f"串口连接失败:{str(e)}")
else:
# 关闭串口连接
self.serial.close()
# 设置连接按钮和指示灯的状态
self.connect_button.setText("Connect")
self.led.setChecked(False)
def handle_received_data(self, data):
# 获取当前时间并格式化为字符串
current_time = QDateTime.currentDateTime().toString("yyyy-MM-dd hh:mm:ss.zzz")
# 添加时间前缀
text_with_time = f"[{current_time}] {data}"
# 处理接收到的数据,例如显示在文本显示框中
self.text_display.append(text_with_time.decode('utf-8'))
if __name__ == '__main__':
# 创建应用程序并运行
app = QApplication([])
# 获取主屏幕
primary_screen = app.primaryScreen()
# 获取显示屏的大小
screen_geometry = primary_screen.geometry()
screen_width = screen_geometry.width()
screen_height = screen_geometry.height()
window = MainWindow()
# 设置窗口的默认大小为宽度为2/3,高度为2/3
window.resize(screen_width * 2 / 3, screen_height * 2 / 3)
window.show()
app.exec()
代码问题-待解决
1. 在接收带有颜色字节的串口数据时,颜色字节不能在文本框正常生效,会打印在文本框内看起来像乱码,如下:
[0;32m 表示设置文本颜色为绿色。
2.本文只是记录,练习时所遇到的问题。