博客專欄

        EEPW首頁 > 博客 > 一個基于QT的開源串口調試工具

        一個基于QT的開源串口調試工具

        發布人:xiaomaidashu 時間:2022-09-19 來源:工程師 發布文章
        1、概述

        在開始軟件設計之前,我們來簡略地分析一下這樣一個小軟件其要包含的主要內容有哪些。我們認為軟件需要如下幾個方面的內容:

        • 串口參數的配置,我們希望串口號能夠自動搜索,而相應的配置參數我們可以選擇。

        • 發送數據的輸入,對于本軟件我們需要輸入相應的數據以實現命令及消息的發送,所以我們需要設計數據的輸入區域以及發送交互按鈕等。

        • 接收信息的顯示,作為調試工具,我們肯定希望能夠一目了然地看到接收到目標設備發送過來的消息,所以我們需要一個顯示區域來對接收的區域進行顯示。

        • 運行狀態的顯示, 我們希望對操作的狀態進行反饋以指示操作的動作是否執行,所以我們需要狀態欄來實現這一需求。

        • 其它輔助功能, 還有如發送計數、接收計數、數據存儲等功能有時候也是需要的,所以我們一并考慮。

        對于串口工具其實網上就有不少,我們之所以要自己實現這么一個串口調試工具,主要的原因有兩點。一是,網上找到的相應工具某一個單獨的工具有時候不能完全滿足我們的需求,所以我們根據自己的需求設計這個工具能更好的滿足我們串口調試的需要。二是,通過這樣一個工具的實現,我們能夠加深對串口通訊相關知識的理解。

        2、界面設計

        根據上一節中分析的需求,我們先來設計軟件的界面。我們在QT中基于QMainWindow類生成一個操作界面,包括菜單欄、工具欄和狀態欄以滿足需求中對狀態顯示及操作命令的要求。

        而在中間顯示區域,我們將其劃分為3行2列。在左邊的一列從上到下設置:串口配置操作區域、接收配置區域以及發送配置區域。在右側的一列從上到下設置:動態曲線顯示區域、信息接收顯示區域以及信息發送輸入區域。具體的界面設置如下圖所示:

        圖片

        完成如上圖的布局后,我們可以選擇在屬性中配置空間的參數,也可以在代碼中添加相關的參數,本人習慣于在代碼中完成。完成整個布局后我們先試著運行程序,正常運行則出現如下的界面:

        圖片

        上圖就是完成布局后的運行界面,不過我們還沒有實現相應的編碼,所以目前還不能實現我們第一節中所提出來的功能。

        3、編碼實現

        接下來這一小節,我們將來編碼實現相應的功能。我們主要將功能分為參數設置與操作功能、數據的輸入與發送功能以及數據的接收與顯示功能三個部分來實現。

        3.1、參數設置與操作功能

        對于參數的配置除了串口號以外都可以直接使用ComboBox控件的相應函數添加。串口號這塊,我們希望搜索電腦安裝的串口并添加到控件中。具體的實現方式如下:

        //搜索可用的串口,并添加到串口組合框
        void MainWindow::SearchSerialPorts()
        {
            ui->comboBoxPort->clear();
        
            foreach(const QSerialPortInfo &info,QSerialPortInfo::availablePorts())
            {
                ui->comboBoxPort->addItem(info.portName());
            }
        }

        配置好串口參數后,我們可以打開串口以建立連接。需要說明的是我們打開串口間離連接時,我們需要將該串口的數據接收與我們的數據接收和處理函數建立信號槽連接。具體實現如下:

        //打開串口
        void MainWindow::on_actionConnect_triggered()
        {
            serialPort->setPortName(ui->comboBoxPort->currentText());
        
            if(serialPort->open(QIODevice::ReadWrite))              //打開串口成功
            {
                serialPort->setBaudRate(ui->comboBoxBaud->currentText().toInt());       //設置波特率
        
                switch(ui->comboBoxData->currentIndex())                   //設置數據位數
                {
                    case 1:serialPort->setDataBits(QSerialPort::Data8);break;
                    default: break;
                }
        
                switch(ui->comboBoxParity->currentIndex())                   //設置奇偶校驗
                {
                    case 0: serialPort->setParity(QSerialPort::NoParity);break;
                    default: break;
                }
        
                switch(ui->comboBoxStop->currentIndex())                     //設置停止位
                {
                    case 1: serialPort->setStopBits(QSerialPort::OneStop);break;
                    case 2: serialPort->setStopBits(QSerialPort::TwoStop);break;
                    default: break;
                }
        
                serialPort->setFlowControl(QSerialPort::NoFlowControl);     //設置流控制
        
                //連接槽函數
                QObject::connect(serialPort, &QSerialPort::readyRead, this, &MainWindow::ReadSerialData);
        
                // 設置控件可否使用
                ui->actionConnect->setEnabled(false);
                ui->actionClose->setEnabled(true);
                ui->actionRefresh->setEnabled(false);
            }
            else    //打開失敗提示
            {
                QMessageBox::information(this,tr("錯誤"),tr("打開串口失敗!"),QMessageBox::Ok);
            }
        }

        同樣的,我們除了要打開串口建立連接外,還需要關閉串口斷開連接,具體的代碼如下:

        //關閉串口
        void MainWindow::on_actionClose_triggered()
        {
            serialPort->clear();
            serialPort->close();
        
            // 設置控件可否使用
            ui->actionConnect->setEnabled(true);
            ui->actionClose->setEnabled(false);
            ui->actionRefresh->setEnabled(true);
        }
        3.2、數據的輸入與發送功能

        數據的輸入與發送,我們設計了5條命令,每條命令可以通過后面的按鈕手動發送,也可以自動循環發送。自動循環發送時,將對每條選中的命令以設定的時間間隔輪詢發送。

        首先我們來看看定時周期發送的過程。我們定義了一個計時器,以我們設定的時間周期觸發發送命令,每次發送復選框被選中的命令一條,依次循環直到人為停止循環發送為止。具體的代碼如下:

        //定時周期發送
        void MainWindow::CycleSendData()
        {
            QCheckBox* cbSend;
        
            while(true)
            {
                snIndex=snIndex>=6?1:snIndex;
        
                cbSend=ui->groupBoxMessage->findChild<QCheckBox*>(QString("checkBoxSendEnable%1").arg(QString::number(snIndex)));
        
                if(cbSend->isChecked())
                {
                    WriteSerialData(snIndex);
                    snIndex++;
                    break;
                }
        
                snIndex++;
            }
        }

        手動單次發送則判斷是哪一個按鈕觸發的動作則操作對應的數據輸入框,將其中的內容以指定的格式發送出去。具體的操作代碼如下:

        //按鈕觸發發送
        void MainWindow::SingleSendData()
        {
            // 判斷如果Sender是QPushButton就執行
            if (QPushButton* btn = dynamic_cast<QPushButton*>(sender()))
            {
                QString senderName;
                int sn=0;
        
                senderName = btn->objectName();
                sn = senderName.replace("pushButtonSend", "").toInt();
        
                if((0<sn) && (sn<6))
                {
                    WriteSerialData(sn);
                }
            }
        }
        3.3、數據的接收與現實功能

        在我們的設計中,數據的接收相對要簡單一些。當串口接收到數據后就會觸發我們的接收數據處理函數,并將以我們設定的格式顯示出來,具體的實現代碼如下:

        //從串口接收數據
        void MainWindow::ReadSerialData()
        {
            QByteArray rxDatas;
            QString context;
        
            rxDatas=serialPort->readAll();
        
            if(!rxDatas.isNull())
            {
                if(ui->checkBoxRecieve->isChecked())    //十六進制顯示
                {
                     context = rxDatas.toHex(' ');
                     context=context.toUpper();
                }
                else    //ASCII顯示
                {
                    context = rxDatas;
                }
        
                QString timeStrLine="["+QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss")+"][接收]: ";
                context = timeStrLine+context+"nr";
        
                QString content = "<span style=" color:blue;">"+context+"</span>";
                ui->textBrowser->append(content);
        
                receivedBytes=receivedBytes+rxDatas.size();
                ui->lcdNumberRecieve->display(receivedBytes);
        
                ui->statusbar->showMessage(tr("成功讀取%1字節數據").arg(rxDatas.size()));
            }
        
            rxDatas.clear();
        }
        4、小結

        完成了編碼調試后,我們來對開發的這一工具進行一些測試。首先我們安裝一個虛擬串口軟件用以虛擬我們用于測試的串口。如果有硬件接口最好,但是在我的電腦上沒有串口,所以我們使用虛擬串口來模擬一對串口。具體的配置如下圖所示:??圖片

        我們使用另一個串口工具來實現與我們開發的這一工具實現通訊驗證。我們使用以前寫得一個串口工具來實現與這一工具的通訊。一個使用使用COM1,一個使用使用COM2。具體的配置如下圖所示:

        注:使用虛擬串口波特率可以

        圖片

        原文地址:南木創智

        轉自公眾號:嵌入式大雜燴


        *博客內容為網友個人發布,僅代表博主個人觀點,如有侵權請聯系工作人員刪除。



        關鍵詞: 串口調試

        技術專區

        關閉
        主站蜘蛛池模板: 长丰县| 加查县| 都江堰市| 育儿| 冕宁县| 乌拉特后旗| 托克逊县| 安吉县| 南岸区| 吉木乃县| 隆尧县| 炎陵县| 兴安县| 乳源| 岑巩县| 苍溪县| 大埔县| 嵊州市| 阳高县| 安塞县| 确山县| 清苑县| 三穗县| 长丰县| 靖边县| 会东县| 平阳县| 炉霍县| 蓬莱市| 太原市| 娄底市| 柞水县| 北票市| 郸城县| 云安县| 眉山市| 贵阳市| 开远市| 浦县| 天等县| 邵东县|