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即为自动回复报文,蓝色部分表示收到报文对比通过,立即发送下方响应报文

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值