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(""));
}

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

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