目录
一、前言
二、环境准备
三、创建QT串口项目
编辑 四、串口项目实现
1.ui界面设计
2.添加QT串口模块
3.功能实现
①串口扫描
②波特率、停止位等设置
③接收数据
④发送数据
五、最终效果
六、总结
一、前言
如果有人之前看过我文章的话应该知道,我之前用python+pyqt5写过一版串口助手。没看过的也不要紧,我贴在下面,大家可以浅浅看一下。最近由于工作需要,开始接触C++以及QT,就想着能不能用C++和QT重写一下串口助手。于是就有了这篇文章单纯记录一下,接下来听我娓娓道来~
基于Python+Pycharm+PyQt5的串口助手开发_基于python+pyqt5的串口助手-CSDN博客文章浏览阅读2.3k次,点赞43次,收藏30次。本期带来的基于PyQt5的串口助手开发,实现串口通信。_基于python+pyqt5的串口助手https://blog.csdn.net/weixin_44765053/article/details/135347552?spm=1001.2014.3001.5502
二、环境准备
操作系统:win 10
编辑器:VS2022、QT5.14
语言及版本:C++
最终实现的功能:串口选择、串口状态显示、发送数据、接收数据、数据显示(ASCII)
首先假设你已经安装好了VS以及QT(如果不清楚的比较多的话麻烦评论区留言,后续我出一篇文章详细介绍),那么如何在VS里面新建QT项目并编写代码呢?我们需要安装Qt VS Tools插件。
①打开Visual Studio点击右上角的扩展,然后点击管理扩展。
②搜索并安装"Qt Visual Studio Tools"插件,然后重启Visual Studio。
③重启后依次点击,扩展-->Qt VS Tools-->Qt Versions ④点击path,选择你QT安装时候编译路径,即qmake.exe所在的目录。例如我这边显示D:\QT\5.14.0\msvc2017_64,但其实qmake.exe是在bin文件下面
三、创建QT串口项目
①打开VS中,选择创建新项目。在搜索框输入Qt Widget Application,选择Qt Widget Application点击下一步。
② 修改项目名称以及项目位置,然后点击创建。
③一直点击默认的next直至以下界面,我们选择QWidget。
四、串口项目实现
1.ui界面设计
在右侧点击Form Files,然后双击ui文件进行界面设计。这里我们就偷个小懒,直接沿用pyqt项目的ui界面。
PS:如果这里出现无法打开ui文件的,可以《扩展》-> 《Qt vs tools》-> 《options》-> 《Qt》-> 《general》 -> 《Qt Designer》 -> 《run in detached window》 -> true
2.添加QT串口模块
在Qt中,串口通信的核心是QSerialPort
和QSerialPortInfo
这两个类。
-
QSerialPort:这个类提供了与串口进行通信的功能。它可以用于打开、关闭串口,设置串口的参数如波特率、数据位、停止位等,还可以通过这个类发送和接收数据。
QSerialPort
是串口助手中最关键的类,它让我们能够轻松地与硬件进行数据通信。 -
QSerialPortInfo:这个类用于提供系统中可用的串口信息。通过它,我们可以获取到当前系统中所有可用串口的名称、描述信息等。它主要用于列出可用串口供用户选择。
但是当我们直接#include <QSerialPort>、#include <QSerialPortInfo>时候会报错,需要将其添加到Qt Modules。依次点击,项目-->serial和属性-->Qt Project Settings-->Qt Modules-->添加serial port。
3.功能实现
主要功能包括:
- 串口扫描:定时每秒扫描现存串口列表,并将其添加到ComboBox。
- 波特率设置:提供一个下拉列表,用户可以选择常用的波特率。
- 数据接收:接收数据,并以十六进制显示。
- 数据发送:包括十六进制发送、定时发送数据等待。
①串口扫描
#include "serial2.h"
SerialPortScanner::SerialPortScanner(QComboBox* comboBox) // 构造函数,传入一个QComboBox指针作为参数
: m_comboBox(comboBox), m_timer(new QTimer(this)) // 初始化成员变量m_comboBox, m_timer
{
// 创建一个定时器,每1000毫秒(1秒)触发一次
connect(m_timer, &QTimer::timeout, this, &SerialPortScanner::scanSerialPorts); // 连接定时器的超时信号和scanSerialPorts槽函数
m_timer->start(1000); // 启动定时器
}
void SerialPortScanner::scanSerialPorts()
{
QList<QString> m_newports; // 新的串口列表
// 获取可用的串口列表
QList<QSerialPortInfo> portList = QSerialPortInfo::availablePorts();
// 遍历串口列表,将每个串口的名称添加到QComboBox中
for (const QSerialPortInfo& portInfo : portList) {
m_newports.append(portInfo.portName()); // 将串口名称添加到列表中
}
if (m_newports != m_portNames) {
m_portNames = m_newports; // 更新旧的串口列表
m_comboBox->clear(); // 清空QComboBox
m_comboBox->addItems(m_portNames); // 将新的串口列表添加到QComboBox中
}
}
效果如下:
②波特率、停止位等设置
#include "serial2.h"
SerialPortSet::SerialPortSet(Ui::serial2Class* ui, QObject* parent) // 构造函数
: QObject(parent),
serialPort(new QSerialPort(this)),
m_ui(ui)
{
}
// 获取波特率
QSerialPort::BaudRate SerialPortSet::getBaudRate(const QString& baudRateStr) {
static const QMap<QString, QSerialPort::BaudRate> baudRateMap = {
{"1200", QSerialPort::Baud1200}, // 1200
{"2400", QSerialPort::Baud2400}, // 2400
{"4800", QSerialPort::Baud4800}, // 4800
{"9600", QSerialPort::Baud9600}, // 9600
{"19200", QSerialPort::Baud19200}, // 19200
{"38400", QSerialPort::Baud38400}, // 38400
};
return baudRateMap.value(baudRateStr, QSerialPort::Baud9600); // 返回对应的波特率
}
// 获取数据位
QSerialPort::DataBits SerialPortSet::getDataBits(const QString& dataBitsStr) {
static const QMap<QString, QSerialPort::DataBits> dataBitsMap = {
{"5", QSerialPort::Data5}, // 5
{"6", QSerialPort::Data6}, // 6
{"7", QSerialPort::Data7}, // 7
{"8", QSerialPort::Data8} // 8
};
return dataBitsMap.value(dataBitsStr, QSerialPort::Data8); // 返回对应的数据位
}
// 获取停止位
QSerialPort::StopBits SerialPortSet::getStopBits(const QString& stopBitsStr) {
static const QMap<QString, QSerialPort::StopBits> stopBitsMap = {
{"1", QSerialPort::OneStop}, // 1
{"1.5", QSerialPort::OneAndHalfStop}, // 1.5
{"2", QSerialPort::TwoStop} // 2
};
return stopBitsMap.value(stopBitsStr, QSerialPort::OneStop); // 返回对应的停止位
}
// 获取奇偶校验位
QSerialPort::Parity SerialPortSet::getParityBits(const QString& parityStr) {
static const QMap<QString, QSerialPort::Parity> parityMap = {
{"NONE", QSerialPort::NoParity}, // 无
{"ODD", QSerialPort::OddParity}, // 奇
{"EVEN", QSerialPort::EvenParity} // 偶
};
return parityMap.value(parityStr, QSerialPort::NoParity); // 返回对应的奇偶校验位
}
void SerialPortSet::open_Port()
{
// 获取各项设置
QSerialPort::BaudRate baudRate = getBaudRate(m_ui->comboBox_Baud->currentText()); // 获取波特率
QSerialPort::DataBits dataBits = getDataBits(m_ui->comboBox_Data->currentText()); // 获取数据位
QSerialPort::StopBits stopBits = getStopBits(m_ui->comboBox_Stop->currentText()); // 获取停止位
QSerialPort::Parity parity = getParityBits(m_ui->comboBox_Check->currentText()); // 获取校验位
// 设置串口参数
serialPort->setPortName(m_ui->comboBox_COM->currentText()); // 设置串口名称
serialPort->setBaudRate(baudRate); // 设置波特率
serialPort->setDataBits(dataBits); // 设置数据位
serialPort->setStopBits(stopBits); // 设置停止位
serialPort->setParity(parity); // 设置校验位
if (serialPort->open(QIODevice::ReadWrite)) { // 尝试打开串口
m_ui->pushButton_Open->setText("关闭串口"); // 更新按钮文本
}
else {
// 如果无法打开串口,弹出错误信息
QMessageBox::warning(m_ui->label, "错误", "无法打开串口: " + serialPort->errorString()); // 弹出警告框
}
}
}
效果如下:
③接收数据
void SerialPortCommunication::readData() // 当有数据可读时,读取数据
{
if (m_serialPort->isOpen())
{ // 如果串口打开,则读取数据
QByteArray data = m_serialPort->readAll(); // 读取数据
m_ui->textEdit_receive->insertPlainText(QString::fromUtf8(data)); // 将数据插入到文本框中
}
m_ui->textEdit_receive->moveCursor(QTextCursor::End);
}
④发送数据
void SerialPortCommunication::sendData() // 发送数据函数
{
QString inputData = m_ui->textEdit_Send->toPlainText(); // 获取发送数据
if (m_serialPort->isOpen() && !inputData.isEmpty()) { // 如果串口打开且发送数据不为空,则发送数据
QByteArray byteArray; // 创建字节数组
byteArray = inputData.toUtf8();
m_serialPort->write(byteArray); // 发送数据
}
由于篇幅有限,以上只贴了主要功能实现代码。
五、最终效果
老样子,我们来看看最终与其他串口通信效果。
QT串口助手
六、总结
通过本文的详细讲解,我们完成了一个基于VS2022和Qt5的串口助手的开发。该串口助手实现了串口扫描、开关串口、数据接收和数据发送等核心功能,能够帮助用户方便地与串口设备进行通信和调试。
在开发过程中,我们深入了解了QSerialPort
和QSerialPortInfo
类的应用,通过它们轻松实现了串口的操作和管理。同时,本文还详细介绍了如何在Qt中设计用户界面,使我们的工具不仅功能完善,而且使用起来简洁直观。
希望通过这篇文章,你能够更好地掌握Qt开发与串口通信相关的知识,并将这些技能应用到实际项目中。如果你在开发过程中遇到任何问题,欢迎在评论区交流讨论。