【Qt串口调试助手】1.1 - Qt5编写串口调试助手,Qt串口编程

 

这章来学习串口数据流操作。仿照已有成品制作一个用Qt开发的串口调试助手。

介于篇幅有限,本篇只介绍一个最简单的能收发的串口调试助手的制作。后续篇幅会陆续对剩余代码进行讲解,并添加各种功能,对显示、操作、功能的各方面继续优化,达成与市面上的成品一样的功能。目标精简、可靠、高效、便于当作框架二次开发,欢迎各位使用和作为框架进行二次开发,并提出改进意见。

发布效果展示:Qt串口调试助手演示效果

GitHub源码仓库:Qt串口调试助手源码下载

更新:后期在原有串口功能上,使用了QCustomPlot绘图库,制作了串口波形绘图上位机,非常适合单片机上传波形进行调试。最多可显示20条曲线,支持滚轮Y轴缩放、左键拖拽。波形帧协议兼容匿名四轴调试上位机,并增加了16进制转换,支持GB2312中文编码。详细介绍见:波形绘图上位机源码下载

 

GitHub中为最终发布代码,可能与讲解教程中略有不同,望自行对照。

1. 布局UI界面

  • 创建QMainWindow工程。
  • 布局UI界面:拖入2个 Plain Text Edit,作为串口数据的接收显示和发送框。
  • 再拖入几个 Combo Box 、 Label 和 Push Button,使用两个Widget进行布局。如下所示。

【Qt串口调试助手】1.1 - Qt5编写串口调试助手,Qt串口编程_第1张图片

【Qt串口调试助手】1.1 - Qt5编写串口调试助手,Qt串口编程_第2张图片

 

  • 将接收区的 Plain Text Edit,属性勾选上 readOnly,使其运行时不会被人为的输入操作影响。

【Qt串口调试助手】1.1 - Qt5编写串口调试助手,Qt串口编程_第3张图片

 

  • 加入一些弹簧,使布局美观。(有必要可以加设置,固定窗口大小,不能最大化。)

【Qt串口调试助手】1.1 - Qt5编写串口调试助手,Qt串口编程_第4张图片

 

2. 添加下拉列表项

  • 在ui设计界面中,双击 Combo Box添加列表项。

【Qt串口调试助手】1.1 - Qt5编写串口调试助手,Qt串口编程_第5张图片

 

  • 更改下拉框的默认值。修改 currentIndex属性,改变默认值。

【Qt串口调试助手】1.1 - Qt5编写串口调试助手,Qt串口编程_第6张图片

【Qt串口调试助手】1.1 - Qt5编写串口调试助手,Qt串口编程_第7张图片    【Qt串口调试助手】1.1 - Qt5编写串口调试助手,Qt串口编程_第8张图片

 

3. 修改控件名称

  • 将控件的命名统一,方便管理和程序书写。

【Qt串口调试助手】1.1 - Qt5编写串口调试助手,Qt串口编程_第9张图片

 

4. 添加串口类,自动扫描可用串口

  • 在工程 .pro文件中,添加 "QT += core gui serialport",以支持串口功能。

【Qt串口调试助手】1.1 - Qt5编写串口调试助手,Qt串口编程_第10张图片

 

  • 窗口构造函数中,添加自动扫描可用串口代码。(由于代码位于窗口构造函数中,故仅在应用刚打开时扫描串口,以后会增加点击下拉框时扫描,需要对鼠标点击事件进行重写)
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include 

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

    QStringList serialPortName;

    // 自动扫描当前可用串口,返回值追加到字符数组中
    foreach(const QSerialPortInfo &info, QSerialPortInfo::availablePorts()){
        serialPortName << info.portName();
    }
    // 可用串口号,显示到串口选择下拉框中
    ui->cmbSerialPort->addItems(serialPortName);
}

 

  • 如果电脑连接了串口设备,运行Qt应用,点击下拉框,会看到可用的串口号。

【Qt串口调试助手】1.1 - Qt5编写串口调试助手,Qt串口编程_第11张图片

 

  • 与标准的串口助手对比,结果一致。

【Qt串口调试助手】1.1 - Qt5编写串口调试助手,Qt串口编程_第12张图片

 

5. 打开串口、翻转开关

  • 功能:点击 "打开串口" 按钮,初始化串口参数,并按照设置好的参数打开串口。
  • 在 "打开串口" 按钮位置,右键,转到槽...。编写串口配置代码。
  • 将字符串,转换为可以代码设置的枚举,根据当前值,设置参数。之后打开对应串口端口。
// 打开/关闭串口 槽函数
void MainWindow::on_btnSwitch_clicked()
{

    QSerialPort::BaudRate baudRate;
    QSerialPort::DataBits dataBits;
    QSerialPort::StopBits stopBits;
    QSerialPort::Parity   checkBits;

    // 获取串口波特率
    // 有没有直接字符串转换为 int的方法???
    //baudRate = ui->cmbBaudRate->currentText().toInt();
    if(ui->cmbBaudRate->currentText() == "9600"){
        baudRate = QSerialPort::Baud9600;
    }else if(ui->cmbBaudRate->currentText() == "38400"){
        baudRate = QSerialPort::Baud38400;
    }else if(ui->cmbBaudRate->currentText() == "115200"){
        baudRate = QSerialPort::Baud115200;
    }else{

    }

    // 获取串口数据位
    if(ui->cmbData->currentText() == "5"){
        dataBits = QSerialPort::Data5;
    }else if(ui->cmbData->currentText() == "6"){
        dataBits = QSerialPort::Data6;
    }else if(ui->cmbData->currentText() == "7"){
        dataBits = QSerialPort::Data7;
    }else if(ui->cmbData->currentText() == "8"){
        dataBits = QSerialPort::Data8;
    }else{

    }

    // 获取串口停止位
    if(ui->cmbStop->currentText() == "1"){
        stopBits = QSerialPort::OneStop;
    }else if(ui->cmbStop->currentText() == "1.5"){
        stopBits = QSerialPort::OneAndHalfStop;
    }else if(ui->cmbStop->currentText() == "2"){
        stopBits = QSerialPort::TwoStop;
    }else{

    }

    // 获取串口奇偶校验位
    if(ui->cmbCheck->currentText() == "无"){
        checkBits = QSerialPort::NoParity;
    }else if(ui->cmbCheck->currentText() == "奇校验"){
        checkBits = QSerialPort::OddParity;
    }else if(ui->cmbCheck->currentText() == "偶校验"){
        checkBits = QSerialPort::EvenParity;
    }else{

    }

    // 想想用 substr strchr怎么从带有信息的字符串中提前串口号字符串
    // 初始化串口属性,设置 端口号、波特率、数据位、停止位、奇偶校验位数
    mySerialPort->setBaudRate(baudRate);
    mySerialPort->setDataBits(dataBits);
    mySerialPort->setStopBits(stopBits);
    mySerialPort->setParity(checkBits);
    mySerialPort->setPortName(ui->cmbSerialPort->currentText());// 不匹配带有串口设备信息的文本

    // 根据初始化好的串口属性,打开串口
    // 如果打开成功,反转打开按钮显示和功能。打开失败,无变化,并且弹出错误对话框。
    if(ui->btnSwitch->text() == "打开串口"){
        if(mySerialPort->open(QIODevice::ReadWrite) == true){
            //QMessageBox::
            ui->btnSwitch->setText("关闭串口");
            // 让端口号下拉框不可选,避免误操作(选择功能不可用,控件背景为灰色)
            ui->cmbSerialPort->setEnabled(false);
        }else{
            QMessageBox::critical(this, "错误提示", "串口打开失败!!!\r\n该串口可能被占用\r\n请选择正确的串口");
        }
    }else{
        mySerialPort->close();
        ui->btnSwitch->setText("打开串口");
        // 端口号下拉框恢复可选,避免误操作
        ui->cmbSerialPort->setEnabled(true);
    }

}

 

  • 为了避免串口被占用,或者其他错误,我们对打开也做相应的处理:如果串口被占用,会弹出错误提示框。
  • 并且为了防止端口在打开时,被篡改参数,避免改动串口号,做了处理:端口在打开后,下拉框是灰色不可选的。
  • 最终实现 打开串口 / 关闭串口 的功能转换与翻转显示。

【Qt串口调试助手】1.1 - Qt5编写串口调试助手,Qt串口编程_第13张图片

 

6. 接收串口数据

  • 预计结果:接收到串口数据后,将其显示到接收文本框中。
  • 构造函数中建立信号槽,将串口读准备信号,关联接收区显示处理槽函数。
  • 文本框内容使用插入显示。并在每次追加后移动光标

【Qt串口调试助手】1.1 - Qt5编写串口调试助手,Qt串口编程_第14张图片

 

  • 对于接收的显示处理方式,我总结了如下四种。各位有兴趣可以将注释打开,运行去了解。
  • 其中第3、4种都是将文本框全部读取再追加内容,运行效率很低,而网上很多开源代码是使用的这种处理方式。这正是使我想要搭建自己开发框架的原因,追求可靠、高效。
  • 我在代码中,使用的是第2种处理方式。解决了不同硬件的插入换行问题,兼容 CH340、CP2102等常用设备。(现象、成因和解决方法在后面序章有说)

【Qt串口调试助手】1.1 - Qt5编写串口调试助手,Qt串口编程_第15张图片

 

7. 发送串口数据

发送按钮,右键,转到槽...。

添加发送字符串代码。

 

8. 清空收区、发区文本内容

发送按钮,右键,转到槽...。

添加清空代码。

【Qt串口调试助手】1.1 - Qt5编写串口调试助手,Qt串口编程_第16张图片

 

运行结果

  • 运行时是没有左上角图标的,这是我后来测试生成可执行文件时添加的。

【Qt串口调试助手】1.1 - Qt5编写串口调试助手,Qt串口编程_第17张图片

 

总结

Qt编程串口调试助手的过程比较简单,但仍有很多地方待完善。例如端口扫描、16进制转换,硬件兼容性,这些会在后面的篇幅进行讲解和添加,力求精简、可靠、高效、便于当作框架二次开发。欢迎各位使用和作为框架进行二次开发,并提出改进意见。

GitHub源码仓库:Qt串口调试助手源码下载
 

你可能感兴趣的:(Qt应用开发,qt,c++,串口通信)