Qt学习笔记第81到90讲

发布于:2025-02-10 ⋅ 阅读:(45) ⋅ 点赞:(0)

第81讲 串口调试助手实现自动发送

为这个名叫“定时发送”的QCheckBox编写槽函数。

想要做出定时发送的效果,必须引入QT框架下的毫秒级定时器QTimer,查阅手册了解详情。

在widget.h内添加新的私有成员变量:

    QTimer *timer;

在widget类的构造函数内部进行变量初始化:

    ui->setupUi(this);
    this->setLayout(ui->gridLayoutGlobal);
    writeCntGobal=0;
    readCntGobal=0;
    serialStatus=false;
    serialPort = new QSerialPort(this);
    timer=new QTimer(this);

关联信号与槽函数,信号是timeout超时函数,槽函数是发送文本函数:

    connect(timer,&QTimer::timeout,[=](){
        on_btnSendContext_clicked();
    });

先测试一下信号与槽是否成功关联,checkBox槽函数的逻辑是勾选后定时器开起,超时后执行槽函数然后自动重装载,如果没有勾选就关闭定时器:

void Widget::on_checkBoxSendInTime_clicked(bool checked)
{
  if(checked)
  {
     timer->start(ui->lineEditTimeeach->text().toInt());
  }else{
     timer->stop();

  }
}

测试结果如下,1S发两个,程序正常跑起来了。

接下来,我们会在串口关闭状态下屏蔽“定时发送”按键与“发送”按键;

打开串口定时发送时,屏蔽发送频率输入框与文本输入框。

setEnabled方法可以屏蔽上述的所有控件,进入一种“不可选中”的状态。其次,对于可以勾选的Check Box,setCheckState方法可以取消勾选状态对控件进行重置。

综上所述:

#include "widget.h"
#include "ui_widget.h"

#include <QMessageBox>
#include <QSerialPort>

Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{
    ui->setupUi(this);
    this->setLayout(ui->gridLayoutGlobal);
    writeCntGobal=0;
    readCntGobal=0;
    serialStatus=false;
    serialPort = new QSerialPort(this);
    timer=new QTimer(this);

    connect(serialPort,&QSerialPort::readyRead,this,&Widget::on_serialData_readytoRead);
    connect(timer,&QTimer::timeout,[=](){
        on_btnSendContext_clicked();
    });

    ui->comboBox_baudRate->setCurrentIndex(6);
    ui->comboBox_dataBit->setCurrentIndex(3);

    QList <QSerialPortInfo> serialList=QSerialPortInfo::availablePorts();
    for(QSerialPortInfo serialInfo:serialList)
    {
        //qDebug()<<serialInfo.portName();
        ui->comboBox_serialNum->addItem(serialInfo.portName());
    }

    ui->btnSendContext->setEnabled(false);
    ui->checkBoxSendInTime->setEnabled(false);
}

Widget::~Widget()
{
    delete ui;
}


void Widget::on_btnCloseOrOpenSerial_clicked()
{
    if(serialStatus==false)
    {

        //1.选择端口号
        serialPort->setPortName(ui->comboBox_serialNum->currentText());
        //2.配置波特率
        serialPort->setBaudRate(ui->comboBox_baudRate->currentText().toInt());
        //3.配置数据位
        serialPort->setDataBits(QSerialPort::DataBits(ui->comboBox_dataBit->currentText().toUInt()));
        //4.配置校验位
        /*MARK DOWN :
    enum Parity {
        NoParity = 0,
        EvenParity = 2,
        OddParity = 3,
        SpaceParity = 4,
        MarkParity = 5,
        UnknownParity = -1
    };
    Q_ENUM(Parity)
  */
        switch(ui->comboBox_checkBit->currentIndex())
        {
        case 0:
            serialPort->setParity(QSerialPort::NoParity);
            break;

        case 1:
            serialPort->setParity(QSerialPort::EvenParity);
            break;

        case 2:
            serialPort->setParity(QSerialPort::OddParity);
            break;

        case 3:
            serialPort->setParity(QSerialPort::SpaceParity);
            break;

        case 4:
            serialPort->setParity(QSerialPort::MarkParity);
            break;


        default:
            serialPort->setParity(QSerialPort::UnknownParity);
            break;
        }
        //5.配置停止位
        serialPort->setStopBits(QSerialPort::StopBits(ui->comboBox_stopBit->currentText().toInt()));
        //6.流控
        if(ui->comboBox_fileCon->currentText()=="None")
            serialPort->setFlowControl(QSerialPort::NoFlowControl);
        //7.打开串口
        if(serialPort->open(QIODevice::ReadWrite))
        {
            qDebug()<<"serial open";

            serialStatus=true;
            ui->btnSendContext->setEnabled(true);

            ui->btnCloseOrOpenSerial->setText("关闭串口 ");
            ui->comboBox_dataBit->setEnabled(false);
            ui->comboBox_fileCon->setEnabled(false);
            ui->comboBox_stopBit->setEnabled(false);
            ui->comboBox_baudRate->setEnabled(false);
            ui->comboBox_checkBit->setEnabled(false);
            ui->comboBox_serialNum->setEnabled(false);

            ui->checkBoxSendInTime->setEnabled(true);

        }else{
            QMessageBox msgBox;
            msgBox.setWindowTitle("错误");
            msgBox.setText("此串口已被占用或拔出!");
            msgBox.exec();
        }
    }else{
        serialStatus=false;
        ui->btnSendContext->setEnabled(false);

        serialPort->close();
        ui->btnCloseOrOpenSerial->setText("打开串口 ");
        ui->comboBox_dataBit->setEnabled(true);
        ui->comboBox_fileCon->setEnabled(true);
        ui->comboBox_stopBit->setEnabled(true);
        ui->comboBox_baudRate->setEnabled(true);
        ui->comboBox_checkBit->setEnabled(true);
        ui->comboBox_serialNum->setEnabled(true);

        ui->checkBoxSendInTime->setEnabled(false);
        ui->checkBoxSendInTime->setCheckState(Qt::Unchecked);
        timer->stop();
        ui->lineEditTimeeach->setEnabled(true);
        ui->lineEditSendContext->setEnabled(true);
    }
}

void Widget::on_btnSendContext_clicked()
{
    int writeCnt=0;

    const char* sendData=ui->lineEditSendContext->text().toStdString().c_str();
    writeCnt=serialPort->write(sendData);

    if(writeCnt==-1){
        ui->labelSendStatus->setText("Send Error!");
    }else{
        writeCntGobal+=writeCnt;
        qDebug()<<"Send Ok! "<<sendData;

        ui->labelSendStatus->setText("Send Ok!");
        ui->labelSendcnt->setNum(writeCntGobal);

        if(strcmp(sendData,sendBack.toStdString().c_str())!=0)
        {
            ui->textEditRecord->append(sendData);
            sendBack=QString(sendData);
        }
    }
}

void Widget::on_serialData_readytoRead()
{
    QString revMessage=serialPort->readAll();

    if(revMessage!=NULL){
        qDebug()<<"getMessage:"<<revMessage;
        ui->textEditRev->append(revMessage);
        readCntGobal+=revMessage.size();
        ui->labelRevcnt->setNum(readCntGobal);
    }else{


    }
}

void Widget::on_checkBoxSendInTime_clicked(bool checked)
{
  if(checked)
  {
     ui->lineEditTimeeach->setEnabled(false);
     ui->lineEditSendContext->setEnabled(false);
     timer->start(ui->lineEditTimeeach->text().toInt());
  }else{
     ui->lineEditTimeeach->setEnabled(true);
     ui->lineEditSendContext->setEnabled(true);
     timer->stop();

  }
}

第82讲 如何自我验证新控件

先布置UI:

然后编写槽函数就行:

#include "widget.h"
#include "ui_widget.h"

#include <QTimer>
#include <QDebug>

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    htim1=new QTimer(this);
    connect(htim1,&QTimer::timeout,[=](){
        qDebug()<<"time out";
    });
}

Widget::~Widget()
{
    delete ui;
}

void Widget::on_btnStart_clicked()
{
    htim1->start(1000);
}

void Widget::on_btnEnd_clicked()
{
    htim1->stop();
}

void Widget::on_checkBox_clicked()
{
    if(ui->checkBox->checkState()==Qt::Checked)
    {
        qDebug()<<"checkBox Checked!";
    }else if(ui->checkBox->checkState()==Qt::Unchecked)
    {
        qDebug()<<"checkBox Unchecked!";
    }
}

第83讲 解决遗留的Bug

①如果传输的字符串较长,可能会导致历史记录里发送过的字符串再次发送;问题的根源是解决QString到const char*的数据转换。

const char* sendData=ui->lineEditSendContext->text().toLocal8Bit().constData();

并且在比较当前字符串与已发送字符串的时候也做出修改:

if(strcmp(sendData,sendBack.toStdString().c_str())!=0)
{
   ui->textEditRecord->append(sendData);
   sendBack=QString::fromUtf8(sendData);
}

这个地方的字符label本来被吞了,现在可以通过拼接字符串解决:

 ui->labelSendcnt->setText("Sent:"+QString::number(writeCntGobal));
 ui->labelRevcnt->setText("Received:"+QString::number(readCntGobal));

最后槽函数:

void Widget::on_btnSendContext_clicked()
{
    int writeCnt=0;

    const char* sendData=ui->lineEditSendContext->text().toLocal8Bit().constData();
    writeCnt=serialPort->write(sendData);

    if(writeCnt==-1){
        ui->labelSendStatus->setText("Send Error!");
    }else{
        writeCntGobal+=writeCnt;
        qDebug()<<"Send Ok! "<<sendData;

        ui->labelSendStatus->setText("Send Ok!");
        //ui->labelSendcnt->setNum(writeCntGobal);
        ui->labelSendcnt->setText("Sent:"+QString::number(writeCntGobal));

        if(strcmp(sendData,sendBack.toStdString().c_str())!=0)
        {
            ui->textEditRecord->append(sendData);
            sendBack=QString::fromUtf8(sendData);
        }
    }
}

第84讲 串口调试助手保存接收记录

为这两个按键添加槽函数:

void Widget::on_btnRevClear_clicked()
{
    ui->textEditRev->setText("");
}

void Widget::on_btnRevSave_clicked()
{
    QString fileName=QFileDialog::getSaveFileName(this,tr("Save File"),
   "E:\\6_Qt Projects\\38_SerialPort\\SerialData\\serialData.txt",
    tr("Text(*.txt)") );

    if(fileName!=NULL)
    {
        QFile file(fileName);
        if(!file.open(QIODevice::WriteOnly|QIODevice::Text))
            return;

        QTextStream out(&file);
        out<<ui->textEditRev->toPlainText();
        file.close();
    }
}

第85讲 获取当前系统时间QDateTime

修改时间戳需要使用QDateTime这个类。

这一讲我们先做一个简单的实验,按下按键把时间戳要显示的字符内容刷新出来。

通过QDateTime内部的静态函数currentDateTime获取日期与时间:

QDateTime currentTime=QDateTime ::currentDateTime();

它的内部有date和time分别可以用来抓取年月日与时分秒:

所以槽函数:

void Widget::on_pushButton_clicked()
{
    QDateTime currentTime=QDateTime ::currentDateTime();

    QDate date=currentTime.date();
//    ui->textEdit->setText(QString::number(date.year()));
//    ui->textEdit->append(QString::number(date.month()));
//    ui->textEdit->append(QString::number(date.day()));

    QTime time=currentTime.time();
//    ui->textEdit->append(QString::number(time.hour()));
//    ui->textEdit->append(QString::number(time.minute()));
//    ui->textEdit->append(QString::number(time.second()));

//    QString nowTime=QString("%1-%2-%3 %4:%5:%6",
//    date.year(),date.month(), date.day(),time.hour(),time.minute(),time.second());

    QString nowTime=QString("%1-%2-%3 %4:%5:%6").arg(date.year()).arg(date.month()).
    arg(date.day()).arg(time.hour()).arg(time.minute()).arg(time.second());

    ui->textEdit->setText(nowTime);
}

注意QString内用占位符拼接字符串需要使用arg方法。

第86讲 串口调试助手右下角时间刷新

新增两个私有变量:

在构造函数内部初始化sysTick、关联信号与槽并且开始定时器:

    sysTick=new QTimer(this);

    connect(sysTick,SIGNAL(timeout()),this,SLOT(time_reflash()));
    sysTick->start(100);

注意,刷新周期为100ms可以让肉眼无法察觉初始label和时间戳的切换。

编写一个API获取windows桌面上的时间:

QString Widget::getSystime()
{
    QDateTime currentTime=QDateTime ::currentDateTime();
    QDate date=currentTime.date();
    QTime time=currentTime.time();

    QString nowTime=QString("%1-%2-%3 %4:%5:%6").arg(date.year()).arg(date.month()).
    arg(date.day()).arg(time.hour()).arg(time.minute()).arg(time.second());

    return nowTime;
}

刷新时间的槽函数可以利用这个API:

void Widget::time_reflash()
{
   ui->labelCurrentTime->setText(getSystime());
}

测试结果:

记录一下widget.cpp

#include "widget.h"
#include "ui_widget.h"

#include <QDateTime>
#include <QFileDialog>
#include <QMessageBox>
#include <QSerialPort>

Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{
    ui->setupUi(this);
    this->setLayout(ui->gridLayoutGlobal);
    writeCntGobal=0;
    readCntGobal=0;
    serialStatus=false;
    serialPort = new QSerialPort(this);
    timer=new QTimer(this);
    sysTick=new QTimer(this);

    connect(sysTick,SIGNAL(timeout()),this,SLOT(time_reflash()));
    sysTick->start(100);

    connect(serialPort,&QSerialPort::readyRead,this,&Widget::on_serialData_readytoRead);
    connect(timer,&QTimer::timeout,[=](){
        on_btnSendContext_clicked();
    });

    ui->comboBox_baudRate->setCurrentIndex(6);
    ui->comboBox_dataBit->setCurrentIndex(3);

    QList <QSerialPortInfo> serialList=QSerialPortInfo::availablePorts();
    for(QSerialPortInfo serialInfo:serialList)
    {
        //qDebug()<<serialInfo.portName();
        ui->comboBox_serialNum->addItem(serialInfo.portName());
    }

    ui->btnSendContext->setEnabled(false);
    ui->checkBoxSendInTime->setEnabled(false);
}

Widget::~Widget()
{
    delete ui;
}


void Widget::on_btnCloseOrOpenSerial_clicked()
{
    if(serialStatus==false)
    {

        //1.选择端口号
        serialPort->setPortName(ui->comboBox_serialNum->currentText());
        //2.配置波特率
        serialPort->setBaudRate(ui->comboBox_baudRate->currentText().toInt());
        //3.配置数据位
        serialPort->setDataBits(QSerialPort::DataBits(ui->comboBox_dataBit->currentText().toUInt()));
        //4.配置校验位
        /*MARK DOWN :
    enum Parity {
        NoParity = 0,
        EvenParity = 2,
        OddParity = 3,
        SpaceParity = 4,
        MarkParity = 5,
        UnknownParity = -1
    };
    Q_ENUM(Parity)
  */
        switch(ui->comboBox_checkBit->currentIndex())
        {
        case 0:
            serialPort->setParity(QSerialPort::NoParity);
            break;

        case 1:
            serialPort->setParity(QSerialPort::EvenParity);
            break;

        case 2:
            serialPort->setParity(QSerialPort::OddParity);
            break;

        case 3:
            serialPort->setParity(QSerialPort::SpaceParity);
            break;

        case 4:
            serialPort->setParity(QSerialPort::MarkParity);
            break;


        default:
            serialPort->setParity(QSerialPort::UnknownParity);
            break;
        }
        //5.配置停止位
        serialPort->setStopBits(QSerialPort::StopBits(ui->comboBox_stopBit->currentText().toInt()));
        //6.流控
        if(ui->comboBox_fileCon->currentText()=="None")
            serialPort->setFlowControl(QSerialPort::NoFlowControl);
        //7.打开串口
        if(serialPort->open(QIODevice::ReadWrite))
        {
            qDebug()<<"serial open";

            serialStatus=true;
            ui->btnSendContext->setEnabled(true);

            ui->btnCloseOrOpenSerial->setText("关闭串口 ");
            ui->comboBox_dataBit->setEnabled(false);
            ui->comboBox_fileCon->setEnabled(false);
            ui->comboBox_stopBit->setEnabled(false);
            ui->comboBox_baudRate->setEnabled(false);
            ui->comboBox_checkBit->setEnabled(false);
            ui->comboBox_serialNum->setEnabled(false);

            ui->checkBoxSendInTime->setEnabled(true);

        }else{
            QMessageBox msgBox;
            msgBox.setWindowTitle("错误");
            msgBox.setText("此串口已被占用或拔出!");
            msgBox.exec();
        }
    }else{
        serialStatus=false;
        ui->btnSendContext->setEnabled(false);

        serialPort->close();
        ui->btnCloseOrOpenSerial->setText("打开串口 ");
        ui->comboBox_dataBit->setEnabled(true);
        ui->comboBox_fileCon->setEnabled(true);
        ui->comboBox_stopBit->setEnabled(true);
        ui->comboBox_baudRate->setEnabled(true);
        ui->comboBox_checkBit->setEnabled(true);
        ui->comboBox_serialNum->setEnabled(true);

        ui->checkBoxSendInTime->setEnabled(false);
        ui->checkBoxSendInTime->setCheckState(Qt::Unchecked);
        timer->stop();
        ui->lineEditTimeeach->setEnabled(true);
        ui->lineEditSendContext->setEnabled(true);
    }
}

void Widget::on_btnSendContext_clicked()
{
    int writeCnt=0;

    const char* sendData=ui->lineEditSendContext->text().toLocal8Bit().constData();
    writeCnt=serialPort->write(sendData);

    if(writeCnt==-1){
        ui->labelSendStatus->setText("Send Error!");
    }else{
        writeCntGobal+=writeCnt;
        qDebug()<<"Send Ok! "<<sendData;

        ui->labelSendStatus->setText("Send Ok!");
        //ui->labelSendcnt->setNum(writeCntGobal);
        ui->labelSendcnt->setText("Sent:"+QString::number(writeCntGobal));

        if(strcmp(sendData,sendBack.toStdString().c_str())!=0)
        {
            ui->textEditRecord->append(sendData);
            sendBack=QString::fromUtf8(sendData);
        }
    }
}

void Widget::on_serialData_readytoRead()
{
    QString revMessage=serialPort->readAll();

    if(revMessage!=NULL){
        qDebug()<<"getMessage:"<<revMessage;
        ui->textEditRev->append(revMessage);
        readCntGobal+=revMessage.size();
        //ui->labelRevcnt->setNum(readCntGobal);
        ui->labelRevcnt->setText("Received:"+QString::number(readCntGobal));
    }else{


    }
}

void Widget::on_checkBoxSendInTime_clicked(bool checked)
{
  if(checked)
  {
     ui->lineEditTimeeach->setEnabled(false);
     ui->lineEditSendContext->setEnabled(false);
     timer->start(ui->lineEditTimeeach->text().toInt());
  }else{
     ui->lineEditTimeeach->setEnabled(true);
     ui->lineEditSendContext->setEnabled(true);
     timer->stop();

  }
}

void Widget::on_btnRevClear_clicked()
{
    ui->textEditRev->setText("");
}

void Widget::on_btnRevSave_clicked()
{
    QString fileName=QFileDialog::getSaveFileName(this,tr("Save File"),
   "E:\\6_Qt Projects\\38_SerialPort\\SerialData\\serialData.txt",
    tr("Text(*.txt)") );

    if(fileName!=NULL)
    {
        QFile file(fileName);
        if(!file.open(QIODevice::WriteOnly|QIODevice::Text))
            return;

        QTextStream out(&file);
        out<<ui->textEditRev->toPlainText();
        file.close();
    }
}

QString Widget::getSystime()
{
    QDateTime currentTime=QDateTime ::currentDateTime();
    QDate date=currentTime.date();
    QTime time=currentTime.time();

    QString nowTime=QString("%1-%2-%3 %4:%5:%6").arg(date.year()).arg(date.month()).
    arg(date.day()).arg(time.hour()).arg(time.minute()).arg(time.second());

    return nowTime;
}

void Widget::time_reflash()
{
   ui->labelCurrentTime->setText(getSystime());
}

widget.h

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QSerialPortInfo>
#include <QDebug>
#include <QTimer>

QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();

private slots:
    void on_btnCloseOrOpenSerial_clicked();

    void on_btnSendContext_clicked();

    void on_serialData_readytoRead();

    void on_checkBoxSendInTime_clicked(bool checked);

    void on_btnRevClear_clicked();

    void on_btnRevSave_clicked();

    void time_reflash();

private:
    Ui::Widget  *ui;
    QSerialPort *serialPort;
    int writeCntGobal;
    int readCntGobal;
    QString sendBack;
    bool serialStatus;
    QTimer *timer;
   // QString nowTime;

    QString getSystime();
    QTimer  *sysTick;
};
#endif // WIDGET_H

第87讲 优化时间显示

优化了arg方法的使用,约束数据的数位,如果不足,就用0来补:

QString Widget::getSystime()
{
    QDateTime currentTime=QDateTime ::currentDateTime();
    QDate date=currentTime.date();
    QTime time=currentTime.time();

    QString nowTime=QString("%1-%2-%3 %4:%5:%6")
            .arg(date.year(),4,10,QChar('0'))
            .arg(date.month(),2,10,QChar('0'))
            .arg(date.day(),2,10,QChar('0'))
            .arg(time.hour(),2,10,QChar('0'))
            .arg(time.minute(),2,10,QChar('0'))
            .arg(time.second(),2,10,QChar('0'));

    return nowTime;
}

同时把接收时间的打印做出来。

修改on_serialData_readytoRead函数即可:

void Widget::on_serialData_readytoRead()
{
    QString revMessage = serialPort->readAll();
    if(revMessage != NULL){
        if(ui->checkBoxRevTime->checkState()== Qt::Unchecked){
            ui->textEditRev->append(revMessage);
        }
        else if(ui->checkBoxRevTime->checkState()== Qt::Checked){
            ui->textEditRev->append("["+getSystime()+"] "+revMessage);
        }

        readCntGobal += revMessage.size();

        ui->labelRevcnt->setText("Received:"+QString::number(readCntGobal));
    }
}

第88讲 串口调试助手初步实现HEX显示

这一讲实现的功能是将textEditRev控件上面的字符串转换成Hex格式:

void Widget::on_checkBoxHexDisplay_clicked(bool checked)
{
    if(checked){
        //1.读取textEdit上的内容
        QString temp=ui->textEditRev->toPlainText();
        //2.转换成Hex
        QByteArray qtemp=temp.toUtf8();
        qtemp=qtemp.toHex();
        //3.显示
        ui->textEditRev->setText(QString::fromUtf8(qtemp));
    }else{
        //1.读取textEdit上的Hex内容
        QString tempHexString=ui->textEditRev->toPlainText();
        QByteArray tempHexQByteArray=tempHexString.toUtf8();
        QByteArray tempQByteString=QByteArray::fromHex(tempHexQByteArray);
        ui->textEditRev->setText(QString::fromUtf8(tempQByteString));
    }
}

第89讲 串口调试助手关联Hex接收

我们现在希望勾选checkBoxHexDisplay之后,接收的内容都能自动转换为Hex,解决的思路还是和添加时间戳一样,修改readytoRead函数:

void Widget::on_serialData_readytoRead()
{
    QString revMessage = serialPort->readAll();
    if(revMessage != NULL){
        if(ui->checkBoxHexDisplay->isChecked())
        {
            //将接受到的字符串转换为十六进制
            QByteArray tempHexString=revMessage.toUtf8().toHex();
            //捕获原来控件上的内容
            QString orignalString=ui->textEditRev->toPlainText();
            //拼接字符串
            tempHexString=orignalString.toUtf8()+tempHexString;
            ui->textEditRev->setText(QString::fromUtf8(tempHexString));

        }else{
            if(ui->checkBoxRevTime->checkState()== Qt::Unchecked){
                ui->textEditRev->append(revMessage);
            }
            else if(ui->checkBoxRevTime->checkState()== Qt::Checked){
                ui->textEditRev->append("["+getSystime()+"]"+revMessage);
            }
            readCntGobal += revMessage.size();
            ui->labelRevcnt->setText("Received:"+QString::number(readCntGobal));
    }
  }
}

第90讲 串口调试助手HEX发送单片机联调测试

修改发送函数,新添加了勾选上Hex发送的条件判断语句。

void Widget::on_btnSendContext_clicked()
{
    int writeCnt=0;

    const char* sendData=ui->lineEditSendContext->text().toLocal8Bit().constData();

    if(ui->checkBoxHexSend->isChecked()){
        QString temp=ui->lineEditSendContext->text();
        //判断是否为偶数位
        QByteArray tempArray=temp.toLocal8Bit();
        if(tempArray.size()%2!=0)
        {
           ui->labelSendStatus->setText("Error Input!");
           return;
        }
        //判断是否符合十六进制的表达
        for(char c:tempArray)
        {
            if(!std::isxdigit(c)){
                ui->labelSendStatus->setText("Error Input!");
                return;
            }else{

            }
        }
        //转换成十六进制数发送
        QByteArray arraySend=QByteArray::fromHex(tempArray);
        writeCnt=serialPort->write(arraySend);
    }else{
        writeCnt=serialPort->write(sendData);

    }


    if(writeCnt==-1){
        ui->labelSendStatus->setText("Send Error!");
    }else{
        writeCntGobal+=writeCnt;
        qDebug()<<"Send Ok! "<<sendData;

        ui->labelSendStatus->setText("Send OK!");
        //ui->labelSendcnt->setNum(writeCntGobal);
        ui->labelSendcnt->setText("Sent:"+QString::number(writeCntGobal));

        if(strcmp(sendData,sendBack.toStdString().c_str())!=0)
        {
            ui->textEditRecord->append(sendData);
            sendBack=QString::fromUtf8(sendData);
        }
    }
}

本章结束,上传一下代码块作为备份

widget.cpp

#include "widget.h"
#include "ui_widget.h"

#include <QDateTime>
#include <QFileDialog>
#include <QMessageBox>
#include <QSerialPort>

Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{
    ui->setupUi(this);
    this->setLayout(ui->gridLayoutGlobal);
    writeCntGobal=0;
    readCntGobal=0;
    serialStatus=false;
    serialPort = new QSerialPort(this);
    timer=new QTimer(this);
    sysTick=new QTimer(this);

    connect(sysTick,SIGNAL(timeout()),this,SLOT(time_reflash()));
    sysTick->start(100);

    connect(serialPort,&QSerialPort::readyRead,this,&Widget::on_serialData_readytoRead);
    connect(timer,&QTimer::timeout,[=](){
        on_btnSendContext_clicked();
    });

    ui->comboBox_baudRate->setCurrentIndex(6);
    ui->comboBox_dataBit->setCurrentIndex(3);

    QList <QSerialPortInfo> serialList=QSerialPortInfo::availablePorts();
    for(QSerialPortInfo serialInfo:serialList)
    {
        //qDebug()<<serialInfo.portName();
        ui->comboBox_serialNum->addItem(serialInfo.portName());
    }

    ui->btnSendContext->setEnabled(false);
    ui->checkBoxSendInTime->setEnabled(false);
}

Widget::~Widget()
{
    delete ui;
}


void Widget::on_btnCloseOrOpenSerial_clicked()
{
    if(serialStatus==false)
    {

        //1.选择端口号
        serialPort->setPortName(ui->comboBox_serialNum->currentText());
        //2.配置波特率
        serialPort->setBaudRate(ui->comboBox_baudRate->currentText().toInt());
        //3.配置数据位
        serialPort->setDataBits(QSerialPort::DataBits(ui->comboBox_dataBit->currentText().toUInt()));
        //4.配置校验位
        /*MARK DOWN :
    enum Parity {
        NoParity = 0,
        EvenParity = 2,
        OddParity = 3,
        SpaceParity = 4,
        MarkParity = 5,
        UnknownParity = -1
    };
    Q_ENUM(Parity)
  */
        switch(ui->comboBox_checkBit->currentIndex())
        {
        case 0:
            serialPort->setParity(QSerialPort::NoParity);
            break;

        case 1:
            serialPort->setParity(QSerialPort::EvenParity);
            break;

        case 2:
            serialPort->setParity(QSerialPort::OddParity);
            break;

        case 3:
            serialPort->setParity(QSerialPort::SpaceParity);
            break;

        case 4:
            serialPort->setParity(QSerialPort::MarkParity);
            break;


        default:
            serialPort->setParity(QSerialPort::UnknownParity);
            break;
        }
        //5.配置停止位
        serialPort->setStopBits(QSerialPort::StopBits(ui->comboBox_stopBit->currentText().toInt()));
        //6.流控
        if(ui->comboBox_fileCon->currentText()=="None")
            serialPort->setFlowControl(QSerialPort::NoFlowControl);
        //7.打开串口
        if(serialPort->open(QIODevice::ReadWrite))
        {
            qDebug()<<"serial open";

            serialStatus=true;
            ui->btnSendContext->setEnabled(true);

            ui->btnCloseOrOpenSerial->setText("关闭串口 ");
            ui->comboBox_dataBit->setEnabled(false);
            ui->comboBox_fileCon->setEnabled(false);
            ui->comboBox_stopBit->setEnabled(false);
            ui->comboBox_baudRate->setEnabled(false);
            ui->comboBox_checkBit->setEnabled(false);
            ui->comboBox_serialNum->setEnabled(false);

            ui->checkBoxSendInTime->setEnabled(true);

        }else{
            QMessageBox msgBox;
            msgBox.setWindowTitle("错误");
            msgBox.setText("此串口已被占用或拔出!");
            msgBox.exec();
        }
    }else{
        serialStatus=false;
        ui->btnSendContext->setEnabled(false);

        serialPort->close();
        ui->btnCloseOrOpenSerial->setText("打开串口 ");
        ui->comboBox_dataBit->setEnabled(true);
        ui->comboBox_fileCon->setEnabled(true);
        ui->comboBox_stopBit->setEnabled(true);
        ui->comboBox_baudRate->setEnabled(true);
        ui->comboBox_checkBit->setEnabled(true);
        ui->comboBox_serialNum->setEnabled(true);

        ui->checkBoxSendInTime->setEnabled(false);
        ui->checkBoxSendInTime->setCheckState(Qt::Unchecked);
        timer->stop();
        ui->lineEditTimeeach->setEnabled(true);
        ui->lineEditSendContext->setEnabled(true);
    }
}

void Widget::on_btnSendContext_clicked()
{
    int writeCnt=0;

    const char* sendData=ui->lineEditSendContext->text().toLocal8Bit().constData();

    if(ui->checkBoxHexSend->isChecked()){
        QString temp=ui->lineEditSendContext->text();
        //判断是否为偶数位
        QByteArray tempArray=temp.toLocal8Bit();
        if(tempArray.size()%2!=0)
        {
           ui->labelSendStatus->setText("Error Input!");
           return;
        }
        //判断是否符合十六进制的表达
        for(char c:tempArray)
        {
            if(!std::isxdigit(c)){
                ui->labelSendStatus->setText("Error Input!");
                return;
            }else{

            }
        }
        //转换成十六进制数发送
        QByteArray arraySend=QByteArray::fromHex(tempArray);
        writeCnt=serialPort->write(arraySend);
    }else{
        writeCnt=serialPort->write(sendData);

    }


    if(writeCnt==-1){
        ui->labelSendStatus->setText("Send Error!");
    }else{
        writeCntGobal+=writeCnt;
        qDebug()<<"Send Ok! "<<sendData;

        ui->labelSendStatus->setText("Send OK!");
        //ui->labelSendcnt->setNum(writeCntGobal);
        ui->labelSendcnt->setText("Sent:"+QString::number(writeCntGobal));

        if(strcmp(sendData,sendBack.toStdString().c_str())!=0)
        {
            ui->textEditRecord->append(sendData);
            sendBack=QString::fromUtf8(sendData);
        }
    }
}

void Widget::on_serialData_readytoRead()
{
    QString revMessage = serialPort->readAll();
    if(revMessage != NULL){
        if(ui->checkBoxHexDisplay->isChecked())
        {
            //将接受到的字符串转换为十六进制
            QByteArray tempHexString=revMessage.toUtf8().toHex();
            //捕获原来控件上的内容
            QString orignalString=ui->textEditRev->toPlainText();
            //拼接字符串
            tempHexString=orignalString.toUtf8()+tempHexString;
            ui->textEditRev->setText(QString::fromUtf8(tempHexString));

        }else{
            if(ui->checkBoxRevTime->checkState()== Qt::Unchecked){
                ui->textEditRev->append(revMessage);
            }
            else if(ui->checkBoxRevTime->checkState()== Qt::Checked){
                ui->textEditRev->append("["+getSystime()+"]"+revMessage);
            }
            readCntGobal += revMessage.size();
            ui->labelRevcnt->setText("Received:"+QString::number(readCntGobal));
    }
  }
}

void Widget::on_checkBoxSendInTime_clicked(bool checked)
{
  if(checked)
  {
     ui->lineEditTimeeach->setEnabled(false);
     ui->lineEditSendContext->setEnabled(false);
     timer->start(ui->lineEditTimeeach->text().toInt());
  }else{
     ui->lineEditTimeeach->setEnabled(true);
     ui->lineEditSendContext->setEnabled(true);
     timer->stop();

  }
}

void Widget::on_btnRevClear_clicked()
{
    ui->textEditRev->setText("");
}

void Widget::on_btnRevSave_clicked()
{
    QString fileName=QFileDialog::getSaveFileName(this,tr("Save File"),
   "E:\\6_Qt Projects\\42_SerialTime\\SerialData\\serialData.txt",
    tr("Text(*.txt)") );

    if(fileName!=NULL)
    {
        QFile file(fileName);
        if(!file.open(QIODevice::WriteOnly|QIODevice::Text))
            return;

        QTextStream out(&file);
        out<<ui->textEditRev->toPlainText();
        file.close();
    }
}

QString Widget::getSystime()
{
    QDateTime currentTime=QDateTime ::currentDateTime();
    QDate date=currentTime.date();
    QTime time=currentTime.time();

    QString nowTime=QString("%1-%2-%3 %4:%5:%6")
            .arg(date.year(),4,10,QChar('0'))
            .arg(date.month(),2,10,QChar('0'))
            .arg(date.day(),2,10,QChar('0'))
            .arg(time.hour(),2,10,QChar('0'))
            .arg(time.minute(),2,10,QChar('0'))
            .arg(time.second(),2,10,QChar('0'));

    return nowTime;
}

void Widget::time_reflash()
{
   ui->labelCurrentTime->setText(getSystime());
}

void Widget::on_checkBoxHexDisplay_clicked(bool checked)
{
    if(checked){
        //1.读取textEdit上的内容
        QString temp=ui->textEditRev->toPlainText();
        //2.转换成Hex
        QByteArray qtemp=temp.toUtf8();
        qtemp=qtemp.toHex();
        //3.显示
        ui->textEditRev->setText(QString::fromUtf8(qtemp));
    }else{
        //1.读取textEdit上的Hex内容
        QString tempHexString=ui->textEditRev->toPlainText();
        QByteArray tempHexQByteArray=tempHexString.toUtf8();
        QByteArray tempQByteString=QByteArray::fromHex(tempHexQByteArray);
        ui->textEditRev->setText(QString::fromUtf8(tempQByteString));
    }
}

widget.h

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QSerialPortInfo>
#include <QDebug>
#include <QTimer>

QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();

private slots:
    void on_btnCloseOrOpenSerial_clicked();

    void on_btnSendContext_clicked();

    void on_serialData_readytoRead();

    void on_checkBoxSendInTime_clicked(bool checked);

    void on_btnRevClear_clicked();

    void on_btnRevSave_clicked();

    void time_reflash();

    void on_checkBoxHexDisplay_clicked(bool checked);

private:
    Ui::Widget  *ui;
    QSerialPort *serialPort;
    int writeCntGobal;
    int readCntGobal;
    QString sendBack;
    bool serialStatus;
    QTimer *timer;
   // QString nowTime;

    QString getSystime();
    QTimer  *sysTick;
};
#endif // WIDGET_H

界面UI概览