QT實現串口調試助手(二)
一、導入庫
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());
}
至此,一個最基本的串口調試工具就完成了,下面就是給它添加功能和優化了
上一篇:
智能推薦
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 所寫,首先總結了前端組件化樣式中的最佳實踐原則,然后在此基...
19.vue中封裝echarts組件
19.vue中封裝echarts組件 1.效果圖 2.echarts組件 3.使用組件 按照組件格式整理好數據格式 傳入組件 home.vue 4.接口返回數據格式...