小工具--串口

Posted whitewn

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了小工具--串口相关的知识,希望对你有一定的参考价值。

功能实现:

  1. 接收串口数据;

  2.保存接收数据到TXT文档,主要是测试串口接收到数据,给python进行处理时的小应用(个人使用),避免长时间测试数据丢失的问题

  3.发送串口数据;

  4.发送文件;

小细节:

   1.串口没有打开之前,不能进行发送数据等操作,需要在发送槽函数中进行判断串口是否打开;

  2.串口刷新监测;

   3.串口发送框允许输入的字符a-f ,A-F,0-9,以及空格符,正则表达式的运用以及过滤器QValidator的使用;

   4.接收框显示,发送数据什么格式,接收数据什么格式;

代码:

#include "serialportqmain.h"
#include "ui_serialportqmain.h"

#include <QFileDialog>
#include<QMessageBox>
#include<QTextStream>
#include<QDebug>
#include <QRegExp>
#include<QValidator>
#include<QSizePolicy>

#include <QComboBox>
#include <QTimer>
#include<QDateTime>
SerialPortQMain::SerialPortQMain(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::SerialPortQMain)
{
    ui->setupUi(this);

    initSerial();
    //recv
    connect(ui->pushButton_Open,&QPushButton::clicked,this,&SerialPortQMain::slot_on_openSerial_clicked);
    connect(ui->pushButton_SaveRecv,&QPushButton::clicked,this,&SerialPortQMain::slot_on_saveRecvBtn_clicked);
    connect(ui->pushButton_ClearRecv,&QPushButton::clicked,this,&SerialPortQMain::slot_on_clearRecvBtn_clicked);
    //send
    connect(ui->pushButton_Send,&QPushButton::clicked,this,&SerialPortQMain::slot_on_sendBtn_clicked);
    connect(ui->pushButton_ClearSend,&QPushButton::clicked,this,&SerialPortQMain::slot_on_clearSendBtn_clicked);
    connect(ui->pushButton_OpenFile,&QPushButton::clicked,this,&SerialPortQMain::slot_on_openFileBtn_clicked);
    connect(ui->pushButton_SendFile,&QPushButton::clicked,this,&SerialPortQMain::slot_on_sendFileBtn_clicked);
    connect(ui->pushButton_StopSend,&QPushButton::clicked,this,&SerialPortQMain::slot_on_stopSend_clicked);//停止发送文件

    //输入自定义波特率
    connect(ui->comboBoxBaudRate, SIGNAL(currentIndexChanged(const QString &)), this, SLOT(slot_on_baudRate(const QString &)));

    //周期发送
    connect(ui->checkBox_SendRegular,&QCheckBox::stateChanged,this,&SerialPortQMain::slot_on_periodSendCheckSelect);
    connect(ui->checkBox_Send,&QCheckBox::stateChanged,this,&SerialPortQMain::slot_on_StrOrHex);
}

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

 void SerialPortQMain::slot_on_refreshCurrentTime()
 {
     currentTime=QTime::currentTime();
     strTime= currentTime.toString("HH:mm");
     currentDate =QDate::currentDate();
     strDate = currentDate.toString("yyyy-MM-dd dddd");
     strDate.append(strTime);
     currenttimeDisplay->setText("当前时间:"+strDate);
 }

/*串口初始化*/
void SerialPortQMain::initSerial()
{
    /*查找可用串口*/
    foreach(const QSerialPortInfo &info, QSerialPortInfo::availablePorts())
    {
        QSerialPort serialPort ;
        serialPort.setPort(info);
        if(serialPort.open(QIODevice::ReadWrite))
        {
            ui->comboBoxSerial->addItem(serialPort.portName());
            serialPort.close();
        }
    }
    //设置波特率下拉菜单默认显示第三项
    ui->comboBoxBaudRate->setCurrentIndex(3);

    //statusbar
    operateState = new QLabel;
    ui->statusBar->addPermanentWidget(operateState,1);
    operateState->setText("当前操作状态:"+operateStateChange);
    operateState->setFixedSize(200,20);

    currenttimeDisplay=new QLabel;
    ui->statusBar->addPermanentWidget(currenttimeDisplay,3);

    timerPeriodSend = new QTimer(this);  //周期发送数据定时器

    refreshSerialTimer = new QTimer(this);//刷新串口定时器
    connect(refreshSerialTimer, SIGNAL(timeout()), this, SLOT(slot_on_refreshComPort())); //定时刷新串口
    refreshSerialTimer->start(1000);

    currentTimer=new QTimer(this);
   connect(currentTimer, SIGNAL(timeout()), this, SLOT(slot_on_refreshCurrentTime())); //定时刷新串口
   currentTimer->start(1000);

    //发送输入规则
    QRegExp exp("[A-Fa-f0-9\\s][A-Fa-f0-9\\s]+$");
    QValidator *validator = new QRegExpValidator(exp,ui->lineEditSend);
    ui->lineEditSend->setValidator(validator);
}
/*刷新串口*/
void SerialPortQMain::slot_on_refreshComPort()
{
    ui->comboBoxSerial->clear(); //每次将之前信息监测到的串口删除,重新扫描
    foreach(const QSerialPortInfo &info, QSerialPortInfo::availablePorts())
    {
        QSerialPort serialPort ;
        serialPort.setPort(info);

        if(serialPort.open(QIODevice::ReadWrite))
        {
            ui->comboBoxSerial->addItem(serialPort.portName());
            serialPort.close();
        }
    }
}

/*操作清除接收窗口按钮*/
void SerialPortQMain::slot_on_clearRecvBtn_clicked()
{
    ui->textEditRecv->clear();
}
/*操作保存接收窗口按钮*/
void SerialPortQMain::slot_on_saveRecvBtn_clicked()
{
    QString fileName = QFileDialog::getSaveFileName(this, tr("Save File"),
                                                    "/home",
                                                    tr("Text (*.txt *.*)"));
    if(fileName !="") //不为空
    {
        QFile saveFile(fileName);
        if(!saveFile.open(QIODevice::WriteOnly))
        {
            //操作提示
            operateStateDisplay("保存文件失败!");

            QMessageBox::about(this,"操作","操作错误");
        }
        else{
            QTextStream stream(&saveFile);
            stream<<ui->textEditRecv->toPlainText();
            stream.flush();
            saveFile.close();
        }
    }
}
/*操作打开串口按钮*/
void SerialPortQMain:: slot_on_openSerial_clicked()
{
    if(ui->pushButton_Open->text() == tr("打开串口"))
    {
        //若串口已经打开则不再继续刷新串口
        refreshSerialTimer->stop();

        serialPort = new QSerialPort;
        //设置串口名
        serialPort->setPortName(ui->comboBoxSerial->currentText());
        //打开串口模式
        serialPort->open(QIODevice::ReadWrite);
        //设置波特率
        serialPort->setBaudRate(ui->comboBoxBaudRate->currentText().toInt());
        //设置数据位
        switch (ui->comboBoxDataBit->currentIndex()) {
        case 8:serialPort->setDataBits(QSerialPort::Data8); break;
        case 7:serialPort->setDataBits(QSerialPort::Data7); break;
        default:
            break;
        }

        //设置奇偶校验位
        switch (ui->comboBoxOdd->currentIndex()) {
        case 0:serialPort->setParity(QSerialPort::NoParity); break;
        case 2:serialPort->setParity(QSerialPort::EvenParity);break;
        case 3:serialPort->setParity(QSerialPort::OddParity);break;
        case 4:serialPort->setParity(QSerialPort::SpaceParity);break;
        case 5:serialPort->setParity(QSerialPort::MarkParity);break;
        default:
            break;
        }

        //设置停止位
        switch(ui->comboBoxStopBit->currentIndex())
        {

        case 1: serialPort->setStopBits(QSerialPort::OneStop); break;
        case 2: serialPort->setStopBits(QSerialPort::TwoStop); break;
        case 3: serialPort->setStopBits(QSerialPort::OneAndHalfStop); break;
        default: break;
        }
        //设置流控制
        serialPort->setFlowControl(QSerialPort::NoFlowControl);
        ui->pushButton_Open->setText(tr("关闭串口"));
        ui->pushButton_Open->setStyleSheet("background: lightgreen");

        //操作提示
        operateStateDisplay("打开串口成功!");

        if(ui->lineEdit_SaveRecv->text() != "") {
            save_TxtName = ui->lineEdit_SaveRecv->text();

            QFile recvfliesave(QString("./%1.txt").arg(save_TxtName));
            if(!recvfliesave.open(QFile::WriteOnly|QIODevice::Truncate|QIODevice::Text) )
            {
                QMessageBox::warning(this,"提示","文件创建失败");
                createTXTEnable = false;
            }
            else{
                createTXTEnable = true;
            }
        }
        else
        {
            QMessageBox::warning(this,"提示","没有填写保存文件名称,可跳过;说明只显示,不保存");
        }

        isOpenSerial =true;

        //串口打开后,连接接收
        connect(serialPort,&QSerialPort::readyRead,this,&SerialPortQMain::slot_on_recvOperate,Qt::QueuedConnection);
    }
    else{
        serialPort->close();
        isOpenSerial=false;
        ui->pushButton_Open->setText(tr("打开串口"));
        ui->pushButton_Open->setStyleSheet("background:#e8e8e8");
        //操作提示
        operateStateDisplay("串口关闭!");
    }

}
/*接收数据,在接收区显示数据*/
void SerialPortQMain::slot_on_recvOperate()
{
    QByteArray readDataBuff(1024,0);
    static QByteArray buff;
    if(serialPort->bytesAvailable())
    {
        //操作提示
        operateStateDisplay("正在接收数据...");
        readDataBuff= serialPort->readAll();
        buff.append(readDataBuff);


        if(createTXTEnable)  //  允许写入Txt
        {
            writeRecvDataToTXT(buff);
        }

        //接收区显示
        if(ui->checkBox_RecvHex->checkState() == Qt::Unchecked){
            ui->textEditRecv->insertPlainText(QString(buff));
        }
        else if(ui->checkBox_RecvHex->checkState() == Qt::Checked)
            ui->textEditRecv->insertPlainText(buff.toHex());
        buff.clear(); //每次接收完成要清除;
    }
    //操作提示
    operateStateDisplay("数据接收完成!");
}

//接收内容写入TXT
void SerialPortQMain::writeRecvDataToTXT(QByteArray data)
{
    QFile recvfliesave(QString("./%1.txt").arg(save_TxtName));
    if(recvfliesave.open(QFile::WriteOnly|QFile::Append)){
        recvfliesave.write(data);
    }
}

//发送端操作
/*发送数据*/
void SerialPortQMain::slot_on_sendBtn_clicked()
{
    if(!isOpenSerial)
    {
        QMessageBox::warning(this,"提示","串口没有打开!");
        return ;
    }
    slot_on_StrOrHex();
    serialPort->write(sendData);
}

//发送str 或者hex
void SerialPortQMain::slot_on_StrOrHex()
{
    if(ui->checkBox_Send->checkState() == Qt::Unchecked) //没有选中,说明 发送字符
    {
        sendData= ui->lineEditSend->text().toLatin1();
        ui->lineEditSend->setText(ui->lineEditSend->text());
    }
    else if(ui->checkBox_Send->checkState() == Qt::Checked)
    {
        StringToHex(ui->lineEditSend->text(),sendData);
        ui->lineEditSend->setText(ui->lineEditSend->text());
    }
}

//周期发送
void SerialPortQMain::slot_on_periodSendCheckSelect()
{
    int period = ui->lineEdit_time->text().toInt();

    if(ui->checkBox_SendRegular->checkState() == Qt::Checked)  //选中
    {

       timerPeriodSend->start(period);
        connect(timerPeriodSend, SIGNAL(timeout()), this, SLOT(slot_on_sendBtn_clicked())); //定时刷新串口

        ui->lineEdit_time->setEnabled(false);
    }
    else if(ui->checkBox_SendRegular->checkState() == Qt::Unchecked) //没选中
    {
        timerPeriodSend->stop();
        ui->lineEdit_time->setEnabled(true);
    }
}

/*打开文件*/
void SerialPortQMain::slot_on_openFileBtn_clicked()
{
    QString fileName = QFileDialog::getOpenFileName(this, tr("Open File"),
                                                    "/home",
                                                    tr("Text (*.txt *.*)"));
    ui->lineEdit_FilePath->setText(fileName);
    txtSendFilePathName = ui->lineEdit_FilePath->text();
    qDebug()<<txtSendFilePathName;
}

/*发送文件*/
void SerialPortQMain::slot_on_sendFileBtn_clicked()
{
    if(!isOpenSerial)
    {
        QMessageBox::warning(this,"提示","串口没有打开!");
        return ;
    }

    if(txtSendFilePathName!="")
    {
        QFile fileexample(txtSendFilePathName);
        if(!fileexample.open(QIODevice::ReadOnly))
            return ;

        while (!fileexample.atEnd()) {
            QByteArray line = fileexample.readLine();
            serialPort->write(line);
            //操作提示
            operateStateDisplay( "正在发送文件...");
            int p = fileexample.pos()/fileexample.size() *100;
            ui->progressBar_SendFile->setValue(p );
        }
        QMessageBox::warning(this,"提示","发送完成!");
        ui->progressBar_SendFile->setValue(0);
        //操作提示
        operateStateDisplay("文件发送完成...");
    }
    else{
        QMessageBox::warning(this,"提示","请先选择要发送文件!");
    }
}

//停止发送文件
void SerialPortQMain::slot_on_stopSend_clicked()
{

}

/*清空发送区*/
void SerialPortQMain::slot_on_clearSendBtn_clicked()
{
    ui->lineEditSend->clear();
}

//statebar显示
QString SerialPortQMain::operateStateDisplay(QString operateStateChange)
{
    ui->statusBar->addWidget(operateState);
    operateState->setText("当前操作状态:"+operateStateChange);
    return operateStateChange;
}

//自定义波特率
void SerialPortQMain::slot_on_baudRate(const QString &text)
{
    if(text == "custom")
    {
        ui->comboBoxBaudRate->setEditable(true);
    }
    else{
        ui->comboBoxBaudRate->setEditable(false);
    }
}

////////////////////////
void SerialPortQMain::StringToHex(QString str,QByteArray &senddata)
{
    int hexdata,lowhexdata;
    int hexdatalen = 0;
    int len = str.length();
    senddata.resize(len/2);
    char lstr,hstr;
    for(int i=0; i<len; )
    {
        //char lstr,
        hstr=str[i].toLatin1();
        if(hstr ==  )
        {
            i++;
            continue;
        }
        i++;
        if(i >= len)
            break;
        lstr = str[i].toLatin1();
        hexdata = ConvertHexChar(hstr);
        lowhexdata = ConvertHexChar(lstr);
        if((hexdata == 16) || (lowhexdata == 16))
            break;
        else
            hexdata = hexdata*16+lowhexdata;
        i++;
        senddata[hexdatalen] = (char)hexdata;
        hexdatalen++;
    }
    senddata.resize(hexdatalen);
}

char SerialPortQMain::ConvertHexChar(char ch)
{
    if((ch >= 0) && (ch <= 9))
        return ch-0x30;
    else if((ch >= A) && (ch <= F))
        return ch-A+10;
    else if((ch >= a) && (ch <= f))
        return ch-a+10;
    else return (-1);


}

 

以上是关于小工具--串口的主要内容,如果未能解决你的问题,请参考以下文章

小工具--串口

日常生活小技巧 -- 虚拟串口工具

串口调试小工具

VS中添加自定义代码片段——偷懒小技巧

提效小技巧——记录那些不常用的代码片段

WPF实用小工具