【QT】編寫一個簡易的串列埠軟體
簡述
QT學了一點發現學不進去,索性看看能不能直接擼個程式,於是就有了這個簡易的串列埠軟體…
分析需求
這是XCOM串列埠收發軟體,以此為例
目的很明確:
- 串列埠列表要能顯示所有已經接上PC上的COM
- 以我們的配置115200-8-1-N開啟串列埠
- 能收、發
新建一個Qt專案
既然用到串列埠,那麼我們就要在.pro裡增加串列埠的庫
QT += serialport # 串列埠庫
以及mainwindow.h裡新增標頭檔案
#include "qDebug.h" // 除錯輸出用
#include <QtSerialPort/QSerialPort> // 提供訪問串列埠的功能
#include <QtSerialPort/QSerialPortInfo> // 提供系統中存在的串列埠的資訊
先拖控制元件把ui整出來
要注意的是,除了Label,其他的控制元件都記得命名呀,當然你用預設的也行…
開啟串列埠功能
1. 選擇串列埠功能
我們要開啟的串列埠,並不希望他是臨時變數,我們用到的地方多呢!所以就在標頭檔案先定義一個私有成員變數
QSerialPort * serial;
我們希望他在開啟的時候就能載入所有的COM,所以我們在MainWindow裡做這一步,建立視窗的時候就初始化COM列表,順帶著我們為serial開闢空間
// 我們在 ui->setupUi(this); 後面加入這些程式碼即可
// 新增所有串列埠到comboBox裡(串列埠號的名字叫comboBox_COMx)
foreach(const QSerialPortInfo &info, QSerialPortInfo::availablePorts())
{
ui->comboBox_COMx->addItem (info.portName()); //+':'+info.description()
}
serial = new QSerialPort(this);
我們用info去引用一個個的從串列埠的列表裡取出COM的資訊,如果有,我們就把他加入到【串列埠選擇】的下拉欄裡
這個時候如果我們執行,就會發現【串列埠選擇】裡已有了PC上已插入的COM裝置。
2. 開啟串列埠
首先為按鈕【開啟串列埠】新增槽,然後在槽函式裡編寫我們的程式碼:
打開了 總不能就一直開吧,所以我們做了一個開關,通過按鈕上的字來判斷是開還是關
// 點選開啟串列埠
if(ui->pushButton_OpenSerial->text()==tr("開啟串列埠"))
{
ui->pushButton_OpenSerial->setText(tr("關閉串列埠"));
}
else
{
ui->pushButton_OpenSerial->setText(tr("開啟串列埠"));
}
這個時候我們執行,會發現開啟串列埠的按鈕已經可以正常工作了,點選開啟,會顯示關閉按鈕。點選關閉,會顯示開啟按鈕。
按鈕做完了,接著就要做功能了,如果要關閉,我們就可以呼叫serial->close();來關閉串列埠,如果要開啟,我們就去開啟,不過不知道能不能開啟(可能別的程式正在使用),所以加個if判斷一下。
// 點選開啟串列埠
if(ui->pushButton_OpenSerial->text()==tr("開啟串列埠"))
{
ui->pushButton_OpenSerial->setText(tr("關閉串列埠"));
// 設定串列埠號(以當前顯示的COM號為要開啟的串列埠)
serial->setPortName(ui->comboBox_COMx->currentText());
// 以讀寫方式開啟串列埠
if(serial->open(QIODevice::ReadWrite))
{
qDebug() << "Open OK" << endl;
}
else
{
qDebug() << "Open Failed" << endl;
}
}
else
{
ui->pushButton_OpenSerial->setText(tr("開啟串列埠"));
serial->close();
}
現在我們執行一下,看除錯資訊知道目前都是正確的。能正確開關串列埠。
既然打開了串列埠,那麼我們就配置一下串列埠的引數,因為只是一個簡易的,所以就固定死串列埠為8-1-N,把一下程式碼放入成功開啟串列埠的if內。
//設定波特率
serial->setBaudRate(115200);
//設定資料位
serial->setDataBits(QSerialPort::Data8);
//設定校驗位
serial->setParity(QSerialPort::NoParity);
//設定流控制
serial->setFlowControl(QSerialPort::NoFlowControl);
//設定停止位
serial->setStopBits(QSerialPort::OneStop);
這就完了嗎?還沒有,我們配置好了串列埠,如何進行接收呢?我們利用的是QT的訊號與槽機制,當串列埠收到資料,就會發出readyRead()訊號,所以我們利用這個訊號,建立一個槽用來接收字元。
先在標頭檔案定義private slots函式 void recv_data(void);
然後我們緊接著剛剛配置串列埠後面寫上connect()來連線訊號與槽
connect(serial, SIGNAL(readyRead()), this, SLOT(recv_data()));
這樣我們點選開啟訊號與槽後,就會配置串列埠,啟用訊號與槽。
現在萬事俱備,只欠東風,我們繼續寫槽函式recv_data()來接收串列埠的資料
仔細思考一下,平時在用串列埠軟體的時候,有新的資料發來會自動出現在舊的資料後面。
所以我們的做法是,先暫時儲存顯示的資料,然後把讀到的資料加在後面,再清除顯示的資料,把合成的資料再顯示出來,就達到我們的效果了。
void MainWindow::recv_data(void)
{
qDebug() << "Recv Data" << endl;
QByteArray buf = serial->readAll();
if(!buf.isEmpty())
{
QString str = ui->textEdit_ReceiveMsg->toPlainText();
str+=tr(buf);
ui->textEdit_ReceiveMsg->clear();
ui->textEdit_ReceiveMsg->append(str);
}
}
這個時候我們執行一下,開啟串列埠,用微控制器來發資料,實測已經可以正確顯示在螢幕上了
3. 傳送資料
對於傳送資料,有了剛才的經驗就比較簡單了。
為UI的【傳送】鍵新增一個槽函式,當我們點選【傳送】時,串列埠就傳送我們寫入的資訊。
所以我們在傳送的槽函式內寫入:
// 先讀取我們寫入的文字
QString str = ui->textEdit_SendMsg->toPlainText().toLatin1();
qDebug() << str <<endl;
// 寫入
serial->write(str.toLatin1());
串列埠的write函式的引數有兩個
- 第一個是char *型別,所以我們要str轉char *,用的.toLatin1()來轉換。
- 第二個是傳入字元最大數量(我選擇不設定所以沒填)
此時我們再執行,發現收發都正常了。
附上我的完整程式碼(不包含UI,看控制元件的英文名字應該能對上圖片)
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QtSerialPort/QSerialPort> // 提供訪問串列埠的功能
#include <QtSerialPort/QSerialPortInfo> // 提供系統中存在的串列埠的資訊
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private slots:
void on_pushButton_OpenSerial_clicked();
void recv_data(void);
void on_pushButton_SendMsg_clicked();
void on_pushButton_ClearRecv_clicked();
private:
Ui::MainWindow *ui;
QSerialPort *serial;
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "qDebug.h"
#include "QObject"
#include "QTimer"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
// 初始化
// 新增所有串列埠到comboBox裡(串列埠號的名字叫comboBox_COMx)
foreach(const QSerialPortInfo &info, QSerialPortInfo::availablePorts())
{
ui->comboBox_COMx->addItem(info.portName()); //+':'+info.description()
}
serial = new QSerialPort(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::recv_data(void)
{
qDebug() << "Recv Data" << endl;
QByteArray buf = serial->readAll();
if(!buf.isEmpty())
{
QString str = ui->textEdit_ReceiveMsg->toPlainText();
str+=tr(buf);
ui->textEdit_ReceiveMsg->clear();
ui->textEdit_ReceiveMsg->append(str);
}
}
void MainWindow::on_pushButton_OpenSerial_clicked()
{
// 點選開啟串列埠
if(ui->pushButton_OpenSerial->text()==tr("開啟串列埠"))
{
ui->pushButton_OpenSerial->setText(tr("關閉串列埠"));
// 開闢空間
//serial = new QSerialPort(this);
// 設定串列埠號
serial->setPortName(ui->comboBox_COMx->currentText());
// 以讀寫方式開啟串列埠
if(serial->open(QIODevice::ReadWrite))
{
qDebug() << "Open OK" << endl;
// 此處寫死為 8-1-N
//設定波特率
serial->setBaudRate(115200);
//設定資料位
serial->setDataBits(QSerialPort::Data8);
//設定校驗位
serial->setParity(QSerialPort::NoParity);
//設定流控制
serial->setFlowControl(QSerialPort::NoFlowControl);
//設定停止位
serial->setStopBits(QSerialPort::OneStop);
connect(serial, SIGNAL(readyRead()), this, SLOT(recv_data()));
}
else
{
qDebug() << "Open Failed" << endl;
}
}
else
{
ui->pushButton_OpenSerial->setText(tr("開啟串列埠"));
serial->close();
}
}
void MainWindow::on_pushButton_SendMsg_clicked()
{
QString str = ui->textEdit_SendMsg->toPlainText().toLatin1();
qDebug() << str <<endl;
serial->write(str.toLatin1());
}
void MainWindow::on_pushButton_ClearRecv_clicked()
{
ui->textEdit_ReceiveMsg->clear();
}
收尾
其實還有很多其他的功能可以加進去,我就多做了一個【清除接收】…
甚至還有BUG…就是隻有開啟軟體的時候才載入已有COM口,所以還要加上點選下拉框的時候就掃描更新一遍。
此時的波特率、停止位啥的都是寫死的,所以真正要做完的話,還需要把這些控制元件都做上
還有等等等等…
哈哈 主要功能做出來了,其他的往上新增就好了。
打包exe教程 https://blog.csdn.net/syzdev/article/details/80860619
over…