一、前言
串口通信作为嵌入式开发和硬件调试的重要工具,在工业控制、物联网等领域广泛应用。本文将手把手教你使用QT框架实现一个跨平台的串口调试助手,支持Windows/Linux/macOS系统。
使用版本为Qt 6以上版本
二、效果
三、界面
控件
四、项目引用
在 .pro 文件中添加模块依赖:
QT += serialport
五、头文件声明
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QSerialPort>
#include <QSerialPortInfo>
QT_BEGIN_NAMESPACE
namespace Ui {
class MainWindow;
}
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private slots:
void on_btnRefreshSerialPort_clicked();
void initUiData();
void on_btnOpen_clicked();
void initSerialPort(QSerialPort *serialPort,QString name,int baudRate,int dataBit,QString parity,int stopBit);
void on_btnSend_clicked();
void receiveData();
void controlEnable(bool isEnable);
void on_btnClear_clicked();
void on_btnSendClear_clicked();
private:
Ui::MainWindow *ui;
QList<QString> BaudRateList;
QList<int> DataBitList;
QList<QString> ParityList;
QList<int> StopBitList;
QSerialPort serialPort;
};
#endif // MAINWINDOW_H
六、Cpp代码
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QMessageBox>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
initUiData();
}
MainWindow::~MainWindow()
{
delete ui;
}
//刷新串口
void MainWindow::on_btnRefreshSerialPort_clicked()
{
ui->cboSerialPort->clear();
QList<QSerialPortInfo> serialPostList = QSerialPortInfo::availablePorts();
foreach(const QSerialPortInfo &info,serialPostList)
{
ui->cboSerialPort->addItem(info.portName());//添加串口名称
}
}
void MainWindow::initUiData()
{
on_btnRefreshSerialPort_clicked();
BaudRateList.append("1200");
BaudRateList.append("2400");
BaudRateList.append("4800");
BaudRateList.append("9600");
BaudRateList.append("19200");
BaudRateList.append("38400");
BaudRateList.append("57600");
BaudRateList.append("115200");
DataBitList.append(5);
DataBitList.append(6);
DataBitList.append(7);
DataBitList.append(8);
ParityList.append("无");
ParityList.append("奇校验");
ParityList.append("偶校验");
StopBitList.append(1);
StopBitList.append(2);
foreach (auto item, BaudRateList) {
ui->cboBaudRate->addItem(item);
}
ui->cboBaudRate->setCurrentText("9600");
foreach (auto item, DataBitList) {
ui->cboDataBits->addItem(QString::number(item));
}
ui->cboDataBits->setCurrentText("8");
foreach (auto item, ParityList) {
ui->cboParityBit->addItem(item);
}
ui->cboParityBit->setCurrentText("无");
foreach (auto item, StopBitList) {
ui->cboStopBit->addItem(QString::number(item));
}
ui->cboStopBit->setCurrentText("1");
}
//打开串口
void MainWindow::on_btnOpen_clicked()
{
if(serialPort.isOpen())
{
//关闭串口
serialPort.close();
ui->lbStatus->setText("未打开");
ui->btnOpen->setText("打开串口");
controlEnable(true);
disconnect(&serialPort,&QSerialPort::readyRead,this,&MainWindow::receiveData);
}
else
{
//打开串口
auto name = ui->cboSerialPort->currentText();
int baudRate = ui->cboBaudRate->currentText().toInt();
int dataBit = ui->cboDataBits->currentText().toInt();
auto parity = ui->cboParityBit->currentText();
int stopBit = ui->cboStopBit->currentText().toInt();
initSerialPort(&serialPort,name,baudRate,dataBit,parity,stopBit);
bool isOk = serialPort.open(QIODevice::ReadWrite);
if(isOk)
{
//接收数据
connect(&serialPort,&QSerialPort::readyRead,this,&MainWindow::receiveData);
ui->lbStatus->setText("打开成功");
ui->btnOpen->setText("关闭串口");
controlEnable(false);
}
else
{
ui->lbStatus->setText("打开失败");
}
}
}
void MainWindow::initSerialPort(QSerialPort *serialPort,QString name,int baudRate,int dataBit,QString parity,int stopBit)
{
serialPort->setPortName(name);
serialPort->setBaudRate(baudRate);
switch(dataBit)
{
case 5:
serialPort->setDataBits(QSerialPort::Data5);
break;
case 6:
serialPort->setDataBits(QSerialPort::Data6);
break;
case 7:
serialPort->setDataBits(QSerialPort::Data7);
break;
case 8:
serialPort->setDataBits(QSerialPort::Data8);
break;
}
if(parity == "无")
{
serialPort->setParity(QSerialPort::NoParity);
}
else if(parity == "奇校验")
{
serialPort->setParity(QSerialPort::OddParity);
}
else if(parity == "偶校验")
{
serialPort->setParity(QSerialPort::EvenParity);
}
if(stopBit == 1)
{
serialPort->setStopBits(QSerialPort::OneStop);
}
else if(stopBit == 1)
{
serialPort->setStopBits(QSerialPort::TwoStop);
}
serialPort->setFlowControl(QSerialPort::NoFlowControl); // 设置流控
}
//发送 按钮
void MainWindow::on_btnSend_clicked()
{
if(serialPort.isOpen() == true)
{
auto data = ui->txtInputData->toPlainText();
if(data.length() > 0)
{
if(ui->chkAddEndMark->checkState() == Qt::Checked)
{
data += "\r\n";
}
//将字符串转为QByteArray
if(ui->chkHexSend->checkState() == Qt::Checked)
{
//16进制发送
QByteArray byteArray = QByteArray::fromHex(data.toUtf8());
serialPort.write(byteArray);
}
else
{
serialPort.write(data.toUtf8());
}
ui->textBrowser->append("<font color='green'>发送:"+data.toUtf8());
}
else
{
QMessageBox::information(this,"系统提示","发送内容不能为空!");
}
}
else
{
QMessageBox::information(this,"系统提示","串口未打开,请先打开串口!");
}
}
void MainWindow::receiveData()
{
QByteArray receiveData = serialPort.readAll();
if(ui->chkHexReceive->checkState() == Qt::Checked)
{
QString hexData = receiveData.toHex(' '); // 将字节数组转换为16进制字符串,每个字节之间有空格分隔
ui->textBrowser->append("<font color='blue'>接收:"+hexData);
}
else
{
ui->textBrowser->append("<font color='blue'>接收:"+QString(receiveData));
}
}
void MainWindow::controlEnable(bool isEnable)
{
ui->cboSerialPort->setEnabled(isEnable);
ui->cboBaudRate->setEnabled(isEnable);
ui->cboDataBits->setEnabled(isEnable);
ui->cboParityBit->setEnabled(isEnable);
ui->cboStopBit->setEnabled(isEnable);
}
void MainWindow::on_btnClear_clicked()
{
ui->textBrowser->clear();
}
void MainWindow::on_btnSendClear_clicked()
{
ui->txtInputData->clear();
}