qt实现串口调试助手

最近在学习qt,于是打算搞一个串口调试助手,初学C++和QT,有理解错误希望能给出意见。

总结归纳

2023.09.22:能够显示串口数据

2023.09.25:增加按钮打开以及之前没注意到的异常处理

2023.09.27:知识补充串口编程Qt Serial Port

2023.09.27:通过所学修改波特率和com口

2023.09.28:增加发送串口数据

1、显示串口数据

创建qt widget工程,ui界面就一个控件QTextEdit,名称为Serial_Display

因为功能比较简单,只需要显示串口数据即可。首先肯定是整体的初始化,需要在.pro文件中添加QT       += serialport。包含两个头文件<QtSerialPort/QSerialPort>和<QtSerialPort/QSerialPortInfo>。接下来就是串口初始化配置

QSerialPort *serialPort = new QSerialPort(this);

serialPort->setPortName("COM6");  // 替换为你的串口名称
serialPort->setBaudRate(QSerialPort::Baud115200);
serialPort->setParity(QSerialPort::NoParity);
serialPort->setDataBits(QSerialPort::Data8);
serialPort->setStopBits(QSerialPort::OneStop);
serialPort->setFlowControl(QSerialPort::NoFlowControl);
serialPort->open(QIODevice::ReadOnly); // 仅读

这一步有点像单片机的配置模块,嫌麻烦所以直接在widget中的共有变量中声明了QSerialPort。然后是读取数据函数

void Widget::readSerialData()
{
    QByteArray data = serialPort->readAll();                // 读取串口数据
    ui->Serial_Display->append(QString::fromUtf8(data));   // 在QTextEdit控件中显示数据
}

这里有一个问题就是readSerialData定义成了槽函数,而串口读取就相当于一个信号,信号与槽好像是qt的核心。我的理解就是信号是触发,槽函数是一个动作,所以读串口触发了文本写入,也就是readSerialData函数。

connect(serialPort, &QSerialPort::readyRead, this, &Widget::readSerialData);

所以整体的代码为:

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    ///连接信号与槽
    connect(serialPort, &QSerialPort::readyRead, this, &Widget::readSerialData);

    ///端口处理
    serialPort->setPortName("COM6");  // 替换为你的串口名称
    serialPort->setBaudRate(QSerialPort::Baud115200);
    serialPort->setParity(QSerialPort::NoParity);
    serialPort->setDataBits(QSerialPort::Data8);
    serialPort->setStopBits(QSerialPort::OneStop);
    serialPort->setFlowControl(QSerialPort::NoFlowControl);
    serialPort->open(QIODevice::ReadOnly); // 仅读
}

void Widget::readSerialData()
{
    QByteArray data = serialPort->readAll();                // 读取串口数据
    ui->Serial_Display->append(QString::fromUtf8(data));   // 在QTextEdit控件中显示数据
}

这里有个问题,串口确实接收到了数据,但是都是乱码,QByteArray读取的是串口字节,而ui->Serial_Display->append是QString类型,所以可以将data转换成十六进制。

void Widget::readSerialData()
{
    QByteArray data = 0;
    QString hexString = 0;

    data = serialPort->readAll(); // 读取串口字节
    hexString = data.toHex();        // 将字节数组转换为十六进制字符串

    ui->Serial_Display->append(hexString);   // 在QTextEdit控件中显示数据
}

2、增加按钮打开以及之前没注意到的异常处理

在ui界面增加一个QComboBox界面,也就是下拉框,用来扫描所有端口然后增加两个QPushButton,一个用来打开串口,另一个用来关闭串口。

这里有一点就是波特率需要能够自主选择,这里可以双击波特率的下拉框,然后在编辑组合框中添加需要的串口波特率。

接下来就是端口扫描

    // 端口扫描
#if Serial_Scan
    foreach (const QSerialPortInfo &inf0, QSerialPortInfo::availablePorts())
    {
        serialNamePort << inf0.portName(); // 端口名称
    }
    ui->serialBox->addItems(serialNamePort);    // 把扫描到的端口放入BOX中
#endif

这里的ui->serialBox,表示选中了画的ui界面中的serialBox,之前的串口下拉框的名称就是这个,这个可以自己定义。

这段代码的解释:这段代码是用C++编写的。其中,'foreach'是一个循环结构,用于遍历集合中的每个元素。'QSerialPortInfo::availablePorts()'是Qt框架中QSerialPortInfo类的一个静态方法,它返回一个包含所有可用串口信息的QList对象。'inf0'是遍历过程中每个QSerialPortInfo对象的引用。'portName()'方法返回串口的名称。'serialNamePort'可能是一个QStringList对象,用于存储所有可用串口的名称。最后,'ui->serialBox->addItems(serialNamePort)'将所有可用的串口名称添加到名为'serialBox'的QComboBox控件中。没错,是搜的文心一言的解释!!!!!

那么串口的设置,尤其是串口号和串口波特率就需要进行相关的更改

    /* 串口设置 */
#if Serial_Set
    serialport->setPortName(ui->serialBox->currentText());           // 串口下拉框当前数据
    serialport->setBaudRate(ui->baudrateBox->currentText().toInt()); // 设置为波特率下拉框中的当前数据
    serialport->setDataBits(QSerialPort::Data8);                     // 默认8位数据
    serialport->setStopBits(QSerialPort::OneStop);                   // 默认一位停止位
    serialport->setParity(QSerialPort::NoParity);                    // 默认没有奇偶校验位
    serialport->setFlowControl(QSerialPort::NoFlowControl);          // 没有流控制
#endif

接着就是串口打开操作,在打开串口的槽函数中(右击打开串口转到槽,选中clicked())

打开串口有两个注意点,一个是就是普通的打开串口,第二是如果已经打开串口就需要提示串口已打开。

void Widget::on_openButton_clicked(void)
{
    // 串口打开提示
#if Serial_Warning
    if (serialport->open(QIODevice::ReadWrite))     // 打开串口
    {
        // information函数表示普通的提示功能
        QMessageBox::information(this, "提示", "串口打开成功");
    }
    else
    {
    #if ERROR
        // critical函数表示警告
        QMessageBox::critical(this, "提示", "串口已打开");
    #endif
    }
#endif
}

而关闭串口只要直接关闭就行了

void Widget::on_closeButton_clicked()
{
#if Serial_Closed_Button
    // 关闭槽函数
    serialport->close();

    // 关闭串口提示
    QMessageBox::information(this, "提示", "关闭串口");
#endif
}

有一处改动,将串口设置放到打开串口的槽函数中。发现如果在Widget::Widget函数中先扫描然后初始化串口会导致程序异常,我也不知道为什么????

3、知识补充串口编程Qt Serial Port

Qt Serial Port模块:这个模块用于串口通信编程,Qt Serial Port有两个类QSerialPortInfo和QSerialPort。

QSerialPortInfo类里面有两个函数,我的理解是就是用来获取数据的

        QSerialPortInfo::availablePorts()                //获取串口列表

        QSerialPortInfo::standardBaudRates()        // 获取串口支持波特率列表

返回值:获取串口列表QList<QSerialPortInfo>,获取波特率的返回值是QList<qint32>。那接下来就有个问题,怎么使用这两个函数?

1)QSerialPortInfo::availablePorts() - 这个函数返回的类型是QStringList,表示一个列表,看名字也看得出来。可以通过遍历这个列表获取系统所有的可用串口。

#include <QSerialPortInfo>  
#include <QDebug>  
  
int main() {  
    // 获取所有可用的串口  
    QList<QSerialPortInfo> ports = QSerialPortInfo::availablePorts();  
  
    // 遍历并打印串口名称  
    for(const QSerialPortInfo &port : ports) {  
        qDebug() << "Port Name:" << port.portName();  
    }  
  
    return 0;  
}

2、QSerialPortInfo::standardBaudRates() - 这个函数返回一个包含所有标准波特率的QList<qint32>。这些波特率是串口通信中常用的标准波特率。

// 获取标准波特率列表  
    QList<qint32> baudRates = QSerialPortInfo::standardBaudRates();  
  
    // 遍历并打印波特率  
    for(qint32 baudRate : baudRates) {  
        qDebug() << "Baud Rate:" << baudRate;  
    } 

4、通过所学修改波特率和com口的获取方法

根据之前学的qseriportinfo中的操作,就可以修改波特率为所有波特率

#if Read_Serial
    // 获取波特率
    QString Baud_String;
    QStringList Baud_StringList;
    QList<qint32> baudRates = QSerialPortInfo::standardBaudRates(); // 获取标准波特率列表

    for(const qint32 &baudRate : baudRates)         // 遍历全部波特率列表
    {
        Baud_String = QString::number(baudRate);    // 将qint32转换成qString
        Baud_StringList.append(Baud_String);        // 添加到QString_List
    }
    // 把标准波特率添加到ui界面
    ui->baudrateBox->addItems(Baud_StringList);
#endif

同样的获取端口列表修改

#if Serial_Scan
    // 获取COM口
    QString COM_String;
    QStringList COM_StringList;
    QList<QSerialPortInfo> COM_Ports = QSerialPortInfo::availablePorts();

    for(const QSerialPortInfo &port : COM_Ports)    // 遍历全部端口列表
    {
        COM_String = port.portName();               // qstring保存端口名称
        COM_StringList.append(COM_String);          // 添加到COM_string列表
    }
        ui->serialBox->addItems(COM_StringList);    // 把扫描到的端口放入BOX中
#endif


接下来是QSerialPort类,学习这个的时候有一个概念叫继承与重载,之前学习C++只学了个皮毛,所以打算记录一下。

继承和重载面向对象的一个概念,类和对象之间的一种关系。回顾继承和重载之前,有一个概念是类和对象。

什么是类和对象?

虽然之前已经接触过类和对象,但还是只停留在似懂非懂的层面。类,英文名叫class,对象的英文名叫object。类就是有相同的属性和方法的东西,而对象就是具体的东西。举个例子,比如说人就是一类,这个类里面有很多属性,比如说身高体重。而具体的人就是对象,比如说张三,他的身高160,体重50kg。转换成计算机语言就是先声明一个类,比如class person{身高,体重}。接着用这个类再声明一个叫张三的人person 张三。然后再赋值属性,比如张三->身高=150,张三->体重->50kg。不知道对不对,先暂时这么理解。

什么是继承和重载?

接下来就可以学习继承和重载了。继承:一种类与类之间的关系,它表示一个类(称为子类)可以继承另一个类(称为父类)的属性和方法,继承允许我们在不重复编写代码的情况下,扩展和定制现有代码的基础。

重载:重载是指在同一类中,可以定义多个具有相同名称但参数列表不同的方法。这些方法可以有不同的返回类型,但关键是参数列表必须不同。


QSerialPort类中有以下一些重要的函数:

1、open(OpenMode mode):这是QIODevice::open()的继承和重载。这个函数的功能是用“OpenMode”模式打开串口,如果打开成功就返回true,否则就返回false并且会报错,错误码可以通过调用“erro()”函数来查看。

2、readData(char * data, qint64 maxSize):这是QIODevice::readData()的继承和重载,用于从串口读取数据。

3、readLineData(char * data, qint64 maxSize):这是QIODevice::readLineData()的继承和重载,用于从串口读取数据直到遇到换行符。

可以看出QSerialPort本质是对QIQDevice进行了一些处理和扩展,使得满足串口的应用场景。

5、增加发送串口数据

在ui界面添加一个发送文本SendData和发送按钮。在发送的clicked()槽函数中做这么几件事,首先是获取发送文本的数据,因为是第一次添加发送数据,所以按照一个byte去发,后面要多组数据的话,再想办法改进。

先要获取发送的数据:DataToSend = ui->SendData->toPlainText(),接下来就是转换成字节,然后使用serialport的成员函数write把数据发送出去

#if Serial_Send
// 串口发送
QByteArray Data;
QString DataToSend;
QByteArray DataByte;

DataToSend = ui->SendData->toPlainText();   // 获取发送中的数据
DataByte = DataToSend.toUtf8();             // 转换成字节数组,适应串口发送
serialport->write(DataByte);                // 发送数据
#endif

实际的效果:

0、发布程序

使用windeployqt,首先是qt creator界面选择release运行程序,在输出目录找到.exe文件

是以管理员身份运行,qt里面的命令行程序(安装完qt自带的),然后跳转到.exe所在的目录,命令

cd /d 后面再跟着目录:cd /d C:\Users\dell\Desktop\qt project\exe

然后输入windeployqt+exe的名称:windeployqt untitled.exe。

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值