Qt中的串口編程之二

來源:互聯網
上載者:User

                                 Qt Serial Port【概述】

   Qt Serial Port提供了基本的功能,包括配置,I/O操作,擷取和設定RS-232引腳的訊號。


本模組暫不支援如下特性:
*終端的特性,例如回顯,控制CR/LF等等
*文字模式
*配置讀操作的逾時和延時
*當RS-232引腳訊號改變的時候跟蹤和通知
要在自己的應用程式中使用這些類,那麼就必須包括如下的聲明:
#include <QtSerialPort/QtSerialPort>
要連結本模組,那麼需要在.pro檔案中添加如下內容:
QT += serialport

【類】

本模組包括兩個類:
QSerialPort:提供訪問串口的功能
QSerialPortInfo:提供系統中存在的串口的資訊

【QSerialPort】

       該類提供訪問串口的功能。你可以使用QSerialPortInfo協助類擷取系統上可用的串口的資訊,可以枚舉系統上存在的所有串口。通過該類你可以擷取串口的正確名稱。你可以傳遞一個該類的對象作為setPort()或者setPortName()方法的參數指定想要訪問的串口裝置。
       在設定完了串口,你就可以以唯讀或者唯寫或者讀寫入模式調用open()方法開啟串口。
注意:串口都是以互斥的方式訪問,這也就是說我們不能開啟一個已經開啟的串口。
        成功開啟之後,QSerialPort嘗試著擷取串口當前的配置並初始化它。你也可以使用setBaudRate(),setDataBits(),setParity(),setStopBits()

和setFlowControl()方法重新設定它。控制管腳的狀態是根據isDataTerminalReady(),isRequestToSend()和pinoutSignals()決定的。要改變控制資訊,可以使用如下方法:setDataTerminalReady()和setRequestToSend()。

        一旦你知道了串口可用於讀或者寫,你就可以調用read()或者write()方法。可選的還有readline()和readAll()方法。如果資料不能在一次讀完,那麼剩下的資料接下來就會存在QSerialPort的內部緩衝區中。你可以使用setReadBufferSize()方法設定緩衝區的大小。可以使用close()方法來關閉串口和取消I/O操作。
看看下面的樣本:

int numRead = 0, numReadTotal = 0;char buffer[50];forever {    numRead  = serial.read(buffer, 50);    // Do whatever with the array    numReadTotal += numRead;    if (numRead == 0 && !serial.waitForReadyRead())        break;}

         在串口串連被關閉或者出現錯誤的時候,waitForReadyRead()就會返回false。
         阻塞的串口編程與非阻塞的串口編程是不一樣的。阻塞的串口不許要事件迴圈,需要的代碼很少。然而,在一個GUI應用程式中,阻塞的串口操作應該僅僅在非GUI線程中使用,避免使用者介面凍結。對於這一點,詳細資料可以查看樣本程式。
         QSerialPort類可以跟QTextStream和QDataStream的流操作一起使用(operator<<()和operator>>())。這裡需要注意一件事:使用操作符operator>>()的重載函數讀取之前請確保有足夠的資料可用。

【QSerialPortInfo】

提供系統中已存在的串口資訊。
使用該類的靜態函數擷取一系列的QSerialPortInfo對象。列表中的每一個QSerialPort對象都代表了一個單獨的串口,可以用於擷取串口名、

系統路徑、描述以及製造商等資訊。QSerialPortInfo類也可以作為QSerialPort類的setPort()方法的一個輸入參數。

【樣本】【樣本一】顯示系統上可用的串口資訊

樣本一展示了如何使用QSerialInfo類擷取系統上可用的串口,顯示所有串口的資訊:

【原始碼】

#include <QTextStream>#include <QCoreApplication>#include <QtSerialPort/QSerialPortInfo>QT_USE_NAMESPACEint main(int argc, char *argv[]){    QCoreApplication a(argc, argv);    QTextStream out(stdout);    QList<QSerialPortInfo> serialPortInfoList = QSerialPortInfo::availablePorts();    out << QObject::tr("Total number of ports available: ") << serialPortInfoList.count() << endl;    foreach (const QSerialPortInfo &serialPortInfo, serialPortInfoList) {        out << endl            << QObject::tr("Port: ") << serialPortInfo.portName() << endl            << QObject::tr("Location: ") << serialPortInfo.systemLocation() << endl            << QObject::tr("Description: ") << serialPortInfo.description() << endl            << QObject::tr("Manufacturer: ") << serialPortInfo.manufacturer() << endl            << QObject::tr("Vendor Identifier: ") << (serialPortInfo.hasVendorIdentifier() ? QByteArray::number(serialPortInfo.vendorIdentifier(), 16) : QByteArray()) << endl            << QObject::tr("Product Identifier: ") << (serialPortInfo.hasProductIdentifier() ? QByteArray::number(serialPortInfo.productIdentifier(), 16) : QByteArray()) << endl            << QObject::tr("Busy: ") << (serialPortInfo.isBusy() ? QObject::tr("Yes") : QObject::tr("No")) << endl;    }    return 0;}
【運行效果如下】

【樣本二】:顯示系統可用串口資訊---圖形介面版本【原始碼】:

#include <QApplication>#include <QWidget>#include <QVBoxLayout>#include <QLabel>#include <QtSerialPort/QSerialPortInfo>QT_USE_NAMESPACEint main(int argc, char *argv[]){    QApplication a(argc, argv);    QWidget w;    w.setWindowTitle(QObject::tr("Info about all available serial ports."));    QVBoxLayout *layout = new QVBoxLayout;    foreach (const QSerialPortInfo &info, QSerialPortInfo::availablePorts()) {        QString s = QObject::tr("Port: ") + info.portName() + "\n"                    + QObject::tr("Location: ") + info.systemLocation() + "\n"                    + QObject::tr("Description: ") + info.description() + "\n"                    + QObject::tr("Manufacturer: ") + info.manufacturer() + "\n"                    + QObject::tr("Vendor Identifier: ") + (info.hasVendorIdentifier() ? QString::number(info.vendorIdentifier(), 16) : QString()) + "\n"                    + QObject::tr("Product Identifier: ") + (info.hasProductIdentifier() ?QString::number(info.productIdentifier(), 16) : QString()) + "\n"                    + QObject::tr("Busy: ") + (info.isBusy() ? QObject::tr("Yes") : QObject::tr("No")) + "\n";        QLabel *label = new QLabel(s);        layout->addWidget(label);    }    w.setLayout(layout);    w.show();    return a.exec();}
【啟動並執行效果如下】:

【樣本三】:阻塞式編程之主裝置

本樣本展示了如何在非GUI線程中使用QSerialPort的同步API。

QSerialPort支援兩種編程方法:

*非同步(非阻塞)方式。當控制權返回到Qt的事件迴圈中,相應的操作就會被調度和執行。當操作執行完了QSerial就會觸發一個訊號。例如:

QSerialPort::write()方法返回。當資料發送到串口,QSerialPort就會觸發bytesWirtten()。

*同步(阻塞)方式。在非GUI和多線程應用程式中,我們可以調用waitFor...()函數(例如QSerialPort::waitForReadyRead())使得調用線程在完成之前都是阻塞的。

        在本樣本中,我們展示如何使用同步的方式,在Terminal樣本中展示如何使用非同步方式。

         本樣本的目的是向你展示一種模式:簡化代碼而不至於使得UI失去響應。Qt中阻塞的串口編程API可以簡化代碼,但是由於它的阻塞特性,所以我們必須只在非GUI線程中使用它。但是跟大多數人相反,使用QThread並不會使得你的應用程式更複雜。

         本樣本是主程式,還有一個與之對應的從程式樣本。主程式通過串口將請求發送給從程式並等待響應。

下面是我們定義的主線程類,它整合自QThread:

【原始碼】

class MasterThread : public QThread{    Q_OBJECTpublic:    MasterThread(QObject *parent = 0);    ~MasterThread();    void transaction(const QString &portName, int waitTimeout, const QString &request);    void run();signals:    void response(const QString &s);    void error(const QString &s);    void timeout(const QString &s);private:    QString portName;    QString request;    int waitTimeout;    QMutex mutex;    QWaitCondition cond;    bool quit;};

線上程的run函數中主要就是向串口中寫入資料,代碼如下:

// write request        QByteArray requestData = currentRequest.toLocal8Bit();        serial.write(requestData);        if (serial.waitForBytesWritten(waitTimeout)) {            // read response            if (serial.waitForReadyRead(currentWaitTimeout)) {                QByteArray responseData = serial.readAll();                while (serial.waitForReadyRead(10))                    responseData += serial.readAll();                QString response(responseData);                emit this->response(response);            } else {                emit timeout(tr("Wait read response timeout %1")                             .arg(QTime::currentTime().toString()));            }        } else {            emit timeout(tr("Wait write request timeout %1")                         .arg(QTime::currentTime().toString()));        }

【樣本四】:阻塞式編程之從裝置

從程式類似上面的,就是起線程,線程從串口中讀取資料:

【原始碼】

       if (serial.waitForReadyRead(currentWaitTimeout)) {//! [7] //! [8]            // read request            QByteArray requestData = serial.readAll();            while (serial.waitForReadyRead(10))                requestData += serial.readAll();//! [8] //! [10]            // write response            QByteArray responseData = currentRespone.toLocal8Bit();            serial.write(responseData);            if (serial.waitForBytesWritten(waitTimeout)) {                QString request(requestData);//! [12]                emit this->request(request);//! [10] //! [11] //! [12]            } else {                emit timeout(tr("Wait write response timeout %1")                             .arg(QTime::currentTime().toString()));            }//! [9] //! [11]        } else {            emit timeout(tr("Wait read request timeout %1")                         .arg(QTime::currentTime().toString()));        }
【運行結果如下】:

【樣本五】:非阻塞編程

       Terminal樣本展示了如何使用Qt Serial Port建立簡單的終端。
        本樣本展示了QSerialPort類的主要特性,例如:配置,I/O實現等等。本樣本也同樣調用了QSerialPortInfo類擷取系統中可用的串口資訊。
QSerialPort支援兩種基本的編程方法:
*非同步(非阻塞)方式。當控制權返回到Qt的事件迴圈中時,操作就得以調度和執行。當操作執行完成了就會QSerialPort就會觸發一個訊號。例如:QSerialPort::write()函數會立即返回,而不會阻塞在寫操作上。當有資料發送到串口,QSerialPort就會觸發bytesWritten()訊號。
*同步(阻塞)方式。在非GUI和多線程應用程式中,可以調用waitFor...()函數(例如:QSerialPort::waitForReadyRead())掛起調用線程,直到操作完成。
         在本樣本中,展示非同步編程方式。
樣本中包含了一些GUI視窗組件:
主視窗:應用程式的主視窗,包括了串口編程的所有邏輯工作,包括配置,I/O處理等等,繼承自QMainWindow。
Console:主視窗的中心組件,顯示發送和接受的資料。該類繼承自QPlainTextEdit類。
設定對話窗:用於配置串口的對話方塊,也顯示了系統上可用的串口的資訊。

【原始碼】

本程式主要展示非同步作業方式,也就是調用write和read函數,並且設定好相應的槽函數。

點擊了connect菜單,就會觸發如下訊號-槽串連

connect(serial, SIGNAL(readyRead()), this, SLOT(readData()));

在終端上輸入字元就會觸發如下訊號-槽串連

connect(console, SIGNAL(getData(QByteArray)), this, SLOT(writeData(QByteArray)));

//! [6]void MainWindow::writeData(const QByteArray &data){    serial->write(data);}//! [6]//! [7]void MainWindow::readData(){    QByteArray data = serial->readAll();    console->putData(data);}//! [7]
【運行效果如下】

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.