Qt5開發串口助手+自定義報文回覆

一、功能目標

1、windows/linux-Ubuntu下串口信息收發(ASCII/HEX)

2、串口相關參數可配置,打開端口後實時生效

3、端口信息根據系統COM口事實刷新3

4、定時自動重發

5、自動換行,log顯示接收時間

6、自定義報文自動回覆(用來與“握手”協議和“心跳”協議對接)

源碼下載請移步https://download.csdn.net/download/white_loong/11933343

可執行文件下載:https://download.csdn.net/download/white_loong/11934068

基本界面如下

開發環境ubuntu14.0.0+Qt 5.9.7、WIN10-64

二、實現(主要以Ubuntu爲主,win10相對簡單可直接移植)

1、查看串口方法

虛擬機加載可移動設備:虛擬機---》可移動設備----》需要加載的串口linux

linux查看串口 這篇博客比較詳細: https://blog.csdn.net/uncle_guo/article/details/80867169

2、建立Qt工程,獲取串口信息

使用的時候在 pro 添加這句導入模塊 QT += serialport

添加串口頭文件

#include <QtSerialPort/QSerialPort>
#include <QtSerialPort/QSerialPortInfo>

3、功能1實現  串口信息收發(ASCII/HEX)

MainWindow添加私有變量

    QSerialPort  *myCom;

打卡串口相關操作

void MainWindow::opencom()
{

    myCom = new QSerialPort("/dev/ttyS0");  //實例化
    if (myCom->isOpen())                    //串口是否打開?
    {
        myCom->clear();
        myCom->close();
        qDebug()<<"Serial port is closed";
    }
    myCom->open(QIODevice::ReadWrite);      //以讀寫方式打開串口
    if(myCom ->isOpen()){                   //串口打開成功,設置參數
        qDebug()<<"open serial success";
        on_BaudRateBox_currentIndexChanged(ui->BaudRateBox->currentIndex());
        on_DataBitsBox_currentIndexChanged(ui->DataBitsBox->currentIndex());
        on_ParityBox_currentIndexChanged(ui->ParityBox->currentIndex());
        on_stopbitBox_currentIndexChanged(ui->stopbitBox->currentIndex());
        on_flowBox_currentIndexChanged(ui->flowBox->currentIndex());
        connect(myCom,SIGNAL(readyRead()),this,SLOT(slotReadReady()));
        //連接信號槽 當下位機發送數據QSerialPortInfo 會發送個 readyRead 信號,我們定義個槽void receiveInfo()解析數據
        ui->opencom->setText("close");
    }else{
        qDebug()<<"open serial fail";
    }
}

關閉串口相關操作

void MainWindow::closecom()
{
    if (myCom->isOpen())  
    {
        myCom->clear();
        myCom->close();
        myCom->deleteLater();
        qDebug()<<"Serial port is closed";
        delete myCom;
        ui->opencom->setText("open");
    }
}

串口接收信息

void MainWindow::slotReadReady()
{
     QString buf;
     if(ui->RXhexradioButton->isChecked())    //hex格式接收
     {
        buf = myCom->readAll().toHex()+ "\n";
        forresp(buf);
        qDebug()<<"buf"<<buf;
     }else{                                   //ASCII格式接收
        buf = myCom->readAll();
     }
     if (!buf.isEmpty()){
          reNum += buf.size();
          QString str = ui->rxtext->toPlainText();
          str = str + LogTime + "\n"+ buf+"\n";   //LogTime 爲系統時間
          ui->rxtext->clear();
          ui->rxtext->append(str);
          ui->label_rxnum->setText("Rx:"+QString::number(reNum, 10)); //顯示發送字符數量
      }
     buf.clear();
}

串口發送信息

void MainWindow::on_sendpushButton_clicked()
{
    QString buf ;
    QByteArray sendBuf;

    if(ui->TXhexradioButton->isChecked()){      //hex格式發送
        buf = ui->txtext->toPlainText().replace(QString(" "),QString(""));
        convertStringToHex(buf, sendBuf);
    }else{                                     //ascii格式發送
       buf = ui->txtext->toPlainText();
       sendBuf = buf.toLatin1();
    }

    seNum = seNum + sendBuf.length();
    myCom->write(sendBuf);                      //串口發送 
    ui->label_txnum->setText("Rx:"+QString::number(seNum, 10)); //發送字符數量
    qDebug()<<"txnum"<<seNum;

    if(ui->txcomboBox->findText(buf)<0)          //發送歷史緩存
    {
       ui->txcomboBox->addItem(buf);
    }
    if(ui->txcheckBox->isChecked()){            //發送回顯
        QString str = ui->rxtext->toPlainText();
        if(ui->TXhexradioButton->isChecked()){
            str = str + LogTime + "\n"  + sendBuf.toHex() + "\n";
        }else{
            str = str + LogTime + "\n"  + sendBuf + "\n";
        }

        ui->rxtext->clear();
        ui->rxtext->append(str);
    }
}

4、功能2  串口相關參數可配置,打開端口後實時生效

以波特率爲例,其他參數類推即可

void MainWindow::on_BaudRateBox_currentIndexChanged(int index)
{
    if(switchflag)             //switchflag用來判斷串口是否打開
    {
        switch(index)            
        {
           case 0:
                myCom->setBaudRate(QSerialPort::Baud9600);
                break;
           case 1:
                myCom->setBaudRate(QSerialPort::Baud19200);
                break;
           case 2:
                myCom->setBaudRate(QSerialPort::Baud38400);
                break;
           case 3:
                myCom->setBaudRate(QSerialPort::Baud115200);
                break;
          default:
                myCom->setBaudRate(QSerialPort::Baud9600);
                break;
        }
   }
}

5、功能3 端口信息根據系統COM口事實刷新

使用foreach每5s獲取一次串口信息,並刷新界面,打開串口時根據combobox值確定

foreach用法參考:https://www.cnblogs.com/lomper/p/3959771.html

void MainWindow::updateiu()
{
    static QString lastComName,curComName;
    static QStringList portName;
    //讀取串口信息
    foreach (const QSerialPortInfo &info, QSerialPortInfo::availablePorts())
    {
         portName += info.portName();
    }
      curComName = portName.join(",");
      if(QString::compare(lastComName,curComName)){  //如果同上次獲取的串口信息有差異則刷新
        ui->comname->clear();
        lastComName = curComName;
        ui->comname->addItems(portName);
     }
      curComName.clear();
      portName.clear();
}


//啓動定時器添加頭文件
#include <QTimer>
#include <QTime>

fTimer,on_timer_timeout()需在類中聲明

//初始化界面添加
fTimer=new QTimer(this);
fTimer->setInterval (50) ;//設置定時週期,單位:毫秒
fTimer->start();
connect(fTimer,SIGNAL(timeout()),this,SLOT(on_timer_timeout()));

//定時器溢出處理
void MainWindow::on_timer_timeout()
{
    //定時器中斷響
 //  qDebug()<<"Enter timeout processing function\n";
   if(fTimer->isActive()){
       fTimer->stop();

       updateiu();
       fTimer->setInterval (5000) ;
       fTimer->start();
   }
}

6、功能4 定時自動重發

根據自動重發控件狀態啓動或關閉定時器

void MainWindow::on_autosendBox_pressed()
{
    if(ui->autosendBox->isChecked()){
        if(sendinterval->isActive()) {
           sendinterval->stop();
         }
    }else{
       sendinterval->setInterval(ui->txtimespinBox->value()) ;//設置定時週期,單位:毫秒
       sendinterval->start();
       connect(sendinterval,SIGNAL(timeout()),this,SLOT(on_sendpushButton_clicked()));
    }
}

7、功能5  log顯示接收時間

獲取系統時間,添加頭文件#include <qdatetime.h>

void MainWindow::real_timer()
{
    QDateTime  timeNow=QDateTime::currentDateTime();
    QString str = timeNow.toString("MM-dd hh:mm:ss dddd");
    ui->lable_time->setText(str);
    LogTime = timeNow.toString("MM-dd hh:mm:ss");   //LogTime 爲全局變量,在顯示時添加即可
}

8、功能6 自定義報文自動回覆(用來與“握手”協議和“心跳”協議對接)

接收到固定報文後,根據用戶自定義信息自動回覆相應信息

比如    串口             發送0x23 --------------》設備

                               0x45 《--------------設備回覆

收到0x45 回覆0xc0  0x00 0xc0------------------》設備

                                  0x67 《--------------設備回覆

                      收到0x67 回覆0x89------------------》設備

思路:使用ListWidget存儲固定報文和響應信息,可以手動增加刪除,專有按鍵管理啓動關閉此功能

//list ack fromat
//RECV+2*~~+recv.len(XX)+2*~~+recv  len<99
//2*~~ + RESP+2*~~+resp.len+2*~~+resp
//新增自定義報文
void MainWindow::on_addpushButton_clicked()
{
    QString buf,buf1;
    buf = ui->recvtextEdit->toPlainText().replace(QString(" "),QString(""));
    buf1= ui->resptextEdit->toPlainText().replace(QString(" "),QString(""));
    buf = "RECV  "+ QString::number(buf.length()) +"  "+ buf ;
    buf1= "  RESP  "+QString::number(buf1.length()) +"  "+buf1;
    ui->listWidget->addItem(buf);
    ui->listWidget->addItem(buf1);
    listnum++;
    qDebug()<<"add list"<<listnum;
}
//刪除自定義報文
void MainWindow::on_deletepushButton_clicked()
{
    if(ui->listWidget->currentItem() != Q_NULLPTR){
       int i=  i=ui->listWidget->currentRow();;
        QString  test = ui->listWidget->item(ui->listWidget->currentRow())->text();
       if(test.indexOf("RECV")<0) {
          i=ui->listWidget->currentRow()-1;
       }
          else{
           i=ui->listWidget->currentRow();
       }
       QListWidgetItem *item1 = ui->listWidget->takeItem(i+1);
       QListWidgetItem *item = ui->listWidget->takeItem(i);
       delete item1;
       delete item;

       if(listnum)    listnum--;
    }
    qDebug()<<"delete list"<<listnum;
}
//啓動、關閉
void MainWindow::on_startpushButton_clicked()
{
    if(startorclose){
      //free time stop
       startorclose  = 0;
       ui->startpushButton->setText("start");
    }else{
      //start time start
        ui->startpushButton->setText("stop");
        ui->RXhexradioButton->setChecked(1);
        startorclose = 1;
    }
}
//響應,此函數在接收響應函數調用
//解析對比報文,迴應
void MainWindow::forresp(const QString &buff)
{
    qDebug()<<"buff"<<buff.toLatin1();
    if(listnum == 0 || startorclose ==0 ) return;
    QString itemText,resp;
    int recvlen,index=9,resplen,index1=10;
    for (int j = 0; j < ui->listWidget->count(); j=j+2)
    {
        index=9;
        index1=11;
        itemText = ui->listWidget->item(j)->text();
        recvlen = itemText.mid(6,2).toInt();
        if(recvlen>9) index = index+1;
        QString recv = itemText.mid(index,recvlen)+"\n";
        if(!QString::compare(recv,buff)){
            qDebug()<<"ok";
            ui->listWidget->item(j)->setBackgroundColor(255);

            resp = ui->listWidget->item(j+1)->text();
            resplen = resp.mid(8,2).toInt();
            if(resplen>9) index1 = index1+1;
            resp = resp.mid(index1,resplen);
            QByteArray sendBuf;
            convertStringToHex(resp, sendBuf);
            myCom->write(sendBuf);

            QString str = ui->rxtext->toPlainText();
            str = str + LogTime + "  autoresponse "+ "\n"  + resp + "\n";
            ui->rxtext->clear();
            ui->rxtext->append(str);
        }

    }

}

效果如下圖:log有autoresponse即爲自動回覆報文,藍色部分表示收到報文對比通過,立即發送下方響應報文

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章