• <noscript id="e0iig"><kbd id="e0iig"></kbd></noscript>
  • <td id="e0iig"></td>
  • <option id="e0iig"></option>
  • <noscript id="e0iig"><source id="e0iig"></source></noscript>
  • QT實現串口調試助手(二)

    標簽: C++  QT  嵌入式  qt  串口通信  c++

    一、導入庫


    1、在項目.pro文件中加入serialport

    QT       += core gui
    QT       += serialport

    2、引入qt中串口通信需要的頭文件

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

    二、配置串口初始化

    1、查找可用的串口。

    通過創建一個comobox,將可用串口的列表展示出來,并用于配置時選擇要連接的串口

    //查找可用串口,刷新串口信息
    void MainWindow::GetAveriablePort()
    {
         ui->uartReadPlain->insertPlainText("串口初始化:\r\n");
    
         //先清除所有串口列表
          ui->portBox->clear();
    
        foreach(const QSerialPortInfo &info,QSerialPortInfo::availablePorts())
        {
            QSerialPort serial;
            serial.setPort(info);
    
            if(serial.open(QIODevice::ReadWrite))
            {
                ui->uartReadPlain->insertPlainText("可用:"+serial.portName()+"\r\n");
                ui->portBox->addItem(serial.portName());
                serial.close();
            }
            else
            {
                ui->uartReadPlain->insertPlainText("不可用:"+serial.portName()+"\r\n");
            }
        }
    }

     

    2、配置串口。

    (1)串口的配置至少應當包含串口號、波特率、數據位、停止位、奇偶校驗位、流控,這些都可以通過串口實例調用函數配置。可以加入幾個comobox或者文本框來選擇,也可以默認初始化時就配好。

    //配置串口初始化
    void MainWindow::PortConfigureInit()
    {
        //填入串口選項
        ui->rateBox->addItem("115200","115200");
        ui->rateBox->addItem("38400","38400");
        ui->rateBox->addItem("19200","19200");
        ui->rateBox->addItem("9600","9600");
    
        ui->dataBox->addItem("8",8);
        ui->dataBox->addItem("7",7);
    
        ui->checkBox->addItem("無校驗",0);
    
        ui->stopBox->addItem("1位",1);
        ui->stopBox->addItem("2位",2);
    
    }

    (2)加入一個打開關閉串口的按鈕,文本顯示“打開串口”時,點擊可以關閉串口。文本顯示“關閉串口“則相反。
    (3)打開串口時,把配置的項的box都disable,使其不可修改,關閉時恢復

    //串口開關按鈕
    void MainWindow::on_openSerialButton_clicked()
    {
        //嘗試打開串口
        if(ui->openSerialButton->text() == tr("打開串口"))
        {
            if(ui->portBox->currentText() == "" )
            {
                QMessageBox::warning(NULL, "警告", "無可開啟串口!\r\n\r\n");
                return;
            }
    
            serial = new QSerialPort;
            //設置串口名
            serial->setPortName(ui->portBox->currentText());
            //打開串口
            serial->open(QIODevice::ReadWrite);
            //設置波特率
            serial->setBaudRate(ui->rateBox->currentText().toInt());
            //設置數據位
            switch (ui->dataBox->currentData().toInt())
            {
                case 8:
                    serial->setDataBits(QSerialPort::Data8);
                    break;
                case 7:
                    serial->setDataBits(QSerialPort::Data7);
                    break;
                default:
                    break;
            }
            //設置校驗位
            switch (ui->checkBox->currentIndex())
            {
                case 0:
                    serial->setParity(QSerialPort::NoParity);
                    break;
                default:
                    break;
            }
            //設置停止位
            switch(ui->stopBox->currentIndex())
            {
                case 0:
                    serial->setStopBits(QSerialPort::OneStop);
                    break;
                case 1:
                    serial->setStopBits(QSerialPort::TwoStop);
                    break;
                default:
                    break;
            }
            //設置流控制
            serial->setFlowControl(QSerialPort::NoFlowControl); //設置為無流控制
    
            //關閉設置菜單使能
            ui->portBox->setEnabled(false);
            ui->dataBox->setEnabled(false);
            ui->checkBox->setEnabled(false);
            ui->stopBox->setEnabled(false);
            ui->rateBox->setEnabled(false);
            ui->openSerialButton->setText("關閉串口");
    
            fTimeCounter.restart();  //計時器重新計數
    
            //連接信號和槽函數,串口有數據可讀時,調用ReadData()函數讀取數據并處理。
            QObject::connect(serial,&QSerialPort::readyRead,this,&MainWindow::ReadData);
        }
        else
        {
            uartRecDataTimer->stop () ; //定時器停止
    
            if(serial->isOpen())       //原先串口打開,則關閉串口
            {
                serial->close();
            }
    
            //釋放串口
            delete serial;
            serial = NULL;
    
            //恢復使能
            ui->portBox->setEnabled(true);
            ui->rateBox->setEnabled(true);
            ui->dataBox->setEnabled(true);
            ui->checkBox->setEnabled(true);
            ui->stopBox->setEnabled(true);
            ui->openSerialButton->setText("打開串口");
        }
    }
    

    三、讀取串口數據

    1、為了讀取數據,要創建一個定時器和一個計時器。因為要解決2個問題,一是我們需要一個超時間隔,用于在串口一定時間收不到數據時,判斷一次接收完成,處理數據并清空buff。二是需要一個計數,統計串口已經連續接收了多久,即使數據一直不斷,我們也要在一個固定時時間點強制判斷一次接收完成,處理數據并清空buff,否則可能會導致數據永遠得不到處理。

    1、初始化定時器

        //設置uart接收緩沖超時定時器
        uartRecDataTimer = new QTimer(this);
        uartRecDataTimer->stop();
        uartRecDataTimer->setInterval(uartRecOvertimeCount*1000);                     //設置定時周期,單位:毫秒
        uartRecDataTimer->setSingleShot(true);                                        //設置為單次觸發
        connect(uartRecDataTimer,SIGNAL(timeout()),this,SLOT(uartRec_timeout()));     //設置槽

    2、實現ReadData。在計時器超出一個指定間隔后,強制處理已經接收完的buff緩沖,其余時間則是把數據放進緩沖中,重啟定時器

    //讀取串口接收消息
    void MainWindow::ReadData()
    {
        //串口可讀數據長度
        int byteLen = serial->bytesAvailable();
        if(byteLen < 0)
        {
            return;
        }
    
        rec_buf_len += byteLen;
        uart_rec_ss.append(serial->readAll());  //讀取數據
    
        //計時器超過最大間隔仍未填入數據,強制填入
        if(fTimeCounter.elapsed() >2000 && uart_rec_ss.size()>0)
        {
            ui->uartReadPlain->moveCursor(QTextCursor::End);        //光標移動到結尾
            ui->uartReadPlain->insertPlainText(uart_rec_ss);
            ui->uartReadPlain->moveCursor(QTextCursor::End);        //光標移動到結尾
            uart_rec_ss.clear();
        }
    
        //定時器開始工作、定時器重啟
        uartRecDataTimer->start();
    }

    3、定時器接收完成處理(一段時間沒有數據接收,定時器超時)

    根據時間戳是否被選擇,將數據內容做填充,插入到存放數據的文本框里

    //定時器觸發打印串口數據
    void MainWindow::uartRec_timeout()
    {
        if(!uart_rec_ss.isEmpty())
        {
            curDateTime = QDateTime::currentDateTime();
            ui->uartReadPlain->moveCursor(QTextCursor::End);            //光標移動到結尾
    
            if(ui->timeZoneCheckBox->isChecked())
            {
                ui->uartReadPlain->insertPlainText("\r\n"+curDateTime.toString("[yyyy-MM-dd hh:mm:ss]")+"R:");
                ui->uartReadPlain->moveCursor(QTextCursor::End);        //光標移動到結尾
                ui->uartReadPlain->insertPlainText(uart_rec_ss);
            }
            else
            {
                ui->uartReadPlain->insertPlainText(uart_rec_ss);
            }
            ui->uartReadPlain->moveCursor(QTextCursor::End);            //光標移動到結尾
            uart_rec_ss.clear();
            fTimeCounter.restart();
            ui->RXLenLabel->setText(QString::number(rec_buf_len)+"bytes");
        }
    }
    

    4、同時,我們需要一個配置超時間隔的選項

    (1)初始化時加入一個配置框

        //設置時間輸入框只允許使用數字
        ui->overTimeRecEdit->setValidator(new QRegExpValidator(QRegExp("^([0-9]{1,4}(.[0-9]{1,3})?)$")));
        ui->overTimeRecEdit->setText(QString::number(uartRecOvertimeCount));

    (2)運行中配置超時間隔

    //超時間隔設置
    void MainWindow::on_overTimeRecEdit_returnPressed()
    {
        if(ui->overTimeRecEdit->text().toFloat()>60)
        {
            QMessageBox::warning(NULL,"警告","超時時間不要超過1分鐘");
            ui->overTimeRecEdit->setText("0.1");
            return;
        }
        uartRecOvertimeCount = ui->overTimeRecEdit->text().toFloat();
        ui->uartReadPlain->insertPlainText("設置超時時間為:"+QString::number(uartRecOvertimeCount*1000)+"ms");
        uartRecDataTimer->setInterval(uartRecOvertimeCount*1000);                       //設置定時周期,單位:毫秒
    
        fTimeCounter.restart();
        uartRecDataTimer->start();
    }
    

    四、發送數據

    簡單的發送數據沒有什么要額外配置的,調用write函數就可以了,可以根據自己的實際情況做一些配置或是校驗處理。比如加回車換行什么的

    //發送串口數據
    void MainWindow::on_sendDataButton_clicked()
    {
        //未打開串口則不準發送
        if(ui->openSerialButton->text() == "打開串口")
        {
            QMessageBox::warning(NULL, "警告", "未打開可用串口,無法發送數據!\r\n\r\n");
            return;
        }
    
        //獲取發送的命令,并選擇在結尾加上換行,AT的命令結尾必須有回車換行
        QString command = ui->uartWritePlain->toPlainText();
        if(ui->changeLineCheckBox->isChecked())
        {
            command += "\r\n";
        }
    
        if(ui->timeZoneCheckBox->isChecked())
        {
             curDateTime = QDateTime::currentDateTime();
             ui->uartReadPlain->insertPlainText("\r\n"+curDateTime.toString("[yyyy-MM-dd hh:mm:ss]")+"SEND:"+command);
        }
    
        send_buf_len += command.length();
        ui->TXLenLabel->setText(QString::number(send_buf_len)+"bytes");
    
        serial->write(command.toLatin1());
    }

    至此,一個最基本的串口調試工具就完成了,下面就是給它添加功能和優化了

    上一篇:

    QT實現串口調試助手(一)

     

    版權聲明:本文為zhangfls原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接和本聲明。
    本文鏈接:https://blog.csdn.net/zhangfls/article/details/109593287

    智能推薦

    HTML中常用操作關于:頁面跳轉,空格

    1.頁面跳轉 2.空格的代替符...

    freemarker + ItextRender 根據模板生成PDF文件

    1. 制作模板 2. 獲取模板,并將所獲取的數據加載生成html文件 2. 生成PDF文件 其中由兩個地方需要注意,都是關于獲取文件路徑的問題,由于項目部署的時候是打包成jar包形式,所以在開發過程中時直接安照傳統的獲取方法沒有一點文件,但是當打包后部署,總是出錯。于是參考網上文章,先將文件讀出來到項目的臨時目錄下,然后再按正常方式加載該臨時文件; 還有一個問題至今沒有解決,就是關于生成PDF文件...

    電腦空間不夠了?教你一個小秒招快速清理 Docker 占用的磁盤空間!

    Docker 很占用空間,每當我們運行容器、拉取鏡像、部署應用、構建自己的鏡像時,我們的磁盤空間會被大量占用。 如果你也被這個問題所困擾,咱們就一起看一下 Docker 是如何使用磁盤空間的,以及如何回收。 docker 占用的空間可以通過下面的命令查看: TYPE 列出了docker 使用磁盤的 4 種類型: Images:所有鏡像占用的空間,包括拉取下來的鏡像,和本地構建的。 Con...

    requests實現全自動PPT模板

    http://www.1ppt.com/moban/ 可以免費的下載PPT模板,當然如果要人工一個個下,還是挺麻煩的,我們可以利用requests輕松下載 訪問這個主頁,我們可以看到下面的樣式 點每一個PPT模板的圖片,我們可以進入到詳細的信息頁面,翻到下面,我們可以看到對應的下載地址 點擊這個下載的按鈕,我們便可以下載對應的PPT壓縮包 那我們就開始做吧 首先,查看網頁的源代碼,我們可以看到每一...

    猜你喜歡

    Linux C系統編程-線程互斥鎖(四)

    互斥鎖 互斥鎖也是屬于線程之間處理同步互斥方式,有上鎖/解鎖兩種狀態。 互斥鎖函數接口 1)初始化互斥鎖 pthread_mutex_init() man 3 pthread_mutex_init (找不到的情況下首先 sudo apt-get install glibc-doc sudo apt-get install manpages-posix-dev) 動態初始化 int pthread_...

    統計學習方法 - 樸素貝葉斯

    引入問題:一機器在良好狀態生產合格產品幾率是 90%,在故障狀態生產合格產品幾率是 30%,機器良好的概率是 75%。若一日第一件產品是合格品,那么此日機器良好的概率是多少。 貝葉斯模型 生成模型與判別模型 判別模型,即要判斷這個東西到底是哪一類,也就是要求y,那就用給定的x去預測。 生成模型,是要生成一個模型,那就是誰根據什么生成了模型,誰就是類別y,根據的內容就是x 以上述例子,判斷一個生產出...

    styled-components —— React 中的 CSS 最佳實踐

    https://zhuanlan.zhihu.com/p/29344146 Styled-components 是目前 React 樣式方案中最受關注的一種,它既具備了 css-in-js 的模塊化與參數化優點,又完全使用CSS的書寫習慣,不會引起額外的學習成本。本文是 styled-components 作者之一 Max Stoiber 所寫,首先總結了前端組件化樣式中的最佳實踐原則,然后在此基...

    基于TCP/IP的網絡聊天室用Java來實現

    基于TCP/IP的網絡聊天室實現 開發工具:eclipse 開發環境:jdk1.8 發送端 接收端 工具類 運行截圖...

    19.vue中封裝echarts組件

    19.vue中封裝echarts組件 1.效果圖 2.echarts組件 3.使用組件 按照組件格式整理好數據格式 傳入組件 home.vue 4.接口返回數據格式...

    精品国产乱码久久久久久蜜桃不卡