用Qt写串口调试助手(二):串口接收

	上次记录了一下用Qt是如何进行串口参数设置的,这次记录一下如何实现串口的接收,也就是:

串口接收区

	可以看到,对于接收,我实现的主要功能有将接收输出到文件,是否显示接收到的时间,
是否用十六进制显示,暂停显示以及保存数据和清除显示。
	在头文件中,也就是widget.h中:
    QSerialPort mSerialPort;		//串口对象   
    QByteArray receivePrimaryData;  //存放接收到的原始数据数据

    bool recDisplayIsPause = false; //判断接收显示是否暂停标志位, 默认显示

    QFile recFile;                  //接收到文件对象
    bool isRecToFile = false;       //是否接收到文件标志位,默认不接收到文件
	定义了这几个与接收有关的成员变量。
	receivePrimaryData:是接收到的原始数据,也就是发送过来的是什么,我们就不进行
任何处理,直接保存到该变量当中去。
	recDisplayIsPause:该变量为true时接收暂停显示。
	recFile:一个文件对象,用于将接收到的数据保存到文件当中去。
	isRecToFile:该变量为true时,接收保存到文件。
	对于源文件,也就是widget.cpp:
Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    //载入用户上次设置
    mLoadSet();

    //添加样式表
    mSetQSS();

    //初始化串口设置
    mQSerialPortSet();

    //接收设置
    mReceiveSet();	//这是与接收相关的函数
	在构造函数中调用mReceiveSet();方法,所有的与接收有关的处理都是在这个方法中
实现的。
	前文提到,我们已经设置好了mSerialPort;串口对象的参数。在Qt中,当串口接收到
信号的时候,会发出QSerialPort::readyRead信号,因此,我们连接该信号到槽函数,对
接收到的信号进行处理。
	也就是:
//串口接收设置
void Widget::mReceiveSet()
{
    //链接串口接收槽函数
    connect(&mSerialPort, &QSerialPort::readyRead, this, [=](){
    	//当串口接收到信号时,会执行下面代码
    	//这里填写处理代码
    });
	在该Lambda函数中,主要要做的是将接收到的信号保存到原始数据也就是,
receivePrimaryData变量中,然后再将该原始数据赋值个一个临时变量,最后对这个
临时变量进行相应的处理,再显示到文本框。至于为什么要保留这个原始数据
receivePrimaryData,不直接对其进行处理,那是因为对于串口通信来说,原始数据
是很重要的,比如我们就想看看串口发送过来的数据到底是什么,并将其保存到文件中
去,那么这个原始数据就非常有用了。

以下是整个处理函数:
	//链接串口接收槽函数
    connect(&mSerialPort, &QSerialPort::readyRead, this, [=](){
        //获取接收数据
        receivePrimaryData = mSerialPort.readAll();
        //qDebug() << receivePrimaryData << endl;

        //创建临时数据
        QByteArray receiveTemporaryData = receivePrimaryData;

        //存放16进制数据
        //QByteArray hexData = receivePrimaryData.toHex();

        //十六进制显示
        if(ui->chB_recDisplayHEX->isChecked() == true)
        {
            //将QByteArray转化为十六进制表示
            receiveTemporaryData = receiveTemporaryData.toHex().toUpper();

            //在每一个十六进制数之间插入空格
            for(int i = 2; i < receiveTemporaryData.size(); i += 3)
            {
                receiveTemporaryData.insert(i, ' ');
            }
        }

        //显示接收时间
        if(ui->chB_recDisplayTime->isChecked() == true)
        {
            //获取当前时间
            QDateTime currentTime = QDateTime::currentDateTime();
            QString timeString = currentTime.toString("yyyy-MM-dd HH:mm:ss");

            timeString = ("[" + timeString + "]");

            //添加时间戳
            receiveTemporaryData = timeString.append(receiveTemporaryData).toUtf8();
        }


        //接收显示不暂停,并且不接收到文件,则接收到接收文本框
        if(recDisplayIsPause == false && isRecToFile == false)
        {
            ui->tE_receiveData->append(receiveTemporaryData);
        }

        //不暂停显示并且接收到文件
        if(recDisplayIsPause == false && isRecToFile == true)
        {
            ui->tE_receiveData->append(receiveTemporaryData);

            QTextStream out(&recFile);
            out << receiveTemporaryData;
        }

        //暂停显示并且接收到文件
        if(recDisplayIsPause == true && isRecToFile == true)
        {
            QTextStream out(&recFile);
            out << receiveTemporaryData;
        }

    });
	首先,我们先将接收到的信息传递给一个临时的变量:
  		//获取接收数据
        receivePrimaryData = mSerialPort.readAll();
        //qDebug() << receivePrimaryData << endl;

        //创建临时数据
        QByteArray receiveTemporaryData = receivePrimaryData;

	之后判断用户是否勾选了十六进制接收,如果勾选了,就调用
receiveTemporaryData.toHex().toUpper();方法,将接收到的数据转换为十六进制的
字符串。
		//十六进制显示
        if(ui->chB_recDisplayHEX->isChecked() == true)
        {
            //将QByteArray转化为十六进制表示
            receiveTemporaryData = receiveTemporaryData.toHex().toUpper();

            //在每一个十六进制数之间插入空格
            for(int i = 2; i < receiveTemporaryData.size(); i += 3)
            {
                receiveTemporaryData.insert(i, ' ');
            }
        }
	结果是这样:
	发送端:发送aa bb cc
	没有勾选16进制显示,结果如下:

在这里插入图片描述

	勾选十六进制显示,结果如下:

在这里插入图片描述

	之后再判断用户是否添加接收时间。如果添加,就获取系统时间,再将信息添加到
时间后面。
		//显示接收时间
        if(ui->chB_recDisplayTime->isChecked() == true)
        {
            //获取当前时间
            QDateTime currentTime = QDateTime::currentDateTime();
            QString timeString = currentTime.toString("yyyy-MM-dd HH:mm:ss");

            timeString = ("[" + timeString + "]");

            //添加时间戳
            receiveTemporaryData = timeString.append(receiveTemporaryData).toUtf8();
        }
	勾选添加时间信息后结果如下:

在这里插入图片描述

	之后的代码就是用于判断是否接收显示,或者是接受到文本框,还是接收到文件。
 		//接收显示不暂停,并且不接收到文件,则接收到接收文本框
        if(recDisplayIsPause == false && isRecToFile == false)
        {
            ui->tE_receiveData->append(receiveTemporaryData);
        }

        //不暂停显示并且接收到文件
        if(recDisplayIsPause == false && isRecToFile == true)
        {
            ui->tE_receiveData->append(receiveTemporaryData);

            QTextStream out(&recFile);
            out << receiveTemporaryData;
        }

        //暂停显示并且接收到文件
        if(recDisplayIsPause == true && isRecToFile == true)
        {
            QTextStream out(&recFile);
            out << receiveTemporaryData;
        }

    });
	可以看到,我们是通过一些定义的标志位来判断的。如何改变这些标志位的真假呢,
我是通过连接槽函数来实现的。
	首先是否接收显示,当用户点击该控件时:

在这里插入图片描述
它将发出一个状态改变的信号:&QCheckBox::stateChanged,我们通过
槽函数进行状态改变。

	//链接是否接收显示
    connect(ui->chB_recDisplayPause, &QCheckBox::stateChanged, this, [=](int isChecked){
        //如果勾选,暂停显示
        if(isChecked == Qt::Checked)
        {
            ui->tE_receiveData->setEnabled(false);
            //显示暂停
            recDisplayIsPause = true;
        }
        else if(isChecked == Qt::Unchecked)
        {
            ui->tE_receiveData->setEnabled(true);
            //继续显示
            recDisplayIsPause = false;
        }
    });
	当用户打勾或取消打勾时,我们改变是否接收显示状态,并且设置接收文本框的使能状态。
之后再判断用户是否接收信息到文件,如果当用户点击接收数据到文件时,弹出一个文件选择
框,让用户选择文件路径,再通过该路径对文件进行操作。
	代码如下:
	//链接是否接收到文件,获取文件对象
    connect(ui->chB_recToFile, &QCheckBox::stateChanged, this, [=](int isChecked){
        if(isChecked == Qt::Checked)
        {
            //修改接收方式为接收到文件
            isRecToFile = true;

            //创建文件路径获取对象
            QFileDialog dialog;

            //设置文件过滤器(txt和所有文件)
            dialog.setNameFilter("Text files (*.txt);;All files (*)");

            //获取文件路径
            if(dialog.exec())
            {
                QStringList fileNames = dialog.selectedFiles();

                foreach(QString fileName, fileNames){
                    recFile.setFileName(fileName);

                    //判断文件是否存在
                    if(!recFile.exists())
                    {
                       qDebug() << "File does not exist, Creating file...";

                       //创建文件(以文本模式打开)
                       if(!recFile.open(QIODevice::ReadWrite | QIODevice::Text))
                       {
                           qDebug() << "Failed to open file for writing!" << endl;
                           return;
                       }
                    }
                    else
                    {
                        if(!recFile.open(QIODevice::Append | QIODevice::Text))
                        {
                            return;
                        }
                    }

                }
            }
            //取消文件路径选择
            else
            {
                //修改接收方式为不接收到文件
                isRecToFile = false;

                //清除勾选
                ui->chB_recToFile->setCheckState(Qt::CheckState::Unchecked);
            }
        }

        else if(isChecked == Qt::Unchecked)
        {
            //修改接收方式为不接收到文件
            isRecToFile = false;

            //关闭文件
            recFile.close();
        }
    });
	当用户勾选或取消勾选接收到文件时,会调用该槽函数,也就是:

在这里插入图片描述

		首先,判断用户是否时勾选,如果是勾选则弹出文件选择对框,此处调用的是
	dialog.exec()方法,当用户选择了文件并点击确定时会返回真值,之后改变是否接收
	到文件标志位并且判断该文件是否存在,如果不存在就创建文件,如果存在就直接
	打开文件。如果用户在文件选择对话框点击取消,那么dialog.exec()方法会返回假值,
	此时改变文件标志位为不接收到文件,并且清除勾选。
	也就是:
            //获取文件路径
            if(dialog.exec())
            {
                QStringList fileNames = dialog.selectedFiles();

                foreach(QString fileName, fileNames){
                    recFile.setFileName(fileName);

                    //判断文件是否存在
                    if(!recFile.exists())
                    {
                       qDebug() << "File does not exist, Creating file...";

                       //创建文件(以文本模式打开)
                       if(!recFile.open(QIODevice::ReadWrite | QIODevice::Text))
                       {
                           qDebug() << "Failed to open file for writing!" << endl;
                           return;
                       }
                    }
                    else
                    {
                        if(!recFile.open(QIODevice::Append | QIODevice::Text))
                        {
                            return;
                        }
                    }

                }
            }
            //取消文件路径选择
            else
            {
                //修改接收方式为不接收到文件
                isRecToFile = false;

                //清除勾选
                ui->chB_recToFile->setCheckState(Qt::CheckState::Unchecked);
            }
        }
		还有一种情况就是用户从勾选到取消勾选,那么就改变接收到文件标志位为false,
	即, isRecToFile = false; 并且关闭文件。
		else if(isChecked == Qt::Unchecked)
        {
            //修改接收方式为不接收到文件
            isRecToFile = false;

            //关闭文件
            recFile.close();
        }
	之后是清除显示按钮也就是:

在这里插入图片描述

	直接调用clear()函数即可。
	//链接清除显示
    connect(ui->pB_recClearDisplay, &QPushButton::clicked, this, [=](){
       ui->tE_receiveData->clear();
    });
	最后是保存数据,也就是将接收文本框显示的数据保存到文件当中去,和接收到文件的
过程也大差不差,首先获取文件路径,再判断文件是否存在,不存在则创建,存在则直接
打开,然后读取接收文本框的数据,将该数据输入到文件中去。
    //链接保存数据
    connect(ui->pB_recSaveData, &QPushButton::clicked, this, [=](){
        //创建获取文件路径对象
        QFileDialog dialog;

        //设置文件过滤器
        dialog.setNameFilter("Text files (*.txt);;All files (*)");

        //获取文件路径
        if(dialog.exec())
        {
            //获取文件路径
            QStringList fileNames = dialog.selectedFiles();

            //创建保存数据文件对象
            QFile saveFile;

            //创建文件
            foreach(QString fileName , fileNames)
            {
                saveFile.setFileName(fileName);

                //判断文件是否存在,不存在创建文件
                if(!saveFile.exists())
                {
                    //创建文件(以文本模式打开)
                    if(!saveFile.open(QIODevice::ReadWrite | QIODevice::Text))
                    {
                        qDebug() << "Failed to open file for writing!" << endl;
                        return;
                    }
                }
                //如果文件存在
                else
                {
                    if(!saveFile.open(QIODevice::Append | QIODevice::Text))
                    {
                        return;
                    }
                }
            }

            //获取需要保存的数据
            QString recEditdata = ui->tE_receiveData->toPlainText();

            //保存到文件
            QTextStream out(&saveFile);
            out << recEditdata;
        }

    });
	以上就是接收模块的全部代码,下面给出整个接收方法void Widget::mReceiveSet()
完整的代码。
//串口接收设置
void Widget::mReceiveSet()
{
    //链接串口接收槽函数
    connect(&mSerialPort, &QSerialPort::readyRead, this, [=](){
        //获取接收数据
        receivePrimaryData = mSerialPort.readAll();
        //qDebug() << receivePrimaryData << endl;

        //创建临时数据
        QByteArray receiveTemporaryData = receivePrimaryData;

        //存放16进制数据
        //QByteArray hexData = receivePrimaryData.toHex();

        //十六进制显示
        if(ui->chB_recDisplayHEX->isChecked() == true)
        {
            //将QByteArray转化为十六进制表示
            receiveTemporaryData = receiveTemporaryData.toHex().toUpper();

            //在每一个十六进制数之间插入空格
            for(int i = 2; i < receiveTemporaryData.size(); i += 3)
            {
                receiveTemporaryData.insert(i, ' ');
            }
        }

        //显示接收时间
        if(ui->chB_recDisplayTime->isChecked() == true)
        {
            //获取当前时间
            QDateTime currentTime = QDateTime::currentDateTime();
            QString timeString = currentTime.toString("yyyy-MM-dd HH:mm:ss");

            timeString = ("[" + timeString + "]");

            //添加时间戳
            receiveTemporaryData = timeString.append(receiveTemporaryData).toUtf8();
        }


        //接收显示不暂停,并且不接收到文件,则接收到接收文本框
        if(recDisplayIsPause == false && isRecToFile == false)
        {
            ui->tE_receiveData->append(receiveTemporaryData);
        }

        //不暂停显示并且接收到文件
        if(recDisplayIsPause == false && isRecToFile == true)
        {
            ui->tE_receiveData->append(receiveTemporaryData);

            QTextStream out(&recFile);
            out << receiveTemporaryData;
        }

        //暂停显示并且接收到文件
        if(recDisplayIsPause == true && isRecToFile == true)
        {
            QTextStream out(&recFile);
            out << receiveTemporaryData;
        }

    });


    //链接是否接收显示
    connect(ui->chB_recDisplayPause, &QCheckBox::stateChanged, this, [=](int isChecked){
        //如果勾选,暂停显示
        if(isChecked == Qt::Checked)
        {
            ui->tE_receiveData->setEnabled(false);
            //显示暂停
            recDisplayIsPause = true;
        }
        else if(isChecked == Qt::Unchecked)
        {
            ui->tE_receiveData->setEnabled(true);
            //继续显示
            recDisplayIsPause = false;
        }
    });

    //链接是否接收到文件,获取文件对象
    connect(ui->chB_recToFile, &QCheckBox::stateChanged, this, [=](int isChecked){
        if(isChecked == Qt::Checked)
        {
            //修改接收方式为接收到文件
            isRecToFile = true;

            //创建文件路径获取对象
            QFileDialog dialog;

            //设置文件过滤器(txt和所有文件)
            dialog.setNameFilter("Text files (*.txt);;All files (*)");

            //获取文件路径
            if(dialog.exec())
            {
                QStringList fileNames = dialog.selectedFiles();

                foreach(QString fileName, fileNames){
                    recFile.setFileName(fileName);

                    //判断文件是否存在
                    if(!recFile.exists())
                    {
                       qDebug() << "File does not exist, Creating file...";

                       //创建文件(以文本模式打开)
                       if(!recFile.open(QIODevice::ReadWrite | QIODevice::Text))
                       {
                           qDebug() << "Failed to open file for writing!" << endl;
                           return;
                       }
                    }
                    else
                    {
                        if(!recFile.open(QIODevice::Append | QIODevice::Text))
                        {
                            return;
                        }
                    }

                }
            }
            //取消文件路径选择
            else
            {
                //修改接收方式为不接收到文件
                isRecToFile = false;

                //清除勾选
                ui->chB_recToFile->setCheckState(Qt::CheckState::Unchecked);
            }
        }

        else if(isChecked == Qt::Unchecked)
        {
            //修改接收方式为不接收到文件
            isRecToFile = false;

            //关闭文件
            recFile.close();
        }
    });


    //链接清除显示
    connect(ui->pB_recClearDisplay, &QPushButton::clicked, this, [=](){
       ui->tE_receiveData->clear();
    });

    //链接保存数据
    connect(ui->pB_recSaveData, &QPushButton::clicked, this, [=](){
        //创建获取文件路径对象
        QFileDialog dialog;

        //设置文件过滤器
        dialog.setNameFilter("Text files (*.txt);;All files (*)");

        //获取文件路径
        if(dialog.exec())
        {
            //获取文件路径
            QStringList fileNames = dialog.selectedFiles();

            //创建保存数据文件对象
            QFile saveFile;

            //创建文件
            foreach(QString fileName , fileNames)
            {
                saveFile.setFileName(fileName);

                //判断文件是否存在,不存在创建文件
                if(!saveFile.exists())
                {
                    //创建文件(以文本模式打开)
                    if(!saveFile.open(QIODevice::ReadWrite | QIODevice::Text))
                    {
                        qDebug() << "Failed to open file for writing!" << endl;
                        return;
                    }
                }
                //如果文件存在
                else
                {
                    if(!saveFile.open(QIODevice::Append | QIODevice::Text))
                    {
                        return;
                    }
                }
            }

            //获取需要保存的数据
            QString recEditdata = ui->tE_receiveData->toPlainText();

            //保存到文件
            QTextStream out(&saveFile);
            out << recEditdata;
        }

    });

}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值