文章目錄
- 1.創建工程
- 1.1 建立空白工程
- 1.2 添加控制元件
- 2. 在主執行緒實作串口發送
- 2.1 在.pro檔案和.h檔案中引入QSerialPort
- 2.2 查找可用串口
- 2.3 打開&關閉串口
- 2.4 將位元組序列轉換為對應的16進制字串
- 2.5 將16進制字串轉換為對應的位元組序列
- 2.6 使用串口發送
- 2.7 使用串口接收
- 3. 在子執行緒實作串口發送與接收
- 3.1 建立串口事務處理子執行緒類:SerialWorker
- 3.2 修改默認工程
- 3.3 增加子執行緒串口發送、接收槽函式、結果通知信號
- 3.4 在GUI執行緒中增加資料發送信號、結果接收槽
- 3.5 在GUI執行緒中添加串口子執行緒
- 3.6 效果演示
文章示例工程下載地址:
https://download.csdn.net/download/u014779536/13790253
1.創建工程
1.1 建立空白工程
工程名:Qt_MultiThread_SerialPort

1.2 添加控制元件
添加下圖所示的所有控制元件,并重新命名:

各控制元件命名如下:

2. 在主執行緒實作串口發送
實作串口發送我們需要進行以下幾個步驟:
- 查找可用串口
- 打開串口
- 通信發送
- 通信接收
- 關閉串口
- 字串轉16位元組(發送用)
- 16位元組轉字串(顯示用)
2.1 在.pro檔案和.h檔案中引入QSerialPort
QT += serialport

#include <QSerialPort>
#include <QSerialPortInfo>
void InitSerialPortName();

2.2 查找可用串口
我們在程式啟動時自動搜索電腦設備,并將可用的串口名稱添加到串口選擇框,

void MainWindow::InitSerialPortName()
{
// 清空下拉框
ui->box_portName->clear();
//通過QSerialPortInfo查找可用串口
foreach(const QSerialPortInfo &info, QSerialPortInfo::availablePorts())
{
QString showName = info.portName()+":"+info.description();
qDebug() << showName.length();
ui->box_portName->addItem(showName);
}
}
2.3 打開&關閉串口
在manwindow.h中宣告串口

設定打開按鈕關閉槽函式:
void MainWindow::on_btn_openPort_clicked()
{
if(ui->btn_openPort->text()==QString("打開串口"))
{
//設定串口名
QString portName = (ui->box_portName->currentText()).split(":").at(0);
qDebug() << portName;
serial_1.setPortName(portName);
//設定波特率
serial_1.setBaudRate(ui->box_baudrate->currentText().toInt());
//設定停止位
if(ui->box_stopBit->currentText() == "1")
serial_1.setStopBits(QSerialPort::OneStop);
else if(ui->box_stopBit->currentText() == "1.5")
serial_1.setStopBits(QSerialPort::OneAndHalfStop);
else if(ui->box_stopBit->currentText() == "2")
serial_1.setStopBits(QSerialPort::TwoStop);
//設定資料位數
if(ui->box_dataBits->currentText() == "8")
serial_1.setDataBits(QSerialPort::Data8);
else if(ui->box_dataBits->currentText() == "7")
serial_1.setDataBits(QSerialPort::Data7);
else if(ui->box_dataBits->currentText() == "6")
serial_1.setDataBits(QSerialPort::Data6);
else if(ui->box_dataBits->currentText() == "5")
serial_1.setDataBits(QSerialPort::Data5);
//設定奇偶校驗
if(ui->box_parityBit->currentText() == "None")
serial_1.setParity(QSerialPort::NoParity);
else if(ui->box_parityBit->currentText() == "Even")
serial_1.setParity(QSerialPort::EvenParity);
else if(ui->box_parityBit->currentText() == "Odd")
serial_1.setParity(QSerialPort::OddParity);
//設定流控制
serial_1.setFlowControl(QSerialPort::NoFlowControl);
//打開串口
if(!serial_1.open(QIODevice::ReadWrite))
{
QMessageBox::about(NULL, "提示", "無法打開串口!");
return;
}
//下拉選單控制元件失能
ui->box_portName->setEnabled(false);
ui->box_baudrate->setEnabled(false);
ui->box_dataBits->setEnabled(false);
ui->box_parityBit->setEnabled(false);
ui->box_stopBit->setEnabled(false);
ui->btn_openPort->setText(QString("關閉串口"));
//發送按鍵使能
ui->btn_send->setEnabled(true);
}
else
{
//關閉串口
serial_1.close();
//下拉選單控制元件使能
ui->box_portName->setEnabled(true);
ui->box_baudrate->setEnabled(true);
ui->box_dataBits->setEnabled(true);
ui->box_parityBit->setEnabled(true);
ui->box_stopBit->setEnabled(true);
ui->btn_openPort->setText(QString("打開串口"));
//發送按鍵失能
ui->btn_send->setEnabled(false);
}
}
2.4 將位元組序列轉換為對應的16進制字串
/*
* @breif 將位元組序列轉換為對應的16進制字串
*/
QString MainWindow::ByteArrayToHexString(QByteArray data)
{
QString ret(data.toHex().toUpper());
int len = ret.length()/2;
qDebug()<<len;
for(int i=1;i<len;i++)
{
//qDebug()<<i;
ret.insert(2*i+i-1," ");
}
return ret;
}
2.5 將16進制字串轉換為對應的位元組序列
/*
* @breif 將16進制字串轉換為對應的位元組序列
*/
QByteArray MainWindow::HexStringToByteArray(QString HexString)
{
bool ok;
QByteArray ret;
HexString = HexString.trimmed();
HexString = HexString.simplified();
QStringList sl = HexString.split(" ");
foreach (QString s, sl) {
if(!s.isEmpty())
{
char c = s.toInt(&ok,16)&0xFF;
if(ok){
ret.append(c);
}else{
qDebug()<<"非法的16進制字符:"<<s;
QMessageBox::warning(0,tr("錯誤:"),QString("非法的16進制字符: \"%1\"").arg(s));
}
}
}
//qDebug()<<ret;
return ret;
}
2.6 使用串口發送
/*
* @breif 發送資料
*/
void MainWindow::on_btn_send_clicked()
{
//獲取界面上的資料并轉換成utf8格式的位元組流
QByteArray data;
if(ui->check_hexSend->isChecked() == true)
data = HexStringToByteArray(ui->edit_dataSend->toPlainText());
else
data = ui->edit_dataSend->toPlainText().toUtf8();
serial_1.write(data);
}
/*
* @breif 清空發送框
*/
void MainWindow::on_btn_clearSend_clicked()
{
ui->edit_dataSend->clear();
}

效果演示:

2.7 使用串口接收
串口接收有兩種方式:
- 主動查詢
- 等待訊息接收中斷
我們這里介紹第二種,

[signal] void QIODevice::readyRead()
每當有新資料可用于從設備的當前讀取通道讀取時,都會發出此信號, 僅當有新資料可用時(例如,當網路套接字上有新的網路資料有效負載到達時,或將新的資料塊附加到設備上時),它才會再次發出,
readyRead()不會遞回地發出; 如果您重新進入事件回圈或在連接到readyRead()信號的插槽內呼叫waitForReadyRead(),則不會重新發出該信號(盡管waitForReadyRead()可能仍回傳true),
對于實作從QIODevice派生的類的開發人員請注意:當新資料到達時,您應該始終發出readyRead()(不要僅僅因為緩沖區中仍有待讀取的資料而發出它), 在其他情況下不要發出readyRead(),
撰寫接收函式:
void MainWindow::serialPort_readyRead()
{
// 獲取當前時間字串
QDateTime current_date_time =QDateTime::currentDateTime();
QString dateStr =current_date_time.toString("[yyyy-MM-dd hh:mm:ss.zzz]");
//從接識訓沖區中讀取資料
QByteArray buffer = serial_1.readAll();
QString bufferStr = ByteArrayToHexString(buffer);
QString displayStr = dateStr+"\n"+bufferStr+"\n";
//從界面中讀取以前收到的資料
QString oldString = ui->browser_dataReceive->toPlainText();
oldString = oldString + QString(displayStr);
//清空以前的顯示
ui->browser_dataReceive->clear();
//重新顯示
ui->browser_dataReceive->append(oldString);
}
在建構式關聯信號與槽:
//連接信號和槽
connect(&serial_1, &QSerialPort::readyRead, this, &MainWindow::serialPort_readyRead);
效果演示:


3. 在子執行緒實作串口發送與接收
假如我們要對一個串口進行長時間的輪詢監控,我們不可能把它放在GUI執行緒處理,這樣會造成界面卡頓,此時,我們就需要在子執行緒使用串口,具體怎么使用呢?我們將串口指標傳入子執行緒進行處理,
3.1 建立串口事務處理子執行緒類:SerialWorker
點擊 “Add New":

選擇”C++ class“:

設定類屬性:


3.2 修改默認工程
1. 修改 serialworker.h

#ifndef SERIALWORKER_H
#define SERIALWORKER_H
#include <QObject>
#include <QSerialPort>
class SerialWorker : public QObject
{
Q_OBJECT
public:
explicit SerialWorker(QSerialPort *ser,QObject *parent = nullptr);
signals:
private:
QSerialPort *serial;
};
#endif // SERIALWORKER_H
2. 修改 serialworker.cpp

3.3 增加子執行緒串口發送、接收槽函式、結果通知信號
.h檔案:

#ifndef SERIALWORKER_H
#define SERIALWORKER_H
#include <QObject>
#include <QSerialPort>
class SerialWorker : public QObject
{
Q_OBJECT
public:
explicit SerialWorker(QSerialPort *ser,QObject *parent = nullptr);
signals:
void sendResultToGui(QString result);
public slots:
void doDataSendWork(const QByteArray data);
void doDataReciveWork();
private:
QSerialPort *serial;
};
#endif // SERIALWORKER_H
cpp檔案:
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-6KWaX92P-1608952364444)(https://tangxing-markdown-pic.oss-cn-shenzhen.aliyuncs.com/images/20201225162529.png"/>
在mainwindow.cpp 發送資料:
/*
* @breif 發送資料
*/
void MainWindow::on_btn_send_clicked()
{
//獲取界面上的資料并轉換成utf8格式的位元組流
QByteArray data;
if(ui->check_hexSend->isChecked() == true)
data = HexStringToByteArray(ui->edit_dataSend->toPlainText());
else
data = ui->edit_dataSend->toPlainText().toUtf8();
// 在主執行緒發送
//serial_1.write(data);
// 在子執行緒發送
emit serialDataSend(data);
qDebug() << "主執行緒發送信號,執行緒ID:" << QThread::currentThreadId();
}
在mainwindow.cpp 結果結果:
void MainWindow::handleResults(QString &result)
{
qDebug() << "主執行緒收到結果資料:" << result << "執行緒ID:" << QThread::currentThreadId();
}
3.5 在GUI執行緒中添加串口子執行緒
在mainwindow.h定義子執行緒:
QThread serialThread_1; // 定義子執行緒

在mainwindow.h使用串口子執行緒:

MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
InitSerialPortName();
// 1.新建串口處理子執行緒
SerialWorker *serialWorker = new SerialWorker(&serial_1);
serialWorker->moveToThread(&serialThread_1);
// 2.連接信號和槽
connect(&serialThread_1, &QThread::finished,
serialWorker, &QObject::deleteLater); // 執行緒結束,自動洗掉物件
connect(this, &MainWindow::serialDataSend,
serialWorker, &SerialWorker::doDataSendWork); // 主執行緒串口資料發送的信號
connect(&serial_1, &QSerialPort::readyRead,
serialWorker, &SerialWorker::doDataReciveWork); // 主執行緒通知子執行緒接收資料的信號
connect(serialWorker, &SerialWorker::sendResultToGui,
this, &MainWindow::handleResults); // 主執行緒收到資料結果的信號
// 3.開始運行子執行緒
serialThread_1.start(); // 執行緒開始運行
// 在主執行緒接收串口資料
//connect(&serial_1, &QSerialPort::readyRead, this, &MainWindow::serialPort_readyRead);
}
MainWindow::~MainWindow()
{
// 退出串口1子執行緒
serialThread_1.quit();
serialThread_1.wait();
delete ui;
}
3.6 效果演示


文章示例工程下載地址:
https://download.csdn.net/download/u014779536/13790253
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/241417.html
標籤:其他
