天天看點

Qt之序列槽類QSerialPort使用筆記

本文轉載自:http://blog.csdn.net/liyuanbhu/article/details/45540825

        雖然現在大多數的家用PC機上已經不提供RS232接口了。但是由于RS232序列槽操作簡單、通訊可靠,在工業領域中仍然有大量的應用。Qt以前的版本中,沒有提供官方的對RS232序列槽的支援,編寫序列槽程式很不友善。現在好了,在 Qt5.1 中提供了QtSerialPort子產品,友善程式設計人員快速的開發應用序列槽的應用程式。 本文就簡單的講講QtSerialPort子產品的使用。

目前的QtSerialPort子產品中提供了兩個C++類,分别是QSerialPort 和QSerialPortInfo。

     QSerialPort 類提供了操作序列槽的各種接口。

     QSerialPortInfo 是一個輔助類,可以提供計算機中可用序列槽的各種資訊。

使用方法

        先介紹 QSerialPortInfo 的使用。下面是一個簡單的例子,用來列舉出電腦上全部的序列槽裝置。

首先,需要在pro檔案中增加如下内容:

QT += serialport

Cpp 檔案如下:

#include <QCoreApplication>
#include <QDebug>
 
#include <QSerialPort>
#include <QSerialPortInfo>
 
int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    foreach (const QSerialPortInfo &info, QSerialPortInfo::availablePorts())
    {
        qDebug() << "Name : " << info.portName();
        qDebug() << "Description : " << info.description();
        qDebug() << "Manufacturer: " << info.manufacturer();
        qDebug() << "Serial Number: " << info.serialNumber();
        qDebug() << "System Location: " << info.systemLocation();
    }
    return a.exec();
}
           

在我的電腦上顯示的結果如下:

Name :  "COM1"
Description :  "通信端口"
Manufacturer:  "(标準端口類型)"
Serial Number:  ""
System Location:  "\\.\COM1"
Name :  "COM5"
Description :  "USB Serial Port"
Manufacturer:  "FTDI"
Serial Number:  "A400G3UXA"
System Location:  "\\.\COM5"
           

        通常,我們需要指定程式使用某一個确定的序列槽,這時不能隻使用序列槽名稱,因為USB序列槽每次插在不同的USB口上時獲得的序列槽名稱都可能有變化。這時可以利用序列槽的序列号,這個号碼一般來說是唯一的,比如下面的代碼,首先周遊所有的序列槽,找到我們需要的序列槽後就傳回。

#include <QCoreApplication>
#include <QDebug>
#include <QSerialPort>
#include <QSerialPortInfo>

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    QSerialPortInfo com_info;
    foreach (const QSerialPortInfo &info, QSerialPortInfo::availablePorts())
    {
        if( info.serialNumber() == "A400G3UXA" )
        {
            com_info = info;
            break;
        }
    }
    qDebug() << "Name : " << com_info.portName();
    qDebug() << "Description : " << com_info.description();
    qDebug() << "serialNumber: " << com_info.serialNumber();
    return a.exec();
}
           

QSerialPort支援兩種程式設計方法:

(1)*異步(非阻塞)方式。當控制權傳回到Qt的事件循環中,相應的操作就會被排程和執行。當操作執行完了QSerial就會觸發一個信号。例如:

QSerialPort::write()方法傳回。當資料發送到序列槽,QSerialPort就會觸發bytesWirtten()。

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

        阻塞的序列槽程式設計與非阻塞的序列槽程式設計是不一樣的。阻塞的序列槽不許要事件循環,需要的代碼很少。然而,在一個GUI應用程式中,阻塞的序列槽操作應該僅僅在非GUI線程中使用,避免使用者界面當機。對于這一點,詳細資訊可以檢視示例程式。

        QSerialPort 負責具體的序列槽操作。標明序列槽後,要先打開序列槽,才能設定波特率等參數。這些參數都設定好了就可以使用了。最基本的操作無非是read() 和 write()。需要注意的是這兩個操作都是非阻塞的。

        另外有一個重要的signal 也需要用到,那就是 void QIODevice::readyRead(),每次序列槽收到資料後都會發出這個signal。我們的程式中需要定義一個slot,并将其與這個signal 相連接配接。這樣,每次新資料到來後,我們就可以在slot中讀取資料了。這時一定要将序列槽緩沖區中的資料全部讀出來,可以利用readAll() 來實作。

下面的代碼片段給出了設定序列槽的例子。

m_reader.setPort(info);
if(m_reader.open(QIODevice::ReadWrite))
{
   qDebug() << "m_reader.open(QIODevice::ReadWrite)";
   m_reader.setBaudRate(QSerialPort::Baud9600);
   m_reader.setParity(QSerialPort::NoParity);
   m_reader.setDataBits(QSerialPort::Data8);
   m_reader.setStopBits(QSerialPort::OneStop);
   m_reader.setFlowControl(QSerialPort::NoFlowControl);

   m_reader.clearError();
   m_reader.clear();
   connect(&m_reader, SIGNAL(readyRead()), this, SLOT(readyReadSlot()));
}


void Dialog::readyReadSlot()
{
    qDebug() << "x";
    QByteArray arr = m_reader.readAll();
    do_something(arr);
}
           

繼續閱讀