Qt小項目之串口助手控制LED
最近剛學了一點Qt開發上位機,嘗試著做個小軟體練練手。查找了很多資料,做了一個簡單的串口助手,可以實現串口基本發送和接收功能,支持中文顯示,還可以控制STM32開發板上的兩個LED。
花了大概3天時間吧,找了很多資料,功能很簡單, 但想著是自己一點一點開發的,還是挺有成就感的哈!
寫這篇文章是為了總結一下開發的過程和一些知識點,主要包括兩部分,上位機的實現和STM32端程序的實現。
新建一個Dialog項目,這3種基類的區別可以根據你的程序來確定。
使用Qt Designer添加所需要的控制項,並進行合理佈局,盡量每一個控制項,起一個合理易懂的名字。
pro文件添加一行:
QT += serialport
對應的頭文件包含:
#include <QSerialPort> #include <QSerialPortInfo>
自動搜索本機串口,並在ComboBox中添加串口號
ui->cbb_com->clear(); //運行開始查找可用串口 foreach(const QSerialPortInfo &info, QSerialPortInfo::availablePorts()) { ui->cbb_com->addItem(info.portName()); //串口號下拉菜單,增加一個條目,為串口號COM4 qDebug() << "串口搜索完成"; }
//打開串口按鈕 void Dialog::on_btn_uart_Ctrl_clicked() { // static bool flag; //也可以用標誌位實現 if(this->ui->btn_uart_Ctrl->text() == "打開串口") //初始狀態,配置串口參數 { serial.setPortName(ui->cbb_com->currentText()); //設置串口號、 serial.setBaudRate(ui->cbb_baud->currentText().toInt()); //設置波特率 serial.setDataBits(QSerialPort::Data8); //設置串口數據位8 serial.setParity(QSerialPort::NoParity); //無校驗位 serial.setStopBits(QSerialPort::OneStop); //1位停止位 serial.setFlowControl(QSerialPort::NoFlowControl); //打開串口 if(!serial.open(QIODevice::ReadWrite)) { QMessageBox::critical(NULL, "提示", "串口打開失敗"); return; } qDebug() << "串口打開成功"; this->ui->btn_uart_Ctrl->setText("關閉串口"); } else { //關閉串口 serial.close(); this->ui->btn_uart_Ctrl->setText("打開串口"); } }
serial.write("A1 "); //串口發送A1
QT默認的編碼是unicode,不能顯示中文的,windows默認使用(GBK/GB2312/GB18030),使用了fromLocal8Bit()函數,實現了從Unicode到本地字符集GBK的轉換,用於處理漢語顯示亂碼等問題
槽函數的實現:
//串口數據接收並顯示 void Dialog::serialPort_readyRead() { QByteArray rx_buf = serial.readAll(); //讀取串口接收的數據 if(rx_buf.endsWith(" ")) //判斷接收最後是否是回車換行,即接收完成標誌 {
} QString rx_buf_tmp = QString::fromLocal8Bit(rx_buf); //轉換為中文格式 qDebug() << rx_buf_tmp; //控制檯輸出
ui->tb_rx_buf->append(rx_buf_tmp);
rx_buf_tmp.clear(); rx_buf.clear(); }
connect語句:
connect(&serial, & QSerialPort::readyRead, this, &Dialog::serialPort_readyRead);
//自定義波特率 void Dialog::on_cbb_baud_currentIndexChanged(const QString &arg1) { if(this->ui->cbb_baud->currentIndex() == 3) { this->ui->cbb_baud->setItemText(3, ""); //調成自定義波特率時,內容設置為空,準備接收輸入 this->ui->cbb_baud->setEditable(true); } else { this->ui->cbb_baud->setItemText(3, "自定義"); //調成自定義波特率時,內容設置為空,準備接收輸入 this->ui->cbb_baud->setEditable(false); } serial.setBaudRate(ui->cbb_baud->currentText().toInt()); //即使打開串口後,仍然可以設置波特率 }
通過一個全局變數實現,發送新行按鈕勾選時,標誌位置1,然後發送按鈕功能裏,根據標誌位決定是否在末尾添加換行符。
對應的槽函數實現:
//是否發送新行 void Dialog::on_cb_send_enter_clicked() { if(ui->cb_send_enter->isChecked()) { send_enter_flag = true; qDebug() << "發送新行"; } else { send_enter_flag = false; qDebug() << "不發送新行"; } } //發送按鈕被按下 void Dialog::on_btn_send_clicked() { //獲取多行輸入框的數據並轉換為UTF8格式 QByteArray tx_buf = ui->te_tx_buf->toPlainText().toUtf8();
if(send_enter_flag == true) tx_buf += " ";
serial.write(tx_buf); //把數據通過串口發送出去 tx_buf.clear(); }
本來想著通過改變樣式表的方式改變顏色
this->ui->lbe_blue->setStyleSheet("color: rgb(255, 0, 0);");
但是,實際運行時,連字體和大小都改成了默認的,有沒有一種只改變顏色其他的格式不變的方法呢?還真有,如下,不過好像只支持標準顏色?
QPalette colr; colr.setColor(QPalette::WindowText,Qt::red); //設置標籤顏色紅色 this->ui->lbe_red->setPalette(colr);
以下兩行語句效果相同,都是失能按鈕功能:
this->ui->btn_led1_Ctrl->setDisabled(true); //LED控制按鈕不可用 this->ui->btn_led1_Ctrl->setEnabled(false); //LED控制按鈕不可用
this->ui->tb_rx_buf->document()->setMaximumBlockCount(10);
你不希望窗口的標題是「Dialog」吧,所以添加一個標題和一個好看的圖標還是很有必要的。
添加窗口標題還是很簡單的,一行代碼:
this->setWindowTitle("串口控制LED - By wcc ");
重新編譯就可以看到這種效果了。
構建選項改成Release版本,編譯完成後,會在Release目錄下生成一個.exe文件,把這個文件單獨拷出來放在一個空白的文件夾裏,如D:QT_PrjExportUART_Demo.exe,可以運行試一下,會提示缺少運行所需要的dll組件
D:QT_PrjExportUART_Demo.exe
而且,這個文件如果單獨拷貝到其他沒有安裝Qt環境的電腦上,也是不能運行的。
所以我們需要添加一些當前程序運行所需要的組件才能正常運行,但是需要添加哪些文件呢?不用擔心,Qt早已經想好了,運行MinGW工具:
先進入到exe文件所在的文件夾中:cd /d D:QT_PrjExport
cd /d D:QT_PrjExport
然後輸入命令:windeployqt UART_Demo.exe
windeployqt UART_Demo.exe
此時,打開exe文件所在的文件夾,可以看到Qt已經為我們添加好了,當前程序運行所需要的組件了。
這個時候,如果想給別人分享你開發好的上位機軟體,就可以直接把這個文件夾拷貝給他。當然也可以安裝一個Enigma Virtual Box軟體,把當前目錄下的所有文件打包成一個exe文件。
Enigma Virtual Box
連接串口模塊,發送接收短接,可以看出Qt上位機的的收發都是正常的。下一步就是編寫STM32端的程序了,很簡單,當接收到字元串"A1"時,點亮紅燈;當接收到字元串「A2」時,熄滅紅燈;當接收到字元串「B1」時,點亮藍燈;當接收到字元串「B2」時,熄滅藍燈,每個字元串結尾都有換行符「 」,
實現思路也很簡單,即把接收到的字元存入一個字元數組,當接收到「 」換行標誌時,意味著接收完成,判斷此時數組的內容,分別和命令比較,如果一致,執行相應的操作,串口1中斷服務函數:
void USART1_IRQHandler(void) { char dat; char flag = 0; if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //接收中斷 { dat = USART1->DR; if(usart1Len >= 64) //防止數據過多,導致內存溢出 usart1Len = 0; if(dat == 0x0D || dat == 0x0A) //回車換行,接收完成,此時的buf不含回車換行 { if(strcmp(usart1Buf, "A2") == 0) //字元串比較 { UsartPrintf(USART1, "紅燈熄滅 "); GPIO_SetBits(GPIOB, GPIO_Pin_9); } else if(strcmp(usart1Buf, "A1") == 0) { UsartPrintf(USART1, "紅燈點亮 "); GPIO_ResetBits(GPIOB, GPIO_Pin_9); } else if(strcmp(usart1Buf, "B2") == 0) { UsartPrintf(USART1, "藍燈熄滅 "); GPIO_SetBits(GPIOB, GPIO_Pin_6); } else if(strcmp(usart1Buf, "B1") == 0) { UsartPrintf(USART1, "藍燈點亮 "); GPIO_ResetBits(GPIOB, GPIO_Pin_6); } usart1Len = 0; memset(usart1Buf,0,64); } else { usart1Buf[usart1Len++] = dat; } USART_ClearFlag(USART1, USART_FLAG_RXNE); } }
程序還是很簡單。板子是用的中移的麒麟座Mini板,基於F103C8T6的,串口1連接上位機,波特率115200,PB9-紅燈,PB6-綠燈,都是低電平點亮。
由於國內Github下載速度實在令人著急,Qt工程文件和STM32工程文件,還包括Enigma_Virtual_Box的安裝包,我都已經上傳到國內的碼雲Gitee上了,有需要的朋友可以在Git中使用以下命令下載:
git clone https://gitee.com/whik/qt_uart_demo.git
或者是在公眾號後臺回復【串口助手】,我會把下載鏈接發送給你。
當然,如果有朋友也在學習Qt開發上位機,歡迎互相交流學習。
歡迎大家關注我的個人博客
或微信掃碼關注我的公眾號
推薦閱讀: