一、串口简介
二、Qt编写串口助手
1、创建Qt工程
选择MinGW 64-bit
点击下一步完成,工程创建完成。
使用串口模块,需要在工程文件.pro中添加以下代码,不添加的话,会报错。
或者在core gui 后输入 serialport 也可以
2、配置UI界面
双击打开带.ui后缀的文件
可以在右边设置窗口的大小(宽和高)
创建一个Widget界面,用于放置控件
下面框选的就是Wiget界面,可以看出里面有很多控件,这样可以方便我们控件布局
做一个串口助手,需要有接收和发送功能,这里接收功能使用接收控件实现.
选择接收控件(Plain Text Edit),拖到UI界面中。
因为接受数据是只读的,我们需要把这个控件的属性设置为只读。在右下角属性栏勾选readOnly。
设置串口号、波特率、停止位、数据位、校验位需要下拉框,所以在左边找到Combo Box,添加到UI界面中。
使用标签 Label控件作注释
使用Line Edit作为发送控件,也就是发送数据的框
打开串口(关闭串口)、发送数据、清除接受等需要使用Push Button作为点击控件
通过以上的配置,一个基础的串口调试助手就完成了
除此之外,还可以加入复选框,使用的是Check Box控件
最终配置UI界面如下
工程文件
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QSerialPortInfo> //提供系统中存在的串口的信息
#include <QMessageBox>
#include <QFileDialog>
#include <QStandardPaths>
#include <QFile>
#include <QDebug>
#include <QTimer>
MainWindow::MainWindow(QWidget *parent)
: QWidget(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
initPort();
// 默认显示文本数据
dispalyText();
// 将复选框的 toggled(bool) 信号连接到槽函数
connect(ui->hexDisplayChex, &QCheckBox::toggled, this, &MainWindow::on_hexDisplayChex_toggled);
}
MainWindow::~MainWindow()
{
delete ui;
}
/****************************串口初始化******************************/
void MainWindow::initPort()
{
//设置改变
connect(ui->baudRateCmb, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
this, [=]
{
auto br = ui->baudRateCmb->currentData().value<QSerialPort::BaudRate>();
if (!serialPort_.setBaudRate(br))
{
QMessageBox::warning(this, "false", "设置波特率失败:" + serialPort_.errorString());
}
});
connect(ui->dataBitsCmb,static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged),this,[=]
{
auto value = ui->dataBitsCmb->currentData().value<QSerialPort::DataBits>();
if(!serialPort_.setDataBits(value))
{
QMessageBox::warning(this,"false","设置数据位失败:"+serialPort_.errorString());
}
});
connect(ui->stopBitCmb,static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged),this,[=]
{
auto value = ui->stopBitCmb->currentData().value<QSerialPort::StopBits>();
if(!serialPort_.setStopBits(value))
{
QMessageBox::warning(this,"false","设置停止位失败:"+serialPort_.errorString());
}
});
connect(ui->parityCmb,static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged),this,[=]
{
auto value = ui->parityCmb->currentData().value<QSerialPort::Parity>();
if(!serialPort_.setParity(value))
{
QMessageBox::warning(this,"false","设置校验位失败:"+serialPort_.errorString());
}
});
//获取所有可用的串口
auto portsInfo = QSerialPortInfo::availablePorts();
for (auto& info : portsInfo)
{
qInfo() << info.description() << info.portName() << info.systemLocation();
ui->portsCmb->addItem(info.portName() + ":" + info.description(),info.portName());
}
//获取标准的波特率
auto baudRates = QSerialPortInfo::standardBaudRates();
for(auto br : baudRates)
{
ui->baudRateCmb->addItem(QString::number(br),br);//遍历设置波特率
}
//设置默认的波特率
ui->baudRateCmb->setCurrentText("9600");
//设置停止位
ui->stopBitCmb->addItem("1",QSerialPort::OneStop);
ui->stopBitCmb->addItem("1.5",QSerialPort::OneAndHalfStop);
ui->stopBitCmb->addItem("2",QSerialPort::TwoStop);
//设置数据位
ui->dataBitsCmb->addItem("5",QSerialPort::Data5);
ui->dataBitsCmb->addItem("6",QSerialPort::Data6);
ui->dataBitsCmb->addItem("7",QSerialPort::Data7);
ui->dataBitsCmb->addItem("8",QSerialPort::Data8);
ui->dataBitsCmb->setCurrentText("8");
//设置校验位
ui->parityCmb->addItem("NoParity ",QSerialPort::NoParity ); //按住ALT多行编辑
ui->parityCmb->addItem("EvenParity ",QSerialPort::EvenParity );
ui->parityCmb->addItem("OddParity ",QSerialPort::OddParity );
ui->parityCmb->addItem("SpaceParity",QSerialPort::SpaceParity);
ui->parityCmb->addItem("MarkParity ",QSerialPort::MarkParity );
connect(&serialPort_,&QSerialPort::readyRead,this,&MainWindow::onReadyRead);
timer_.callOnTimeout([=]
{
this->on_sendBtn_released();
});
// //读取串口信息
// foreach (const QSerialPortInfo &info, QSerialPortInfo::availablePorts())
// {
// qDebug()<<"Name:"<<info.portName();
// qDebug()<<"Description:"<<info.description();
// qDebug()<<"Manufacturer:"<<info.manufacturer();
// //这里相当于自动识别串口号之后添加到了cmb,如果要手动选择可以用下面列表的方式添加进去
// QSerialPort serial;
// serial.setPort(info);
// if(serial.open(QIODevice::ReadWrite))
// {
// //将串口号添加到cmb
// ui->portsCmb->addItem(info.portName());
// //关闭串口等待人为(打开串口按钮)打开
// serial.close();
// }
// }
// QStringList baudList;//波特率
// QStringList parityList;//校验位
// QStringList dataBitsList;//数据位
// QStringList stopBitsList;//停止位
// baudList<<"50"<<"75"<<"100"<<"134"<<"150"<<"200"<<"300"
// <<"600"<<"1200"<<"1800"<<"2400"<<"4800"<<"9600"
// <<"14400"<<"19200"<<"38400"<<"56000"<<"57600"
// <<"76800"<<"115200"<<"128000"<<"256000";
// ui->baudRateCmb->addItems(baudList);
// ui->baudRateCmb->setCurrentIndex(12);
// parityList<<"无"<<"奇"<<"偶";
// parityList<<"标志";
// parityList<<"空格";
// ui->parityCmb->addItems(parityList);
// ui->parityCmb->setCurrentIndex(0);
// dataBitsList<<"5"<<"6"<<"7"<<"8";
// ui->dataBitsCmb->addItems(dataBitsList);
// ui->dataBitsCmb->setCurrentIndex(3);
// stopBitsList<<"1";
// stopBitsList<<"1.5";
// stopBitsList<<"2";
// ui->stopBitCmb->addItems(stopBitsList);
// ui->stopBitCmb->setCurrentIndex(0);
// //设置按钮可以被按下
// ui->openPortBtn->setCheckable(true);
}
/****************************串口设置******************************/
void MainWindow::on_openPortBtn_released()
{
//串口是否已经打开
if(serialPort_.isOpen())
{
serialPort_.close();
ui->openPortBtn->setText("打开串口");
if(timer_.isActive())
{
timer_.stop();
}
return;
}
//获取串口
auto portName = ui->portsCmb->currentData().toString();
// //获取波特率
// auto baudRate = ui->baudRateCmb->currentData().value<QSerialPort::BaudRate>();
// //获取数据位
// auto dataBits = ui->dataBitsCmb->currentData().value<QSerialPort::DataBits>();
// //获取停止位
// auto stopBits = ui->stopBitCmb->currentData().value<QSerialPort::StopBits>();
// //获取校验位
// auto parity = ui->parityCmb->currentData().value<QSerialPort::Parity>();
serialPort_.setPortName(portName);
// serialPort_.setBaudRate(baudRate);
// serialPort_.setDataBits(dataBits);
// serialPort_.setStopBits(stopBits);
// serialPort_.setParity(parity);
//打开串口
if(!serialPort_.open(QIODevice::ReadWrite))
{
QMessageBox::warning(this,"warning",portName + "open failaed:" + serialPort_.errorString());
return;
}
else
{
ui->openPortBtn->setText("关闭串口");
}
}
//发送数据
void MainWindow::on_sendBtn_released()
{
auto dataStr = ui->sendEdit->toPlainText() + (ui->sendNewLineChx->isChecked() ?"\r\n":"");//+ ui->sendNewLineChx->isChecked() ?"\r\n":""
serialPort_.write(dataStr.toLocal8Bit());
}
//接收函数
void MainWindow::onReadyRead()
{
// auto data = serialPort_.readAll();
// ui->recvEdit->setPlainText(QString::fromLocal8Bit(data));
QByteArray data = serialPort_.readAll();
QString receivedData = QString::fromLocal8Bit(data); // 使用正确的编码解析数据
processReceivedData(receivedData);
}
//接收处理函数
void MainWindow::processReceivedData(const QString& data)
{
if (ui->hexDisplayChex->isChecked()) {
// 如果复选框已勾选,将接收到的数据转换为十六进制并显示
QString hexData = data.toLocal8Bit().toHex(' ').toUpper();
ui->recvEdit->appendPlainText(hexData);
} else {
// 如果复选框未勾选,显示接收到的数据文本
ui->recvEdit->appendPlainText(data);
}
}
//打开文件
void MainWindow::on_openfileBtn_released()
{
auto filename = QFileDialog::getOpenFileName(this,"选择文件",QStandardPaths::writableLocation(QStandardPaths::DesktopLocation),
"txt(*.txt);;all(*.*)");
if(!filename.isEmpty())
{
ui->fileNameEdit->setText(filename);
}
}
//发送文件
void MainWindow::on_sendfileBtn_released()
{
auto filename = ui->fileNameEdit->text();
QFile file(filename);
if(!file.open(QIODevice::ReadOnly))
{
QMessageBox::warning(this,"warning",filename + "open failed:" + file.errorString());
return;
}
//最好判断一下文件的编码
serialPort_.write(QString::fromUtf8(file.readAll()).toLocal8Bit());
}
//显示十六进制或者十进制
void MainWindow::on_hexDisplayChex_toggled(bool checked)
{
if (checked) {
// 如果复选框被选中,显示接收数据的十六进制格式
dispalyHex();
} else {
// 如果复选框未选中,显示接收数据的文本格式
dispalyText();
}
}
void MainWindow::dispalyHex()
{
QString currentText = ui->recvEdit->toPlainText();
QString hexData = currentText.toLocal8Bit().toHex(' ').toUpper();
ui->recvEdit->setPlainText(hexData);
}
void MainWindow::dispalyText()
{
QString currentText = ui->recvEdit->toPlainText();
ui->recvEdit->setPlainText(currentText);
}
//十六进制显示
//void MainWindow::on_hexDisplayChex_toggled(bool checked)
//{
// if(checked)
// dispalyHex();
// else
// dispalyText();
//}
//void MainWindow::dispalyHex()
//{
// //先把数据拿出来
// auto dataStr = ui->recvEdit->toPlainText();
// //转成十六进制
// auto hexData = dataStr.toLocal8Bit().toHex(' ').toUpper();//添加间隔符' '
// //写回去
// ui->recvEdit->setPlainText(hexData);
//}
//void MainWindow::dispalyText()
//{
// //先把数据拿出来
// auto dataStr = ui->recvEdit->toPlainText();
// //转成文本
// auto textData =QString::fromLocal8Bit(dataStr.toLocal8Bit());
// //写回去
// ui->recvEdit->setPlainText(textData);
//}
void MainWindow::on_timerSendChx_toggled(bool checked)
{
if(checked)
{
timer_.start(ui->timerperiodEdit->text().toUInt());
ui->timerperiodEdit->setEnabled(false);
}
else
{
timer_.stop();
}
}
void MainWindow::on_sendstopBtn_released()
{
serialPort_.clear();
if(timer_.isActive())
timer_.stop();
}
//清空槽函数
void MainWindow::on_clearRecvBtn_clicked()
{
ui->recvEdit->clear();
}
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QWidget>
#include <QTimer>
#include <QSerialPort> //提供访问串口的功能
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QWidget
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
void initPort(); //Alt+回车快捷键
private slots:
void on_openPortBtn_released();
void on_sendBtn_released();
void onReadyRead();
void on_openfileBtn_released();
void on_sendfileBtn_released();
void on_hexDisplayChex_toggled(bool checked);
void on_timerSendChx_toggled(bool checked);
void on_sendstopBtn_released();
void on_clearRecvBtn_clicked();
// void toggleHexDisplay(int state);
void processReceivedData(const QString& data);
private:
void dispalyHex();
void dispalyText();
Ui::MainWindow *ui;
QSerialPort serialPort_;
QTimer timer_;
};
#endif // MAINWINDOW_H