QT開發的串列埠通訊軟體(基於qextserialport工具)
阿新 • • 發佈:2018-12-08
研一上了楊迎澤老師的一門《列車網路與通訊》課程,課程的最後老師給我們分配的小作業居然是寫上位機控制一臺程控電流源,我在查閱了這臺程控電流源的手冊後,發現它的通訊方式是串列埠,而且在串列埠通訊的基礎上指定了一套詳細的通訊協議,基於此,我花了小半天的時間做了一個上位機,完成了任務,這裡主要分享一下基於QT開發串列埠助手的一些程式碼,具體是基於qextserialport的串列埠通訊開源類庫實現的,上位機介面如下圖,介面比較簡陋。
完整工程點選如下連結:https://download.csdn.net/download/qq_18108083/10798653
(1) main.cpp
#include "mainwindow.h" #include <QApplication> int main(int argc, char *argv[]) { QTextCodec::setCodecForTr(QTextCodec::codecForName("UTF8")); //保證正常顯示中文 QTextCodec::setCodecForLocale(QTextCodec::codecForName("UTF8")); QTextCodec::setCodecForCStrings(QTextCodec::codecForName("UTF8")); QApplication a(argc, argv); MainWindow w; w.show(); return a.exec(); }
(2) mainwindow.cpp
#include "mainwindow.h" #include "ui_mainwindow.h" MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); //建立定時器 timer =new QTimer(this); //按鈕狀態初始化 ui->openMyComBtn->setEnabled(true); //開啟串列埠後“開啟串列埠”按鈕不可用 ui->closeMyComBtn->setEnabled(false); //開啟串列埠後“關閉串列埠”按鈕可用 ui->sendMsgBtn->setEnabled(false); //開啟串列埠後“傳送資料”按鈕可用 connect(ui->openMyComBtn,SIGNAL(clicked(bool)),this,SLOT(startSerialPort())); //關聯開啟串列埠槽函式 connect(ui->closeMyComBtn,SIGNAL(clicked(bool)),this,SLOT(closeSerialPort())); //關聯關閉串列埠槽函式 connect(ui->sendMsgBtn,SIGNAL(clicked(bool)),this,SLOT(sendMessage())); //關聯傳送資料槽函式 connect(ui->voltDial,SIGNAL(valueChanged(int)),this,SLOT(voltValueSet(int))); //關聯設定電壓槽函式 connect(this->timer,SIGNAL(timeout()),this,SLOT(timeOut())); //關聯定時器溢位槽函式 } MainWindow::~MainWindow() { delete ui; } void MainWindow::startSerialPort() //開啟串列埠槽函式 { /* //定義一個結構體,用來存放串列埠各個引數 struct PortSettings myComSetting = {BAUD115200,DATA_8,PAR_NONE,STOP_1,FLOW_OFF,500}; //波特率,資料位,奇偶校驗,停止位,資料流控制(延時)等 //定義串列埠物件,並傳遞引數,在建構函式裡對其進行初始化 myCom = new Win_QextSerialPort("com8",myComSetting,QextSerialBase::EventDriven); //串列埠 //以可讀寫方式開啟串列埠 myCom ->open(QIODevice::ReadWrite); //訊號和槽函式關聯,當串列埠緩衝區有資料時,進行讀串列埠操作 connect(myCom,SIGNAL(readyRead()),this,SLOT(readMyCom())); //按鈕狀態轉換 ui->openMyComBtn->setEnabled(false); //開啟串列埠後“開啟串列埠”按鈕不可用 ui->closeMyComBtn->setEnabled(true); //開啟串列埠後“關閉串列埠”按鈕可用 ui->sendMsgBtn->setEnabled(true); //開啟串列埠後“傳送資料”按鈕可用 */ //獲取串列埠名 QString portName = ui->portNameComboBox->currentText(); //定義串列埠物件,並傳遞引數,在建構函式裡對其進行初始化 myCom = new Win_QextSerialPort(portName,QextSerialBase::EventDriven); //開啟串列埠 myCom ->open(QIODevice::ReadWrite); //根據組合框內容對串列埠進行設定 //設定波特率 QString baudValue=ui->baudRateComboBox->currentText(); baudValue = "BAUD"+baudValue; ui->debugLabel->setText(baudValue); if(ui->baudRateComboBox->currentText()==tr("1200")) myCom->setBaudRate(BAUD1200); else if(ui->baudRateComboBox->currentText()==tr("2400")) myCom->setBaudRate(BAUD2400); else if(ui->baudRateComboBox->currentText()==tr("4800")) myCom->setBaudRate(BAUD4800); else if(ui->baudRateComboBox->currentText()==tr("9600")) myCom->setBaudRate(BAUD9600); else if(ui->baudRateComboBox->currentText()==tr("14400")) myCom->setBaudRate(BAUD14400); else if(ui->baudRateComboBox->currentText()==tr("19200")) myCom->setBaudRate(BAUD19200); else if(ui->baudRateComboBox->currentText()==tr("38400")) myCom->setBaudRate(BAUD38400); else if(ui->baudRateComboBox->currentText()==tr("57600")) myCom->setBaudRate(BAUD57600); else if(ui->baudRateComboBox->currentText()==tr("115200")) myCom->setBaudRate(BAUD115200); else if(ui->baudRateComboBox->currentText()==tr("128000")) myCom->setBaudRate(BAUD128000); else if(ui->baudRateComboBox->currentText()==tr("256000")) myCom->setBaudRate(BAUD256000); //設定資料位 if(ui->dataBitsComboBox->currentText()==tr("8")) myCom->setDataBits(DATA_8); else if(ui->dataBitsComboBox->currentText()==tr("7")) myCom->setDataBits(DATA_7); //設定奇偶校驗 if(ui->parityComboBox->currentText()==tr("無")) myCom->setParity(PAR_NONE); else if(ui->parityComboBox->currentText()==tr("奇")) myCom->setParity(PAR_ODD); else if(ui->parityComboBox->currentText()==tr("偶")) myCom->setParity(PAR_EVEN); //設定停止位 if(ui->stopBitsComboBox->currentText()==tr("1")) myCom->setStopBits(STOP_1); else if(ui->stopBitsComboBox->currentText()==tr("2")) myCom->setStopBits(STOP_2); //設定資料流控制,我們使用無資料流控制的預設設定 myCom->setFlowControl(FLOW_OFF); //設定延時 myCom->setTimeout(500); //訊號和槽函式關聯,當串列埠緩衝區有資料時,進行讀串列埠操作 connect(myCom,SIGNAL(readyRead()),this,SLOT(readMyCom())); //按鈕狀態轉換 ui->openMyComBtn->setEnabled(false); //開啟串列埠後“開啟串列埠”按鈕不可用 ui->closeMyComBtn->setEnabled(true); //開啟串列埠後“關閉串列埠”按鈕可用 ui->sendMsgBtn->setEnabled(true); //開啟串列埠後“傳送資料”按鈕可用 ui->baudRateComboBox->setEnabled(false); //設定各個組合框不可用 ui->dataBitsComboBox->setEnabled(false); ui->parityComboBox->setEnabled(false); ui->stopBitsComboBox->setEnabled(false); ui->portNameComboBox->setEnabled(false); isSerialOpen = true; } void MainWindow::closeSerialPort() //關閉串列埠槽函式 { myCom->close(); //關閉串列埠,該函式在win_qextserialport.cpp檔案中定義 //按鈕狀態轉換 ui->openMyComBtn->setEnabled(true); //關閉串列埠後“開啟串列埠”按鈕可用 ui->closeMyComBtn->setEnabled(false); //關閉串列埠後“關閉串列埠”按鈕不可用 ui->sendMsgBtn->setEnabled(false); //關閉串列埠後“傳送資料”按鈕不可用 ui->baudRateComboBox->setEnabled(true); //設定各個組合框可用 ui->dataBitsComboBox->setEnabled(true); ui->parityComboBox->setEnabled(true); ui->stopBitsComboBox->setEnabled(true); ui->portNameComboBox->setEnabled(true); } void MainWindow::sendMessage() //傳送資料槽函式 { //以ASCII碼形式將行編輯框中的資料寫入串列埠 // myCom->write() myCom->write(ui->sendMsgLineEdit->text().toAscii()); } void MainWindow::readMyCom() //讀串列埠資料槽函式 { //讀取串列埠緩衝區的所有資料給臨時變數temp QByteArray temp = myCom->readAll(); //將串列埠的資料顯示在視窗的文字瀏覽器中 ui->textBrowser->insertPlainText(temp+"\n"); ui->textBrowser->moveCursor(QTextCursor::End); if(serReadMode == 1) //串列埠讀功能的工作模式, 1.讀電壓 2.讀電流 0.正常讀 { QString str = temp; int size = str.size(); qDebug("index size:%d",size); if(size > 0) { qDebug("str is:%s",str.toLatin1().data()); //將qstring轉換成char* qDebug("str num is:%f",str.toDouble()); //將qstring轉換成double ui->voltValueLcd->display(str.toDouble()); } //int index = str.indexOf("\n"); //str = str.left(index); //qDebug("index size:%s",str.toLatin1().data()); //將qstring轉換成char* } } void MainWindow::voltValueSet(int volt) //設定電壓值槽函式 (帶引數) { //ui->voltValueLcd->display(volt); //ui->debugLabel->setText(QString::number(volt,10)); if(isSerialOpen) { if(timeoutFlag) //定時器延時已到 { timeoutFlag = false; this->timer->stop(); //首先關閉定時器 this->timer->start(100); //開啟定時器 單位毫秒 QString setVolt = "VOLTage " + QString::number(volt,10) + "\n"; QString queryVolt = "VOLTage?\n"; //myCom->write(setVolt.toAscii()); //傳送獲取控制電壓命令 //myCom->write(queryVolt.toAscii()); //傳送獲取控制電壓命令 //ui->textBrowser->insertPlainText(setVolt); //將命令新增到工作日誌 //ui->textBrowser->insertPlainText(queryVolt); myCom->write(QString::number(volt,10).toAscii()); //傳送獲取控制電壓命令 serReadMode = 1; //串列埠讀功能的工作模式, 1.讀電壓 2.讀電流 0.正常讀 //ui->outputStaLight->setStyleSheet("background-color: #ff3333;"); } } else { QMessageBox::information(this,"提示:","未開啟串列埠"); } } void MainWindow::curValueSet() //設定電流值槽函式 { } void MainWindow::timeOut() //定時器溢位 { this->timer->stop(); //首先關閉定時器 timeoutFlag = true; // QMessageBox::information(this,"提示:","定時器時間溢位"); }
(3) mainwindow.h
#ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> #include <QDebug> #include <QTextCodec>//保證正常顯示中文 #include "win_qextserialport.h" //引入第三方庫 #include <QMessageBox> #include <QTimer> //定時器 #include <QDebug> namespace Ui { class MainWindow; } class MainWindow : public QMainWindow { Q_OBJECT public: explicit MainWindow(QWidget *parent = 0); ~MainWindow(); private: Ui::MainWindow *ui; Win_QextSerialPort *myCom; //宣告物件 QTimer *timer; //定義定時器指標 bool isSerialOpen = false; //串列埠開啟標誌 bool timeoutFlag = true; //定時器溢位標誌 unsigned char serReadMode = 0; //串列埠讀功能的工作模式, 1.讀電壓 2.讀電流 0.正常讀 private slots: void readMyCom(); //新增讀槽函式 void startSerialPort(); //開啟串列埠槽函式 void closeSerialPort(); //關閉串列埠槽函式 void sendMessage(); //傳送資料槽函式 void voltValueSet(int volt); //設定電壓值槽函式 void curValueSet(); //設定電流值槽函式 void timeOut(); //定時器溢位 }; #endif // MAINWINDOW_H