目录

一、准备

二、预备知识

QSerialPortInfo类

QSerialPort类


最近在使用QT5进行一些嵌入式系统及Linux平台上的开发,对于QT我是一个入门者,最近在使用QT5开发一个串口读取设备配置的功能中遇到了一些问题,后来虽然最终解决了,想到可能后来者也会在这方面遇到问题,所以写下这么一篇文章记录下来,供后来者参考和交流。

一、准备

首先说明一下,我使用的QT版本是Windows上的Qt5.14.1,编译环境是MinGW-64(好像是5.12之前MinGW默认是32位的),如下图所示:

在Qt5中关于串口编程的主要有两个类:QSerialPort和QSerialPortInfo。其中QSerialPort提供了操作串口的一些方法(如打开、关闭等),而QSerialPortInfo用来表示串口的一系列静态属性(如获取所有串口)。题外话,在Qt中这样成双成对出现的类有很多,如QFile/QFileInfo、QFont/QFontInfo、QCamera/QCameraInfo、QPrinter/QPrinterInfo,其关联和区别也是类似。

在QT5中要进行串口开发,首先需要引入相应的模块,具体做法就是在项目的pri或pro中添加serialport,如下面就是我进行串口开发的功能模块中的定义:

QT       += core gui serialport

上面的配置表示除了核心模块core之外还使用了gui和serialport模块。

当然除了在代码项目级配置外,还需要在具体使用串口的代码处引入QSerialPortInfo或QSerialPort。

一般用下面的方式即可:

#include <QSerialPortInfo>
#include <QSerialPort>

二、预备知识

QSerialPortInfo类

QSerialPortInfo提供了获取设备串口的方法,QSerialPortInfo::availablePorts()方法可用于获取当前运行程序的系统上所有可连接的串口情况,下面的代码可以获取到当前系统上的所有串口信息:

    QString description;
    QString manufacturer;
    QString serialNumber;
    QString portName;
    const auto infos = QSerialPortInfo::availablePorts();
    for (const QSerialPortInfo &info : infos) {
        QStringList list;
        description = info.description();//串口描述
        manufacturer = info.manufacturer();//串口设备制造商
        serialNumber = info.serialNumber();//串口序列号
        portName=info.portName();//串口描述

    }

QSerialPort类

QSerialPort类继承自QIODevice类,提供了串口操作的功能,串口相关的属性有:串口对象(用PortName关联)、波特率(BaudRate)、数据位(DataBits)、停止位(StopBits)、奇偶校验(Parity)、硬件流控(FlowControl)等几个属性。

以上属性出PortName外都有相应的枚举分别规定它们可能的取值,如下图:

 

 

从每个枚举的最后一个value为-1的值就可以看得出上面每个枚举分别对应QSerialPort类的哪个属性了。

QSerialPort类用父类QIODevice类提供的write()方法写入数据,用一系列read()读取数据,另外其本身提供了open(OpenMode mode)和close()方法来打开和关闭端口。同时还提供了两个有用信号(signal)用于数据读取和错误控制。readyRead()信号用于读取数据控制,每当收到新的数据时会触发这个信号。而当串口通信过程中发生错误会触发errorOccurred()信号。

需要注意的是,我们向串口写入以数据后,串口设备的响应可能不是一次全部数据,你可以想象一下你用一个9600bit的Modem打开一个100KB网页的情况。比如我用来查询设备的某些配置信息,你在命令行上看到的这样的:

下面是我用一个串口监听工具监听到的情况:

两相对比,你可以看到输入一条命令,对方的响应可能是多个,有时候是几个字符,有时候可能是仅仅一个字符,但是每一次都会readyRead()信号事件。很多初次接触QT串口编程的人会踩到这个坑,从一些串口交互工具上看到的是输入一条命令就会得到一段响应数据,编写对应的槽函数与readyRead()信号关联,以为调用QSerialPort类的readAll()方法就可以读取到全部的响应数据了,结果发现根本不对。

在我做的项目中有一个功能,就是通过数十条查询命令通过串口查询设备状态,然后再将每条查询命令对应的响应保存起来并进行分析,因此需要区分每条查询命令对应的响应。在这里有几种办法,第一种是通过waitForReadyRead(int msecs = 30000)方法来读取,也就是写入命令后等待msecs毫秒后触发readyRead(),然后在关联的槽函数中读取数据。还有一种办法就是通过计时器QTimer来实现,在我的项目中我就是通过这种方式来实现的。

Logo

更多推荐