Qt串口通訊例子(再也不用擔心串口問題了)

       很多小夥伴們對串口編程剛上手時,不知道如何下手,本例子帶大家看看一個簡單的串口通訊的例子,例子是網上的demo,這裏簡單的介紹下:

這是我們常見的界面窗口,下面我們來解析下代碼部分:

串口步驟:

* 1.設置串口參數

* 2.打開串口

* 3.讀/寫串口

* 4.關閉串口

#ifndef SERIALPORT_H
#define SERIALPORT_H

#include <QMainWindow>
#include <QtSerialPort/QSerialPort>
#include <QtSerialPort/QSerialPortInfo>

#include <QLabel>
#include <QPushButton>
#include <QCloseEvent>

namespace Ui {
class SerialPort;
}

class SerialPort : public QMainWindow
{
    Q_OBJECT

public:
    explicit SerialPort(QWidget *parent = 0);
    ~SerialPort();

    /* 初始狀態欄 */
    void InitStatusBar();   // 初始化狀態欄
    void SetSerState();     // 設置狀態欄串口狀態
    void SetRecvNum();      // 設置接收字節數
    void SetSendNum();      // 設置發送字節數

    /* 初始化CombBox控件 */
    void InitCommCmb();         // 初始化CombBox控件
    void SetPortNumCmb();       // 設置串口號
    QStringList GetEnableCommPortQt();      // 獲取計算機可用串口 Qt方式
    QStringList GetEnableCommPortWin();     // 獲取計算機可用串口 Windows API方式
    QString GetComm(int nIndex, bool bValue = true);
    void SetBaudCmb();          // 設置波特率
    void SetDPaityCmb();        // 設置校驗位
    void SetDataBCmb();         // 設置數據位
    void SetStopBCmb();         // 設置停止位
    void SetStreamCmb();        // 設置流控制

    bool SetSerialPortParam(QSerialPort *serial);   // 設置串口參數,失敗返回false,成功返回true

    /* 父類函數重寫 */
    void closeEvent(QCloseEvent *event);

private slots:
    void on_baudRCmb_currentIndexChanged(int index);    // 自定義波特率
    void on_OnOffBtn_clicked();                         // 打開/斷開串口
    void on_ReflushSerPortBtn_clicked();    // 刷新串口,重新掃描計算機可用串口
    void slot_RecvPortData();               // 接收串口數據
    void on_SendBtn_clicked();              // 發送數據
    void on_ClearRecvBtn_clicked();         // 清空接收區
    void slot_ResetNumBtn_clicked();          // 復位計數

private:
    Ui::SerialPort *ui;

    /* 狀態欄控件 */
    QLabel *m_SerStateLbl;        // 串口狀態
    QLabel *m_RecvNumLbl;         // 接收字節數
    QLabel *m_SendNumLbl;         // 發送字節數
    QPushButton *m_ResetNumBtn;   // 復位計數按鈕

    /* 發送、接收字節數 */
    uint m_nRecvNum;              // 接收字節數
    uint m_nSendNum;              // 發送字節數
    bool m_bOpen;                 // 標識串口狀態

    QSerialPort *m_serial;        // 串口通信類對象
    qint64 m_nReadBuffSize;       // 串口緩衝區大小
};

#endif // SERIALPORT_H

對應 cpp:

函數初始化:

SerialPort::SerialPort(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::SerialPort)
{
    ui->setupUi(this);

    this->setWindowTitle(tr("串口調試助手 Qt版 V1.0"));
    this->setFixedSize(this->width(), this->height());

    m_nRecvNum = 0;
    m_nSendNum = 0;
    m_bOpen = false;

    InitStatusBar();
    InitCommCmb();

    ui->OnOffBtn->setIcon(QIcon(":/pic/res/OFF.png"));
    ui->RecvDataEdt->setReadOnly(true);

    m_serial = new QSerialPort;
    connect(m_serial, SIGNAL(readyRead()), this, SLOT(slot_RecvPortData()));
    m_nReadBuffSize = 64;

}

 InitStatusBar() 初始化狀態欄:

void SerialPort::InitStatusBar()
{
    m_SerStateLbl = new QLabel();
    m_RecvNumLbl = new QLabel();
    m_SendNumLbl = new QLabel();
    m_ResetNumBtn = new QPushButton();
    connect(m_ResetNumBtn, SIGNAL(clicked()), this, SLOT(slot_ResetNumBtn_clicked()));

    m_SerStateLbl->setMinimumSize(180, 20);
    m_RecvNumLbl->setMinimumSize(180, 20); // 標籤最小尺寸
    m_SendNumLbl->setMinimumSize(180, 20);

    ui->statusBar->addWidget(m_SerStateLbl);
    ui->statusBar->addWidget(m_RecvNumLbl);
    ui->statusBar->addWidget(m_SendNumLbl);
    ui->statusBar->addWidget(m_ResetNumBtn);

    SetSerState();
    SetRecvNum();
    SetSendNum();
    m_ResetNumBtn->setText(tr("復位計數"));
}

 其中對應的set個個的函數:

void SerialPort::SetSerState()
{
    QString strState;
    if ( m_bOpen )
        strState = tr("打開");
    else
        strState = tr("關閉");

    m_SerStateLbl->setText(tr("串口狀態:%1").arg(strState));
}

void SerialPort::SetRecvNum()
{
    QString strRecvNum = QString::number(m_nRecvNum);
    m_RecvNumLbl->setText(tr("接收字節數:%1").arg(strRecvNum));
}

void SerialPort::SetSendNum()
{
    QString strSendNum = QString::number(m_nSendNum);
    m_SendNumLbl->setText(tr("發送字節數:%1").arg(strSendNum));
}

其目的在狀態欄上顯示對應的接收數據,並顯示在狀態欄上面。

InitCommCmb()  初始化CombBox

void SerialPort::InitCommCmb()
{
    SetPortNumCmb();    // 串口號
    SetBaudCmb();       // 波特率
    SetDPaityCmb();     // 校驗位
    SetDataBCmb();      // 數據位
    SetStopBCmb();      // 停止位
    SetStreamCmb();     // 流控制
}

這些函數是初始化最基本的東西:串口號,波特率,校驗位,數據位,停止位,流控制(這個用的較少)

// 設置串口號
void SerialPort::SetPortNumCmb()
{
    QStringList commPortList = GetEnableCommPortQt();
    if ( !commPortList.isEmpty() )
        ui->PortNumCmb->addItems(commPortList);
}
// 獲取計算機可用串口 QSerialPort QSerialPortInfo類
QStringList SerialPort::GetEnableCommPortQt()
{
    QStringList CommPortList;

    foreach (const QSerialPortInfo &info, QSerialPortInfo::availablePorts())
    {
        QSerialPort serial;
        serial.setPort(info);
        if (serial.open(QIODevice::ReadWrite))
        {
            CommPortList.append(serial.portName());
            serial.close();
        }
    }

    return CommPortList;
}

 這個可以尋找當前串口號,然後添加到對應的選項框。

波特率:

 // 設置波特率
void SerialPort::SetBaudCmb()
{
    QStringList baudRList;
    baudRList.append(tr("110"));
    baudRList.append(tr("300"));
    baudRList.append(tr("600"));
    baudRList.append(tr("1200"));
    baudRList.append(tr("2400"));
    baudRList.append(tr("4800"));
    baudRList.append(tr("9600"));
    baudRList.append(tr("14400"));
    baudRList.append(tr("19200"));
    baudRList.append(tr("38400"));
    baudRList.append(tr("56000"));
    baudRList.append(tr("57600"));
    baudRList.append(tr("115200"));
    baudRList.append(tr("128000"));
    baudRList.append(tr("256000"));
    baudRList.append(tr("自定義"));

    ui->baudRCmb->addItems(baudRList);
    ui->baudRCmb->setCurrentIndex(6);
}

校驗位

void SerialPort::SetDPaityCmb()
{
    QStringList DPaityList;
    DPaityList.append(tr("NONE"));
    DPaityList.append(tr("ODD"));
    DPaityList.append(tr("EVEN"));
    DPaityList.append(tr("MARK"));
    DPaityList.append(tr("SPACE"));

    ui->DPaityCmb->addItems(DPaityList);
}

 數據位:

 // 設置數據位
void SerialPort::SetDataBCmb()
{
    for (int i = 5; i <= 8; i++)
    {
        QString strDataB = QString::number(i);
        ui->DataBCmb->addItem(strDataB);
    }
    ui->DataBCmb->setCurrentIndex(3);
}

停止位

// 設置停止位
void SerialPort::SetStopBCmb()
{
    ui->StopBCmb->addItem(tr("1"));
    ui->StopBCmb->addItem(tr("1.5"));
    ui->StopBCmb->addItem(tr("2"));
}

流控制:

// 流控制
void SerialPort::SetStreamCmb()
{
    ui->FlowCtrlCmb->addItem(tr("NO"));
    ui->FlowCtrlCmb->addItem(tr("RTS/CTS"));
    ui->FlowCtrlCmb->addItem(tr("XON/XOFF"));
}

初始化結束後,我們開始第二歩:

打開串口

// 打開/關閉串口
void SerialPort::on_OnOffBtn_clicked()
{
    if (m_serial->isOpen()) // 已經處於打開狀態,則關閉串口
    {
        m_serial->close();
        ui->OnOffBtn->setText(tr("打開"));
        ui->OnOffBtn->setIcon(QIcon(":/pic/res/OFF.png"));
        m_bOpen = false;
        SetSerState();
    }
    else // 串口處於關閉狀態,打開串口
    {
        if ( !SetSerialPortParam(m_serial) )
        {
            QMessageBox::critical(this, tr("Error"), tr("串口錯誤!"), QMessageBox::Ok);
            return;
        }

        // 打開串口
        if ( !m_serial->open(QIODevice::ReadWrite) ) // 打開失敗
        {
            QMessageBox::critical(this, tr("Error"), tr("串口不存在或者被其它程序佔用!"), QMessageBox::Ok);
            // QString strRecv = ui->RecvDataEdt->toPlainText();
            // strRecv += tr("\n【Error】Can't Open COM Port!");
            ui->RecvDataEdt->append(tr("\n【Error】Can't Open COM Port!"));
            return;
        }

        // 設置串口緩衝區大小
        m_serial->setReadBufferSize(m_nReadBuffSize);

        ui->OnOffBtn->setText(tr("斷開"));
        ui->OnOffBtn->setIcon(QIcon(":/pic/res/ON.png"));
        m_bOpen = true;
        SetSerState();
    }
}
// 設置串口參數,失敗返回false,成功返回true
bool SerialPort::SetSerialPortParam(QSerialPort *serial)
{
    // 設置串口號
    QString strPortNum = ui->PortNumCmb->currentText();
    if (strPortNum == tr(""))
        return false;
    serial->setPortName(strPortNum);

    // 設置波特率
    qint32 nBaudRate = ui->baudRCmb->currentText().toInt();
    serial->setBaudRate(nBaudRate);

    // 設置奇偶校驗
    int nParityType = ui->DPaityCmb->currentIndex();
    switch (nParityType)
    {
    case 0:
        serial->setParity(QSerialPort::NoParity);
        break;
    case 1:
        serial->setParity(QSerialPort::OddParity);
        break;
    case 2:
        serial->setParity(QSerialPort::EvenParity);
        break;
    case 3:
        serial->setParity(QSerialPort::MarkParity);
        break;
    case 4:
        serial->setParity(QSerialPort::SpaceParity);
        break;
    default:
        serial->setParity(QSerialPort::UnknownParity);
        break;
    }

    // 設置數據位
    int nDataBits = ui->DataBCmb->currentIndex();
    switch (nDataBits)
    {
    case 0:
        serial->setDataBits(QSerialPort::Data5);
        break;
    case 1:
        serial->setDataBits(QSerialPort::Data6);
        break;
    case 2:
        serial->setDataBits(QSerialPort::Data7);
        break;
    case 3:
        serial->setDataBits(QSerialPort::Data8);
        break;
    default:
        serial->setDataBits(QSerialPort::UnknownDataBits);
        break;
    }

    // 設置停止位
    int nStopBits = ui->StopBCmb->currentIndex();
    switch (nStopBits)
    {
    case 0:
        serial->setStopBits(QSerialPort::OneStop);
        break;
    case 1:
        serial->setStopBits(QSerialPort::OneAndHalfStop);
        break;
    case 2:
        serial->setStopBits(QSerialPort::TwoStop);
        break;
    default:
        serial->setStopBits(QSerialPort::UnknownStopBits);
        break;
    }

    // 流控制
    int nFlowCtrl = ui->FlowCtrlCmb->currentIndex();
    switch (nFlowCtrl)
    {
    case 0:
        serial->setFlowControl(QSerialPort::NoFlowControl);
        break;
    case 1:
        serial->setFlowControl(QSerialPort::HardwareControl);
        break;
    case 2:
        serial->setFlowControl(QSerialPort::SoftwareControl);
        break;
    default:
        serial->setFlowControl(QSerialPort::UnknownFlowControl);
        break;
    }

    return true;
}

發送數據,接收數據:

// 槽函數,接收串口數據
void SerialPort::slot_RecvPortData()
{
    QByteArray bytes = m_serial->readAll();

    if ( !bytes.isEmpty() )
    {
        QString strRecv = QString::fromLocal8Bit(bytes);
        ui->RecvDataEdt->append(strRecv);

        m_nRecvNum += bytes.count();
        SetRecvNum();
    }
    else
        ui->RecvDataEdt->setText(tr("接收數據出錯!"));
}

// 發送數據,寫串口
void SerialPort::on_SendBtn_clicked()
{
    // 串口未打開
    if ( !m_bOpen )
    {
        QMessageBox::warning(this, tr("Error"), tr("串口未打開,發送失敗!"), QMessageBox::Ok);
        return;
    }

    QByteArray SendBytes = ui->SendDataEdt->toPlainText().toLocal8Bit();
    if ( !SendBytes.isEmpty() )
    {
        m_serial->write(SendBytes);
        m_nSendNum += SendBytes.count();
        SetSendNum();
    }
}

這裏如果想顯示16進制,可以把代碼給爲下面:

QByteArray buffer = tcpClient->readAll();
    int  length =  buffer.count();
    if(!buffer.isEmpty())
    {
      for(int i = 0; i<length; i++)
      {
        ui->textEdit_2->append(QString::asprintf("%0.2X ",buffer.at(i)));
      }
//        ui->textEdit_2->append(buffer.toHex()); //16進制顯示出來數據
    }

這樣輸出的就是大寫的16進制的數據啦。

其他槽函數

// 串口關閉事件,如果窗口關閉前串口未關閉,則關閉串口
void SerialPort::closeEvent(QCloseEvent *event)
{
    if (m_serial->isOpen())
        m_serial->close();

    event->accept();
}

// 波特率自定義
void SerialPort::on_baudRCmb_currentIndexChanged(int index)
{
    uint nCount = ui->baudRCmb->count();
    if ((unsigned)index == nCount - 1)
    {
        ui->baudRCmb->setEditable(TRUE);
        ui->baudRCmb->setItemText(index, tr(""));
    }
    else
    {
        ui->baudRCmb->setEditable(FALSE);
        ui->baudRCmb->setItemText(nCount-1, tr("自定義"));
    }
}

// 刷新串口
void SerialPort::on_ReflushSerPortBtn_clicked()
{
    ui->PortNumCmb->clear();
    SetPortNumCmb();
}

// 復位計數
void SerialPort::slot_ResetNumBtn_clicked()
{
    m_nSendNum = 0;
    m_nRecvNum = 0;
    SetSendNum();
    SetRecvNum();
}

// 清空接受區
void SerialPort::on_ClearRecvBtn_clicked()
{
    ui->RecvDataEdt->setText(tr(""));
}

需要例子的可以私信我,關注我。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章