一個基于QT的開源串口調(diào)試工具
在開始軟件設(shè)計之前,我們來簡略地分析一下這樣一個小軟件其要包含的主要內(nèi)容有哪些。我們認為軟件需要如下幾個方面的內(nèi)容:
串口參數(shù)的配置,我們希望串口號能夠自動搜索,而相應(yīng)的配置參數(shù)我們可以選擇。
發(fā)送數(shù)據(jù)的輸入,對于本軟件我們需要輸入相應(yīng)的數(shù)據(jù)以實現(xiàn)命令及消息的發(fā)送,所以我們需要設(shè)計數(shù)據(jù)的輸入?yún)^(qū)域以及發(fā)送交互按鈕等。
接收信息的顯示,作為調(diào)試工具,我們肯定希望能夠一目了然地看到接收到目標設(shè)備發(fā)送過來的消息,所以我們需要一個顯示區(qū)域來對接收的區(qū)域進行顯示。
運行狀態(tài)的顯示, 我們希望對操作的狀態(tài)進行反饋以指示操作的動作是否執(zhí)行,所以我們需要狀態(tài)欄來實現(xiàn)這一需求。
其它輔助功能, 還有如發(fā)送計數(shù)、接收計數(shù)、數(shù)據(jù)存儲等功能有時候也是需要的,所以我們一并考慮。
對于串口工具其實網(wǎng)上就有不少,我們之所以要自己實現(xiàn)這么一個串口調(diào)試工具,主要的原因有兩點。一是,網(wǎng)上找到的相應(yīng)工具某一個單獨的工具有時候不能完全滿足我們的需求,所以我們根據(jù)自己的需求設(shè)計這個工具能更好的滿足我們串口調(diào)試的需要。二是,通過這樣一個工具的實現(xiàn),我們能夠加深對串口通訊相關(guān)知識的理解。
2、界面設(shè)計根據(jù)上一節(jié)中分析的需求,我們先來設(shè)計軟件的界面。我們在QT中基于QMainWindow類生成一個操作界面,包括菜單欄、工具欄和狀態(tài)欄以滿足需求中對狀態(tài)顯示及操作命令的要求。
而在中間顯示區(qū)域,我們將其劃分為3行2列。在左邊的一列從上到下設(shè)置:串口配置操作區(qū)域、接收配置區(qū)域以及發(fā)送配置區(qū)域。在右側(cè)的一列從上到下設(shè)置:動態(tài)曲線顯示區(qū)域、信息接收顯示區(qū)域以及信息發(fā)送輸入?yún)^(qū)域。具體的界面設(shè)置如下圖所示:
完成如上圖的布局后,我們可以選擇在屬性中配置空間的參數(shù),也可以在代碼中添加相關(guān)的參數(shù),本人習慣于在代碼中完成。完成整個布局后我們先試著運行程序,正常運行則出現(xiàn)如下的界面:
上圖就是完成布局后的運行界面,不過我們還沒有實現(xiàn)相應(yīng)的編碼,所以目前還不能實現(xiàn)我們第一節(jié)中所提出來的功能。
3、編碼實現(xiàn)接下來這一小節(jié),我們將來編碼實現(xiàn)相應(yīng)的功能。我們主要將功能分為參數(shù)設(shè)置與操作功能、數(shù)據(jù)的輸入與發(fā)送功能以及數(shù)據(jù)的接收與顯示功能三個部分來實現(xiàn)。
3.1、參數(shù)設(shè)置與操作功能對于參數(shù)的配置除了串口號以外都可以直接使用ComboBox控件的相應(yīng)函數(shù)添加。串口號這塊,我們希望搜索電腦安裝的串口并添加到控件中。具體的實現(xiàn)方式如下:
//搜索可用的串口,并添加到串口組合框 void MainWindow::SearchSerialPorts() { ui->comboBoxPort->clear(); foreach(const QSerialPortInfo &info,QSerialPortInfo::availablePorts()) { ui->comboBoxPort->addItem(info.portName()); } }
配置好串口參數(shù)后,我們可以打開串口以建立連接。需要說明的是我們打開串口間離連接時,我們需要將該串口的數(shù)據(jù)接收與我們的數(shù)據(jù)接收和處理函數(shù)建立信號槽連接。具體實現(xiàn)如下:
//打開串口 void MainWindow::on_actionConnect_triggered() { serialPort->setPortName(ui->comboBoxPort->currentText()); if(serialPort->open(QIODevice::ReadWrite)) //打開串口成功 { serialPort->setBaudRate(ui->comboBoxBaud->currentText().toInt()); //設(shè)置波特率 switch(ui->comboBoxData->currentIndex()) //設(shè)置數(shù)據(jù)位數(shù) { case 1:serialPort->setDataBits(QSerialPort::Data8);break; default: break; } switch(ui->comboBoxParity->currentIndex()) //設(shè)置奇偶校驗 { case 0: serialPort->setParity(QSerialPort::NoParity);break; default: break; } switch(ui->comboBoxStop->currentIndex()) //設(shè)置停止位 { case 1: serialPort->setStopBits(QSerialPort::OneStop);break; case 2: serialPort->setStopBits(QSerialPort::TwoStop);break; default: break; } serialPort->setFlowControl(QSerialPort::NoFlowControl); //設(shè)置流控制 //連接槽函數(shù) QObject::connect(serialPort, &QSerialPort::readyRead, this, &MainWindow::ReadSerialData); // 設(shè)置控件可否使用 ui->actionConnect->setEnabled(false); ui->actionClose->setEnabled(true); ui->actionRefresh->setEnabled(false); } else //打開失敗提示 { QMessageBox::information(this,tr("錯誤"),tr("打開串口失??!"),QMessageBox::Ok); } }
同樣的,我們除了要打開串口建立連接外,還需要關(guān)閉串口斷開連接,具體的代碼如下:
//關(guān)閉串口 void MainWindow::on_actionClose_triggered() { serialPort->clear(); serialPort->close(); // 設(shè)置控件可否使用 ui->actionConnect->setEnabled(true); ui->actionClose->setEnabled(false); ui->actionRefresh->setEnabled(true); }3.2、數(shù)據(jù)的輸入與發(fā)送功能
數(shù)據(jù)的輸入與發(fā)送,我們設(shè)計了5條命令,每條命令可以通過后面的按鈕手動發(fā)送,也可以自動循環(huán)發(fā)送。自動循環(huán)發(fā)送時,將對每條選中的命令以設(shè)定的時間間隔輪詢發(fā)送。
首先我們來看看定時周期發(fā)送的過程。我們定義了一個計時器,以我們設(shè)定的時間周期觸發(fā)發(fā)送命令,每次發(fā)送復選框被選中的命令一條,依次循環(huán)直到人為停止循環(huán)發(fā)送為止。具體的代碼如下:
//定時周期發(fā)送 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++; } }
手動單次發(fā)送則判斷是哪一個按鈕觸發(fā)的動作則操作對應(yīng)的數(shù)據(jù)輸入框,將其中的內(nèi)容以指定的格式發(fā)送出去。具體的操作代碼如下:
//按鈕觸發(fā)發(fā)送 void MainWindow::SingleSendData() { // 判斷如果Sender是QPushButton就執(zhí)行 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、數(shù)據(jù)的接收與現(xiàn)實功能
在我們的設(shè)計中,數(shù)據(jù)的接收相對要簡單一些。當串口接收到數(shù)據(jù)后就會觸發(fā)我們的接收數(shù)據(jù)處理函數(shù),并將以我們設(shè)定的格式顯示出來,具體的實現(xiàn)代碼如下:
//從串口接收數(shù)據(jù) 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字節(jié)數(shù)據(jù)").arg(rxDatas.size())); } rxDatas.clear(); }4、小結(jié)
完成了編碼調(diào)試后,我們來對開發(fā)的這一工具進行一些測試。首先我們安裝一個虛擬串口軟件用以虛擬我們用于測試的串口。如果有硬件接口最好,但是在我的電腦上沒有串口,所以我們使用虛擬串口來模擬一對串口。具體的配置如下圖所示:??
我們使用另一個串口工具來實現(xiàn)與我們開發(fā)的這一工具實現(xiàn)通訊驗證。我們使用以前寫得一個串口工具來實現(xiàn)與這一工具的通訊。一個使用使用COM1,一個使用使用COM2。具體的配置如下圖所示:
注:使用虛擬串口波特率可以
原文地址:南木創(chuàng)智
轉(zhuǎn)自公眾號:嵌入式大雜燴
*博客內(nèi)容為網(wǎng)友個人發(fā)布,僅代表博主個人觀點,如有侵權(quán)請聯(lián)系工作人員刪除。