目录

1、头文件

2、工程文件

3、实现

3.1、扫描串口

3.2、配置串口

3.3、打开串口

3.4、读取数据

3.5、发送数据


 

早在 QT4 时代,那时候 QT 并没有实现串口相关的类,记得那时候写的一个上位机是使用了老外实现的一个串口类(具体的类名字忘记了,反正很长)并调用了它的接口,到了 QT5 时代,QT 库已经自带了串口相关的类,这里主要聊下这么使用这个玩意,并自己简单的实现了一个串口 Demo;

先上图为证:

android开发 qt 串口 qt串口程序_串口

对应的代码已经上传到:《用 QT 实现的串口收发程序》

实现的部分包括:

1、扫描当前可用的串口

2、配置串口参数

3、开启串口并显示状态

4、进行接收(支持 Hex 和 Char 显示)和清屏

5、发送数据(支持 Hex 和 Char 发送)

6、显示/清除当前接收和发送的数据总数

那么下面就来简述一下整个过程

 

1、头文件

在 QT5 版本中,和串口相关的头文件主要需要包含:

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

 

2、工程文件

打开你的 QT 工程文件(xxx.pro),在其中添加如下:

QT       += serialport

 

3、实现

在做完1、2步骤后,就可以使用串口类了,最主要使用到的类是 QSerialPort 还有一个辅助的类 QSerialPortInfo

 

3.1、扫描串口

一般的,在使用串口之前呢,都需要先去轮询当前有哪些串口可用,这里用到 QSerialPortInfo 类:

void HiSerialPortMainWindow::ScanPort()
{
    qDebug()<<tr("扫描存在的串口");

    ui->progressBar->setValue(20);

    ui->progressBar->reset();
    ui->portComboBox->clear();

    foreach (const QSerialPortInfo &info, QSerialPortInfo::availablePorts()){
        qDebug() << "Name        : " << info.portName();
        qDebug() << "Description : " << info.description();
        qDebug() << "Manufacturer: " << info.manufacturer();
        qDebug() << "isBusy(): " << info.isBusy();

        ui->portComboBox->addItem(info.portName());
    }

    ui->progressBar->setValue(100);
}

这个ScanPort 是一个 SLOT,对应的就是按下 【Scan Ports】这个 QPushButton 的时候的响应函数;函数中轮询了当前系统中的所有串口,并将其名字添加到了串口的 QComboBox 中;我们需要通过下拉菜单选择期望打开的那个串口;

 

3.2、配置串口

在使用串口之前呢,不仅仅需要指定哪一个串口,还需要对它进行配置,包含波特率、停止位、数据位、校验位等等;这里我们主要使用到了 QSerialPort 类,首先需要定义它:

HiSerialPort = new QSerialPort();

配置的时候呢,需要调用它的一些列接口:

HiSerialPort->setPortName(ui->portComboBox->currentText());
HiSerialPort->setBaudRate(getBaud());
HiSerialPort->setParity(getParity());
HiSerialPort->setDataBits(getDataBits());
HiSerialPort->setStopBits(getStopBits());
// TODO: FlowControl
HiSerialPort->setFlowControl(QSerialPort::NoFlowControl);
HiSerialPort->setReadBufferSize(1024);

这里,由于下拉菜单获取到的都是 QString,在调用串口配置的代码里需要进行一些转换,这里直接贴代码,不多说:

enum QSerialPort::BaudRate HiSerialPortMainWindow::getBaud()
{
    bool ok;
    enum QSerialPort::BaudRate ret;
    switch (ui->baudComboBox->currentText().toLong(&ok, 10))
    {
        case 1200:
            ret = QSerialPort::Baud1200;
        break;
        case 2400:
            ret = QSerialPort::Baud2400;
            break;
        case 4800:
            ret = QSerialPort::Baud4800;
            break;
        case 9600:
            ret = QSerialPort::Baud9600;
            break;
        case 19200:
            ret = QSerialPort::Baud19200;
            break;
        case 38400:
            ret = QSerialPort::Baud38400;
            break;
        case 57600:
            ret = QSerialPort::Baud57600;
            break;
        case 115200:
            ret = QSerialPort::Baud115200;
            break;
        default:
            ret = QSerialPort::UnknownBaud;
            break;
    }
    return ret;
}

enum QSerialPort::Parity HiSerialPortMainWindow::getParity()
{
    QString CurrentParityBit = ui->ParityBitComboBox->currentText();

    if (CurrentParityBit == "None")      return QSerialPort::NoParity;
    else if (CurrentParityBit == "Odd")  return QSerialPort::OddParity;
    else if (CurrentParityBit == "Even") return QSerialPort::EvenParity;
    return QSerialPort::UnknownParity;
}

enum QSerialPort::DataBits HiSerialPortMainWindow::getDataBits()
{
    QString CurrentDataBits = ui->dataBitComboBox->currentText();

    if (CurrentDataBits == "5")      return QSerialPort::Data5;
    else if (CurrentDataBits == "6") return QSerialPort::Data6;
    else if (CurrentDataBits == "7") return QSerialPort::Data7;
    else if (CurrentDataBits == "8") return QSerialPort::Data8;
    return QSerialPort::UnknownDataBits;
}

enum QSerialPort::StopBits HiSerialPortMainWindow::getStopBits()
{
    QString CurrentStopBits = ui->stopBitComboBox->currentText();

    if (CurrentStopBits == "1")        return QSerialPort::OneStop;
    else if (CurrentStopBits == "1.5") return QSerialPort::OneAndHalfStop;
    else if (CurrentStopBits == "2")   return QSerialPort::TwoStop;
    return QSerialPort::UnknownStopBits;
}

 

3.3、打开串口

配置完毕后,当然是打开串口,开启的方式以读写的方式打开:

HiSerialPort->open(QSerialPort::ReadWrite)

这个 open 有一个 bool 类型的返回值,ture 为打开成功,false 为打开失败;

 

3.4、读取数据

QSerialPort 类实现了一个 SIGNAL,为 readyRead(),即,当有数据的时候,会产生这个 SIGNAL,所以我们自己定义好 SLOT ,并在自己定义的这个 SLOT 函数(ReadSerialData())中去拿去串口数据:

void HiSerialPortMainWindow::ReadSerialData()
{
    QByteArray buffer = HiSerialPort->readAll();
    QString Str;

    if (!buffer.isEmpty())
    {
        if (RXFormatAsHex)
        {
            int data_len = buffer.length();
            // Handle the Hex Case
            for (int var = 0; var < data_len; var++)
            {
                QString tempStr;
                tempStr = QString::number(buffer.at(var), 16);
                if (buffer.at(var) < 0x10)
                {
                    tempStr = "0" + tempStr;
                }
                tempStr = /*"0x" + */tempStr.toUpper() + " ";

                Str += tempStr;
            }
        }
        else
        {
            Str = buffer;
        }

        ui->textBrowser->moveCursor(QTextCursor::End);
        ui->textBrowser->insertPlainText(Str);

        RXCount += buffer.size();
        UpdateLCDNumber(0);
    }
}

拿串口数据的方式是通过调用 QSerialPort 的 readAll() 接口,返回的是 QByteArray 类型的数据,读到的数据就放在这里;

这里需要注意两点:

1、比如对方发送 0x11、0x22、0x33、0x44、0x55,的数据,很可能会触发很多次 ReadSerialData() 调用,并不是收完这 5 个数据,才会触发一次,但是读走的数据,下次不会重复读到,这点可以放心

2、这里需要去判断读取的 QByteArray 的 buffer 是不是空,调试的时候遇到过,空数据,也触发了一次进入这个函数

 

3.5、发送数据

串口的数据发送是靠调用 QSerialPort 的 write 接口实现,传入的数据依然是 QByteArray 类型:

void HiSerialPortMainWindow::WriteSerialData()
{
    QByteArray data;

    if (!CurrentSerialPortOpened)
    {
        QMessageBox::warning(this,tr("Warning"),
                             tr("Please Open Port First"),QMessageBox::Ok);
        return;
    }

    if (TXFormatAsHex)
    {
        QString Str = ui->sendContentlineEdit->text();
        QStringList DataList = Str.split(" ");
        qDebug() << "DataList " << DataList;

        for(int i = 0; i < DataList.length(); i++)
        {
            bool ok;
            QString tempStr = DataList.at(i);
            if (tempStr != " " && tempStr != "")
            {
                qDebug() << "tempStr " << tempStr;
                data.append((char)tempStr.toInt(&ok, 16));
            }
        }
         qDebug() << "Send QByteArray  "<< data;
         HiSerialPort->write(data);

         TXCount += data.size();
    }
    else
    {
        QByteArray ba = ui->sendContentlineEdit->text().toLatin1();
        HiSerialPort->write(ba.data());
        TXCount += ba.size();
    }
    UpdateLCDNumber(1);
}

这里我对数据进行了 Hex 或者 Char 的处理,以及 QLineEdit 的按照空格切分;

其他的没啥了,亲测可用,经验证与下位机收发数据(Hex 和 Char)均正常。