QT串列埠助手(三):資料接收

zzssdd2發表於2021-01-23

作者:zzssdd2

E-mail:zzssdd2@foxmail.com

一、前言

開發環境:Qt5.12.10 + MinGW

實現的功能

  • 串列埠資料的接收
  • ascii字元形式顯示與hex字元形式顯示
  • 時間戳的顯示
  • 接收資料的統計與顯示
  • 接收清零

涉及的知識點

  • QSerialPort類的使用
  • 資料格式的轉換
  • QTime類的使用
  • 控制元件QTextEditQCheckBoxQPushButtonQLabel的使用

二、功能實現

下面開始逐步講解以上列舉的功能實現

2.1、資料讀取

《QT串列埠助手(二):引數配置》中已經實現了串列埠引數的配置,引數配置完成後就可以開啟串列埠的資料接收功能了。在QT中的QSerialPort類繼承自QIODevice類,所以可以使用QIODevice的readyRead()訊號來觸發資料的接收,在槽函式中實現資料的讀取與處理。訊號槽連線如下:

/* 接收資料訊號槽 */
connect(serial, &QSerialPort::readyRead, this, &Widget::SerialPortReadyRead_slot);

補充:

[signal]void QIODevice::readyRead()

This signal is emitted once every time new data is available for reading from the device's current read channel. It will only be emitted again once new data is available, such as when a new payload of network data has arrived on your network socket, or when a new block of data has been appended to your device.

readyRead() is not emitted recursively; if you reenter the event loop or call waitForReadyRead() inside a slot connected to the readyRead() signal, the signal will not be reemitted (although waitForReadyRead() may still return true).

Note for developers implementing classes derived from QIODevice: you should always emit readyRead() when new data has arrived (do not emit it only because there's data still to be read in your buffers). Do not emit readyRead() in other conditions.

當有收到新資料訊號時,就會執行槽函式裡面的資料讀取功能:

/*讀取串列埠收到的資料*/
QByteArray bytedata = serial->readAll();

補充:

QByteArray QIODevice::readAll()

Reads all remaining data from the device, and returns it as a byte array.

This function has no way of reporting errors; returning an empty QByteArray can mean either that no data was currently available for reading, or that an error occurred.

2.2、資料轉換

若需要將接收到的資料以HEX格式顯示,則需要對接收到的資料進行以下處理:

/*將資料轉換為hex格式並以空格分隔->去掉頭尾空白字元->轉換為大寫形式*/
framedata = bytedata.toHex(' ').trimmed().toUpper();

補充:

QByteArray QByteArray::toHex(char separator) const

This is an overloaded function.

Returns a hex encoded copy of the byte array. The hex encoding uses the numbers 0-9 and the letters a-f.

If separator is not '\0', the separator character is inserted between the hex bytes.

Example:

QByteArray macAddress = QByteArray::fromHex("123456abcdef");
macAddress.toHex(':'); // returns "12:34:56:ab:cd:ef"
macAddress.toHex(0);   // returns "123456abcdef"

This function was introduced in Qt 5.9.

QByteArray QByteArray::trimmed() const

Returns a byte array that has whitespace removed from the start and the end.

Whitespace means any character for which the standard C++ isspace() function returns true in the C locale. This includes the ASCII characters '\t', '\n', '\v', '\f', '\r', and ' '.

Example:

QByteArray ba("  lots\t of\nwhitespace\r\n ");
ba = ba.trimmed();
// ba == "lots\t of\nwhitespace";

Unlike simplified(), trimmed() leaves internal whitespace alone.

QByteArray QByteArray::toUpper() const

Returns an uppercase copy of the byte array. The bytearray is interpreted as a Latin-1 encoded string.

Example:

QByteArray x("Qt by THE QT COMPANY");
QByteArray y = x.toUpper();
// y == "QT BY THE QT COMPANY"

2.3、新增時間戳

有時為了便於觀察資料收發時間,需要在資料前插入時間戳顯示。使用QTime類中的方法可以獲取當前系統的時間(精確到ms),對資料處理如下:

/*在資料前插入時間戳:[時:分:秒:毫秒]:RX -> 資料*/
framedata = QString("[%1]:RX -> %2").arg(QTime::currentTime().toString("HH:mm:ss:zzz")).arg(framedata);

補充:

[static]QTime QTime::currentTime()

Returns the current time as reported by the system clock.

Note that the accuracy depends on the accuracy of the underlying operating system; not all systems provide 1-millisecond accuracy.

Furthermore, currentTime() only increases within each day; it shall drop by 24 hours each time midnight passes; and, beside this, changes in it may not correspond to elapsed time, if a daylight-saving transition intervenes.

2.4、接收計數

使用一個quint32型別資料對每次接收資料長度進行累加,記錄接收資料總數,然後將資料更新到ui介面:

dataTotalRx += bytedata.length();
ui->RxCnt_label->setText(QString::number(dataTotalRx));

2.5、資料顯示

以上功能完成後將資料顯示到接收框中(為了區分不同顯示格式,做了不同的顏色顯示)。完整的資料接收功能展示如下:

/*
    函   數:SerialPortReadyRead_slot
    描   述:readyRead()訊號對應的資料接收槽函式
    輸   入:無
    輸   出:無
*/
void Widget::SerialPortReadyRead_slot()
{
    QString framedata;
    /*讀取串列埠收到的資料*/
    QByteArray bytedata = serial->readAll();

    /*資料是否為空*/
    if (!bytedata.isEmpty())
    {
        if(ui->HexDisp_checkBox->isChecked())
        {
            /*hex顯示*/
            framedata = bytedata.toHex(' ').trimmed().toUpper();
            ui->Receive_TextEdit->setTextColor(QColor(Qt::green));
        }
        else
        {
            /*ascii顯示*/
            framedata = QString(bytedata);
            ui->Receive_TextEdit->setTextColor(QColor(Qt::magenta));
        }
        
        /*是否顯示時間戳*/
        if (ui->TimeDisp_checkBox->isChecked()) 
        {
            framedata = QString("[%1]:RX -> %2").arg(QTime::currentTime().toString("HH:mm:ss:zzz")).arg(framedata);
            ui->Receive_TextEdit->append(framedata);
        }
        else
        {
            ui->Receive_TextEdit->insertPlainText(framedata);
        }
        
        /*更新接收計數*/
        dataTotalRxCnt += bytedata.length();
        ui->RxCnt_label->setText(QString::number(dataTotalRxCnt));
    }
}

演示效果如下:

補充:

QColor::QColor(Qt::GlobalColor color)

This is an overloaded function.

Constructs a new color with a color value of color.

enum Qt::GlobalColor

Qt's predefined QColor objects:

Constant Value Description
Qt::white 3 White (#ffffff)
Qt::black 2 Black (#000000)
Qt::red 7 Red (#ff0000)
Qt::darkRed 13 Dark red (#800000)
Qt::green 8 Green (#00ff00)
Qt::darkGreen 14 Dark green (#008000)
Qt::blue 9 Blue (#0000ff)
Qt::darkBlue 15 Dark blue (#000080)
Qt::cyan 10 Cyan (#00ffff)
Qt::darkCyan 16 Dark cyan (#008080)
Qt::magenta 11 Magenta (#ff00ff)
Qt::darkMagenta 17 Dark magenta (#800080)
Qt::yellow 12 Yellow (#ffff00)
Qt::darkYellow 18 Dark yellow (#808000)
Qt::gray 5 Gray (#a0a0a4)
Qt::darkGray 4 Dark gray (#808080)
Qt::lightGray 6 Light gray (#c0c0c0)
Qt::transparent 19 a transparent black value (i.e., QColor(0, 0, 0, 0))
Qt::color0 0 0 pixel value (for bitmaps)
Qt::color1 1 1 pixel value (for bitmaps)

2.6、清除接收

清除接收按鍵點選後,會清除接收框顯示的內容以及接收計數。使用QPushButton的點選訊號槽實現如下:

/*
    函   數:on_ClearRx_Bt_clicked
    描   述:清除接收按鍵點選訊號對應的槽函式
    輸   入:無
    輸   出:無
*/
void Widget::on_ClearRx_Bt_clicked()
{
    ui->Receive_TextEdit->clear();
    ui->RxCnt_label->setText(QString::number(0));
    dataTotalRxCnt = 0;
}

三、總結

本篇文章主要是講述如何對串列埠資料進行接收和顯示。除了上面列出的主要功能外,還需要了解各個控制元件的操作方法,比如QTextEdit文字的新增、QLabel文字的設定等。還有就是QT中基本的資料型別的資料使用,比如QStringQBytArray等。

相關文章