开源 C++ QT Widget 开发(五)通讯--串口调试
文章的目的为了记录使用C++ 进行QT Widget 开发学习的经历。临时学习,完成app的开发。开发流程和要点有些记忆模糊,赶紧记录,防止忘记。
相关链接:
开源 C++ QT Widget 开发(一)工程文件结构-CSDN博客
开源 C++ QT Widget 开发(二)基本控件应用-CSDN博客
开源 C++ QT Widget 开发(三)图表--波形显示器-CSDN博客
开源 C++ QT Widget 开发(四)文件--二进制文件查看编辑-CSDN博客
开源 C++ QT Widget 开发(五)通讯--串口调试-CSDN博客
开源 C++ QT Widget 开发(六)通讯--TCP调试-CSDN博客
推荐链接:
开源 java android app 开发(一)开发环境的搭建-CSDN博客
开源 java android app 开发(二)工程文件结构-CSDN博客
开源 java android app 开发(三)GUI界面布局和常用组件-CSDN博客
开源 java android app 开发(四)GUI界面重要组件-CSDN博客
开源 java android app 开发(五)文件和数据库存储-CSDN博客
开源 java android app 开发(六)多媒体使用-CSDN博客
开源 java android app 开发(七)通讯之Tcp和Http-CSDN博客
开源 java android app 开发(八)通讯之Mqtt和Ble-CSDN博客
开源 java android app 开发(九)后台之线程和服务-CSDN博客
开源 java android app 开发(十)广播机制-CSDN博客
开源 java android app 开发(十一)调试、发布-CSDN博客
开源 java android app 开发(十二)封库.aar-CSDN博客
推荐链接:
开源C# .net mvc 开发(一)WEB搭建_c#部署web程序-CSDN博客
开源 C# .net mvc 开发(二)网站快速搭建_c#网站开发-CSDN博客
开源 C# .net mvc 开发(三)WEB内外网访问(VS发布、IIS配置网站、花生壳外网穿刺访问)_c# mvc 域名下不可訪問內網,內網下可以訪問域名-CSDN博客
开源 C# .net mvc 开发(四)工程结构、页面提交以及显示_c#工程结构-CSDN博客
开源 C# .net mvc 开发(五)常用代码快速开发_c# mvc开发-CSDN博客
本章主要内容:实现了一个串口调试工具,参数可设,支持实时数据收发、格式转换、参数配置及通信过程监控等功能。可以广泛应用于工业控制、单片机开发、智能设备调试等场景,可通过调节波特率(110bps至256000bps)、校验方式等参数实现高速串口通讯。
一、代码分析
1.1 串口配置模块
// 串口参数配置
QComboBox *portComboBox; // 串口选择
QComboBox *baudComboBox; // 波特率选择(9600-115200)
QComboBox *stopBitsComboBox; // 停止位(1, 1.5, 2)
QComboBox *parityComboBox; // 校验位(无, 奇校验, 偶校验)
数据接收模块
cpp
QTextEdit *receiveEdit; // 接收数据显示区域
QCheckBox *hexDisplayCheckBox; // 16进制显示开关
数据发送模块
cpp
QTextEdit *sendEdit; // 发送数据输入区域
QCheckBox *hexSendCheckBox; // 16进制发送开关
1.2 核心功能实现分析
1. 串口管理
cpp
void MainWindow::onOpenButtonClicked()
{
// 实现串口的打开/关闭切换
// 配置串口参数:端口名、波特率、数据位、停止位、校验位
}
2. 数据发送处理
cpp
void MainWindow::onSendButtonClicked()
{
// 支持两种发送模式:
// - 文本模式:直接发送UTF-8文本
// - 16进制模式:将输入的16进制字符串转换为字节数据
// 包含数据验证:16进制数据长度校验、字符合法性检查
}
3. 数据接收处理
cpp
void MainWindow::onSerialReadyRead()
{
// 支持两种显示模式:
// - 文本模式:直接显示接收到的文本
// - 16进制模式:将字节数据转换为16进制字符串显示
// 自动滚动到底部功能
}
二、所有源码
2.1 mainwindow.h源码
#ifndef MAINWINDOW_H
#define MAINWINDOW_H#include <QMainWindow>
#include <QSerialPort>
#include <QSerialPortInfo>
#include <QComboBox>
#include <QTextEdit>
#include <QCheckBox>
#include <QPushButton>
#include <QLabel>
#include <QGroupBox>
#include <QVBoxLayout>class MainWindow : public QMainWindow
{Q_OBJECTpublic:MainWindow(QWidget *parent = nullptr);~MainWindow();private slots:void onOpenButtonClicked();void onRefreshButtonClicked();void onSendButtonClicked();void onSerialReadyRead();void onClearReceiveButtonClicked();void onClearSendButtonClicked();private:void createSerialConfigGroup();void createReceiveGroup();void createSendGroup();void initSerialPort();void refreshSerialPorts();void connectSignals();// 串口配置控件QComboBox *portComboBox;QComboBox *baudComboBox;QComboBox *stopBitsComboBox;QComboBox *parityComboBox;QPushButton *refreshButton;QPushButton *openButton;QLabel *statusLabel;// 接收区域控件QTextEdit *receiveEdit;QCheckBox *hexDisplayCheckBox;QPushButton *clearReceiveButton;// 发送区域控件QTextEdit *sendEdit;QCheckBox *hexSendCheckBox;QPushButton *clearSendButton;QPushButton *sendButton;// 串口对象QSerialPort *serialPort;// 布局和容器QWidget *centralWidget;QVBoxLayout *mainLayout;QGroupBox *configGroup;QGroupBox *receiveGroup;QGroupBox *sendGroup;
};#endif // MAINWINDOW_H
2.2 mainwindow.cpp源码
#include "mainwindow.h"
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QMessageBox>
#include <QScrollBar>MainWindow::MainWindow(QWidget *parent): QMainWindow(parent)
{// 设置窗口大小this->resize(1000, 600);this->setWindowTitle("QT串口调试助手");// 创建中央部件centralWidget = new QWidget(this);setCentralWidget(centralWidget);// 主布局mainLayout = new QVBoxLayout(centralWidget);// 创建各个功能区域createSerialConfigGroup();createReceiveGroup();createSendGroup();// 将各个区域添加到主布局mainLayout->addWidget(configGroup);mainLayout->addWidget(receiveGroup);mainLayout->addWidget(sendGroup);// 初始化串口initSerialPort();// 刷新可用串口refreshSerialPorts();// 连接信号槽connectSignals();
}MainWindow::~MainWindow()
{if(serialPort && serialPort->isOpen()){serialPort->close();}
}void MainWindow::createSerialConfigGroup()
{configGroup = new QGroupBox("串口配置");QHBoxLayout *configLayout = new QHBoxLayout(configGroup);// 串口选择QLabel *portLabel = new QLabel("串口:");portComboBox = new QComboBox();configLayout->addWidget(portLabel);configLayout->addWidget(portComboBox);// 波特率选择QLabel *baudLabel = new QLabel("波特率:");baudComboBox = new QComboBox();baudComboBox->addItems(QStringList() << "9600" << "19200" << "38400" << "57600" << "115200");baudComboBox->setCurrentText("115200");configLayout->addWidget(baudLabel);configLayout->addWidget(baudComboBox);// 停止位选择QLabel *stopBitsLabel = new QLabel("停止位:");stopBitsComboBox = new QComboBox();stopBitsComboBox->addItems(QStringList() << "1" << "1.5" << "2");configLayout->addWidget(stopBitsLabel);configLayout->addWidget(stopBitsComboBox);// 校验位选择QLabel *parityLabel = new QLabel("校验位:");parityComboBox = new QComboBox();parityComboBox->addItems(QStringList() << "无" << "奇校验" << "偶校验");configLayout->addWidget(parityLabel);configLayout->addWidget(parityComboBox);// 刷新按钮refreshButton = new QPushButton("刷新");configLayout->addWidget(refreshButton);// 打开/关闭按钮openButton = new QPushButton("打开串口");configLayout->addWidget(openButton);// 状态标签statusLabel = new QLabel("串口未打开");configLayout->addWidget(statusLabel);configLayout->addStretch();
}void MainWindow::createReceiveGroup()
{receiveGroup = new QGroupBox("接收数据");QVBoxLayout *receiveLayout = new QVBoxLayout(receiveGroup);// 接收文本框receiveEdit = new QTextEdit();receiveEdit->setReadOnly(true);receiveLayout->addWidget(receiveEdit);// 接收选项QHBoxLayout *receiveOptionsLayout = new QHBoxLayout();hexDisplayCheckBox = new QCheckBox("16进制显示");clearReceiveButton = new QPushButton("清空接收");receiveOptionsLayout->addWidget(hexDisplayCheckBox);receiveOptionsLayout->addWidget(clearReceiveButton);receiveOptionsLayout->addStretch();receiveLayout->addLayout(receiveOptionsLayout);
}void MainWindow::createSendGroup()
{sendGroup = new QGroupBox("发送数据");QVBoxLayout *sendLayout = new QVBoxLayout(sendGroup);// 发送文本框sendEdit = new QTextEdit();sendEdit->setMaximumHeight(100);sendLayout->addWidget(sendEdit);// 发送选项QHBoxLayout *sendOptionsLayout = new QHBoxLayout();hexSendCheckBox = new QCheckBox("16进制发送");clearSendButton = new QPushButton("清空发送");sendButton = new QPushButton("发送");sendOptionsLayout->addWidget(hexSendCheckBox);sendOptionsLayout->addWidget(clearSendButton);sendOptionsLayout->addWidget(sendButton);sendOptionsLayout->addStretch();sendLayout->addLayout(sendOptionsLayout);
}void MainWindow::initSerialPort()
{serialPort = new QSerialPort(this);
}void MainWindow::refreshSerialPorts()
{portComboBox->clear();QList<QSerialPortInfo> ports = QSerialPortInfo::availablePorts();for(const QSerialPortInfo &port : ports){portComboBox->addItem(port.portName());}
}void MainWindow::connectSignals()
{connect(openButton, &QPushButton::clicked, this, &MainWindow::onOpenButtonClicked);connect(refreshButton, &QPushButton::clicked, this, &MainWindow::onRefreshButtonClicked);connect(sendButton, &QPushButton::clicked, this, &MainWindow::onSendButtonClicked);connect(clearReceiveButton, &QPushButton::clicked, this, &MainWindow::onClearReceiveButtonClicked);connect(clearSendButton, &QPushButton::clicked, this, &MainWindow::onClearSendButtonClicked);connect(serialPort, &QSerialPort::readyRead, this, &MainWindow::onSerialReadyRead);
}void MainWindow::onOpenButtonClicked()
{if(serialPort->isOpen()){serialPort->close();openButton->setText("打开串口");statusLabel->setText("串口已关闭");}else{// 配置串口参数serialPort->setPortName(portComboBox->currentText());serialPort->setBaudRate(baudComboBox->currentText().toInt());// 设置数据位serialPort->setDataBits(QSerialPort::Data8);// 设置停止位QString stopBits = stopBitsComboBox->currentText();if(stopBits == "1") serialPort->setStopBits(QSerialPort::OneStop);else if(stopBits == "1.5") serialPort->setStopBits(QSerialPort::OneAndHalfStop);else if(stopBits == "2") serialPort->setStopBits(QSerialPort::TwoStop);// 设置校验位QString parity = parityComboBox->currentText();if(parity == "无") serialPort->setParity(QSerialPort::NoParity);else if(parity == "奇校验") serialPort->setParity(QSerialPort::OddParity);else if(parity == "偶校验") serialPort->setParity(QSerialPort::EvenParity);// 打开串口if(serialPort->open(QIODevice::ReadWrite)){openButton->setText("关闭串口");statusLabel->setText("串口已打开: " + portComboBox->currentText());}else{QMessageBox::critical(this, "错误", "无法打开串口: " + serialPort->errorString());}}
}void MainWindow::onRefreshButtonClicked()
{refreshSerialPorts();
}void MainWindow::onSendButtonClicked()
{if(!serialPort->isOpen()){QMessageBox::warning(this, "警告", "请先打开串口");return;}QString sendText = sendEdit->toPlainText();if(sendText.isEmpty()) return;QByteArray sendData;if(hexSendCheckBox->isChecked()){// 16进制发送sendText = sendText.trimmed();sendText.replace(" ", "");if(sendText.length() % 2 != 0){QMessageBox::warning(this, "警告", "16进制数据长度必须为偶数");return;}bool ok;for(int i = 0; i < sendText.length(); i += 2){QString byteStr = sendText.mid(i, 2);uint8_t byte = byteStr.toUShort(&ok, 16);if(!ok){QMessageBox::warning(this, "警告", "包含非法的16进制字符");return;}sendData.append(byte);}}else{// 文本发送sendData = sendText.toUtf8();}// 发送数据serialPort->write(sendData);
}void MainWindow::onSerialReadyRead()
{QByteArray data = serialPort->readAll();if(hexDisplayCheckBox->isChecked()){// 16进制显示QString hexData;for(int i = 0; i < data.size(); i++){hexData += QString("%1 ").arg((uint8_t)data[i], 2, 16, QLatin1Char('0')).toUpper();}receiveEdit->insertPlainText(hexData);}else{// 文本显示QString text = QString::fromUtf8(data);receiveEdit->insertPlainText(text);}// 自动滚动到底部QScrollBar *scrollbar = receiveEdit->verticalScrollBar();scrollbar->setValue(scrollbar->maximum());
}void MainWindow::onClearReceiveButtonClicked()
{receiveEdit->clear();
}void MainWindow::onClearSendButtonClicked()
{sendEdit->clear();
}
2.3 .prog工程文件
QT += core gui
QT += core gui serialport widgets
greaterThan(QT_MAJOR_VERSION, 4): QT += widgetsCONFIG += c++11# The following define makes your compiler emit warnings if you use
# any Qt feature that has been marked deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS# You can also make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0SOURCES += \main.cpp \mainwindow.cppHEADERS += \mainwindow.hFORMS += \mainwindow.ui# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target
三、显示效果