QT开发--串口通信

news2024/12/31 5:39:32

第十六章 串口通信

16.1 串口通信基础

串口通信主要通过DB9接口,适用于短距离(<10米)。关键参数包括:

  • 波特率:每秒传输bit数,如9600。
  • 数据位:信息包中的有效数据位数。
  • 停止位:单个包的最后一位,通常为1或2位。
  • 奇偶校验位:检错方式,分偶、奇校验。

16.1.1 QtSerialPort模块简介

        QtSerialPort是QT5的附加模块,为硬件和虚拟串口提供接口。它简化串口应用开发,提供配置、I/O操作等功能。

        使用QtSerialPort,需包含以下头文件:

#include <QSerialPortInfo>  
#include <QSerialPort>

        并在.pro文件中添加:

QT += serialport

        QSerialPort类用于访问串口

        QSerialPortInfo用于获取串口信息

        可通过setPort()setPortName()设置要访问的串口

        使用open()close()打开和关闭串口

        串口打开后,可使用setBaudRate()等函数重新配置。

        waitForReadyRead()waitForBytesWritten()用于阻塞操作。

16.1.2 QSerialPort 成员函数

构造函数:

// 构造一个未初始化的QSerialPort对象,可选指定父对象  
QSerialPort::QSerialPort(QObject *parent = nullptr)  
  
// 构造并初始化QSerialPort对象,指定端口名和可选的父对象  
QSerialPort::QSerialPort(const QString &name, QObject *parent = nullptr)  
  
// 构造并初始化QSerialPort对象,根据QSerialPortInfo指定端口信息和可选的父对象  
QSerialPort::QSerialPort(const QSerialPortInfo &serialPortInfo, QObject *parent = nullptr)

关键方法:

        bool atEnd() const:检查是否有数据可读

        qint64 bytesAvailable() const:返回可读数据字节数

        qint64 bytesToWrite() const:返回可写数据字节数

        void close():关闭串口。

        void setPort(const QSerialPortInfo &serialPortInfo):设置串口信息

        void setPortName(const QString &name):设置串口名

        //波特率改变时触发信号

        [signal] void baudRateChanged(qint32 baudRate, //新的波特率
                        QSerialPort::Directions directions)          //波特率用于哪方

/*检查是否有数据可读,无数据可读返回true*/
[virtual] bool QSerialPort::atEnd() const;

/*波特率改变后,信号触发*/
[signal] void QSerialPort::baudRateChanged(qint32 baudRate, //新的波特率
                        QSerialPort::Directions directions) //波特率用于哪方
/*
QSerialPort::AllDirections //默认,表示读写方向都应用此波特率
QSerialPort::Input         //仅用于输入方向
QSerialPort::Output        //仅用于输出方向
*/

/*返回可读数据的字节数*/
[virtual] qint64 QSerialPort::bytesAvailable() const;

/*返回可写数据的字节数*/
[virtual] qint64 QSerialPort::bytesToWrite() const;

/*关闭串口*/
[virtual] void QSerialPort::close();

/*设置串口端口信息为 serialPortInfo*/
void QSerialPort::setPort(const QSerialPortInfo &serialPortInfo);

/*设置串口名为name*/
void QSerialPort::setPortName(const QString &name);

16.2 QSerialPortInfo

16.2.1 QSerialPortInfo 简介

        QSerialPortInfo 类用于提供系统中已有串口设备的信息。可通过其静态成员函数获取代表各串口的 QSerialPortInfo 对象链表。每个对象包含端口的详细信息,如端口名、系统位置、描述、制造商等,并可用于配置 QSerialPort 对象

16.2.2 QSerialPortInfo 成员函数

构造函数

QSerialPortInfo(const QSerialPort &port);  
QSerialPortInfo(const QString &name);  
QSerialPortInfo(const QSerialPortInfo &other);

静态成员函数

static QList<QSerialPortInfo> availablePorts(); // 返回可用串口链表  
static QList<qint32> standardBaudRates();      // 返回标准波特率链表

成员函数

QString description() const;         // 返回串口描述  
bool hasProductIdentifier() const; // 是否有生产编码  
bool hasVendorIdentifier() const; // 是否有制造商编码  
bool isBusy() const;               // 串口是否正忙  
QString manufacturer() const;     // 返回制造商名称  
QString portName() const;         // 返回串口名称  
quint16 productIdentifier() const; // 返回生产编码  
QString serialNumber() const;    // 返回序列号  
QString systemLocation() const; // 返回系统位置  
quint16 vendorIdentifier() const; // 返回制造商编码  
void swap(QSerialPortInfo &other); // 交换两个对象

16.3 实现简易串口

打开/关闭串口:

        当点击“打开串口”按钮时,配置串口参数并尝试打开串口。如果成功,禁用串口配置ComboBox,启用发送按钮,并更改按钮文本为“关闭串口”。

        同时连接串口的 readyRead信号到 readData槽函数。

        当点击“关闭串口”按钮时(即串口已打开状态),关闭串口,重新启用串口配置ComboBox,更改按钮文本为“打开串口”,并禁用发送按钮。

数据发送与接收:

        点击发送按钮时,将发送文本框中的内容以Latin1编码写入串口。

        点击清空接收/发送数据按钮时,清空相应的文本框内容。

        当串口有数据可读时,readData槽函数被调用,读取所有可用数据,并将其追加到接收文本框中。

#ifndef MAINWINDOW_H // 防止头文件重复包含,如果已定义MAINWINDOW_H则不再次包含  
#define MAINWINDOW_H  
  
// 包含必要的Qt库头文件  
#include <QMainWindow> // 主窗口类  
#include <QSerialPort> // 串口通信类  
#include <QSerialPortInfo> // 串口信息类,用于获取系统中可用的串口信息  
#include <QList> // 用于存储串口信息列表  
#include <QDebug> // 用于调试输出  
  
// Ui命名空间,包含UI类的声明(通常由Qt Designer生成)  
namespace Ui {  
class MainWindow;  
}  
  
// MainWindow类,继承自QMainWindow  
class MainWindow : public QMainWindow {  
    Q_OBJECT // 使用Qt的宏,允许该类使用信号和槽机制  
  
public:  
    // 构造函数,explicit关键字防止隐式转换  
    explicit MainWindow(QWidget *parent = 0);   
    // 析构函数  
    ~MainWindow();  
  
private slots:  
    // 私有槽函数,用于处理UI按钮点击事件  
    void on_btn_openConsole_clicked(); // 打开控制台按钮点击事件处理  
    void on_btn_send_clicked(); // 发送按钮点击事件处理  
    void on_btn_clearRecv_clicked(); // 清空接收区按钮点击事件处理  
    void on_btn_clearSend_clicked(); // 清空发送区按钮点击事件处理  
    void readData(); // 读取串口数据  
  
private:  
    // Ui类的指针,用于访问UI元素  
    Ui::MainWindow *ui;   
    // QSerialPort类的指针,用于串口通信  
    QSerialPort *serial;  
};  
  
#endif // MAINWINDOW_H // 结束头文件保护
#include "mainwindow.h"  
#include "ui_mainwindow.h"  
  
// 定义一个静态常量字符串,用于表示“不可用”或“无数据”的情况  
static const char blankString[] = QT_TRANSLATE_NOOP("SettingsDialog", "N/A");  
  
// MainWindow类的构造函数实现  
MainWindow::MainWindow(QWidget *parent) :  
    QMainWindow(parent), // 调用基类的构造函数  
    ui(new Ui::MainWindow) { // 初始化UI类的指针  
    ui->setupUi(this); // 设置UI界面  
  
    // 初始化串口类的指针  
    serial = new QSerialPort;  
  
    // 用于存储串口描述、制造商、序列号等信息的字符串  
    QString description;  
    QString manufacturer;  
    QString serialNumber;  
  
    // 获取系统中可用的串口信息列表  
    QList<QSerialPortInfo> serialPortInfos = QSerialPortInfo::availablePorts();  
  
    // 输出当前系统可以使用的串口个数  
    qDebug() << "Total numbers of ports: " << serialPortInfos.count();  
  
    // 遍历所有可用的串口信息,并将其添加到ComboBox中  
    for (const QSerialPortInfo &serialPortInfo : serialPortInfos) {  
        QStringList list; // 用于存储串口信息的字符串列表  
        description = serialPortInfo.description(); // 获取串口描述  
        manufacturer = serialPortInfo.manufacturer(); // 获取制造商信息  
        serialNumber = serialPortInfo.serialNumber(); // 获取序列号  
  
        // 将串口的相关信息添加到列表中,如果信息为空则使用blankString代替  
        list << serialPortInfo.portName()  
             << (!description.isEmpty() ? description : blankString)  
             << (!manufacturer.isEmpty() ? manufacturer : blankString)  
             << (!serialNumber.isEmpty() ? serialNumber : blankString)  
             << serialPortInfo.systemLocation()  
             << (serialPortInfo.vendorIdentifier() ? QString::number(serialPortInfo.vendorIdentifier(), 16) : blankString)  
             << (serialPortInfo.productIdentifier() ? QString::number(serialPortInfo.productIdentifier(), 16) : blankString);  
  
        // 将串口名称作为第一项,其余信息作为关联数据添加到ComboBox中  
        ui->comboBox_serialPort->addItem(list.first(), list);  
    }  
  
    // 添加一个自定义选项到串口ComboBox中  
    ui->comboBox_serialPort->addItem(tr("custom"));  
  
    // 设置波特率的ComboBox选项  
    ui->comboBox_baudRate->addItem(QStringLiteral("9600"), QSerialPort::Baud9600);  
    ui->comboBox_baudRate->addItem(QStringLiteral("19200"), QSerialPort::Baud19200);  
    ui->comboBox_baudRate->addItem(QStringLiteral("38400"), QSerialPort::Baud38400);  
    ui->comboBox_baudRate->addItem(QStringLiteral("115200"), QSerialPort::Baud115200);  
    ui->comboBox_baudRate->addItem(tr("Custom"));  
  
    // 设置数据位的ComboBox选项  
    ui->comboBox_dataBits->addItem(QStringLiteral("5"), QSerialPort::Data5);  
    ui->comboBox_dataBits->addItem(QStringLiteral("6"), QSerialPort::Data6);  
    ui->comboBox_dataBits->addItem(QStringLiteral("7"), QSerialPort::Data7);  
    ui->comboBox_dataBits->addItem(QStringLiteral("8"), QSerialPort::Data8);  
    ui->comboBox_dataBits->setCurrentIndex(3); // 默认选择8数据位  
  
    // 设置奇偶校验位的ComboBox选项  
    ui->comboBox_parity->addItem(tr("None"), QSerialPort::NoParity);  
    ui->comboBox_parity->addItem(tr("Even"), QSerialPort::EvenParity);  
    ui->comboBox_parity->addItem(tr("Odd"), QSerialPort::OddParity);  
    ui->comboBox_parity->addItem(tr("Mark"), QSerialPort::MarkParity);  
    ui->comboBox_parity->addItem(tr("Space"), QSerialPort::SpaceParity);  
  
    // 设置停止位的ComboBox选项  
    ui->comboBox_stopBit->addItem(QStringLiteral("1"), QSerialPort::OneStop);  
    ui->comboBox_stopBit->addItem(QStringLiteral("2"), QSerialPort::TwoStop);  
  
    // 设置流控的ComboBox选项  
    ui->comboBox_flowBit->addItem(tr("None"), QSerialPort::NoFlowControl);  
    ui->comboBox_flowBit->addItem(tr("RTS/CTS"), QSerialPort::HardwareControl);  
    ui->comboBox_flowBit->addItem(tr("XON/XOFF"), QSerialPort::SoftwareControl);  
  
    // 初始禁用发送按钮  
    ui->btn_send->setEnabled(false);  
}  
  
// MainWindow类的析构函数实现  
MainWindow::~MainWindow() {  
    delete ui; // 释放UI类的指针所指向的内存  
}  
  
// 打开串口按钮的槽函数实现  
void MainWindow::on_btn_openConsole_clicked() {  
    qDebug() << ui->btn_openConsole->text(); // 输出按钮的当前文本  
    if (ui->btn_openConsole->text() == tr("打开串口")) {  
        // 配置串口参数  
        serial->setPortName(ui->comboBox_serialPort->currentText()); // 设置串口名称  
        serial->setBaudRate(ui->comboBox_baudRate->currentText().toInt()); // 设置波特率  
        serial->setDataBits(QSerialPort::Data8); // 设置数据位  
        serial->setParity(QSerialPort::NoParity); // 设置奇偶校验位  
        serial->setStopBits(QSerialPort::OneStop); // 设置停止位  
        serial->setFlowControl(QSerialPort::NoFlowControl); // 设置流控  
  
        // 尝试打开串口  
        if (serial->open(QIODevice::ReadWrite)) {  
            // 禁用串口配置相关的ComboBox  
            ui->comboBox_baudRate->setEnabled(false);  
            ui->comboBox_dataBits->setEnabled(false);  
            ui->comboBox_flowBit->setEnabled(false);  
            ui->comboBox_parity->setEnabled(false);  
            ui->comboBox_serialPort->setEnabled(false);  
            ui->comboBox_stopBit->setEnabled(false);  
  
            // 启用发送按钮  
            ui->btn_send->setEnabled(true);  
  
            // 更改按钮文本  
            ui->btn_openConsole->setText(tr("关闭串口"));  
  
            // 连接串口的readyRead信号到readData槽函数  
            connect(serial, &QSerialPort::readyRead, this, &MainWindow::readData);  
        }  
    } else {  
        // 关闭串口  
        serial->close(); // 关闭串口连接  
  
        // 重新启用串口配置相关的ComboBox  
        ui->comboBox_baudRate->setEnabled(true);  
        ui->comboBox_dataBits->setEnabled(true);  
        ui->comboBox_flowBit->setEnabled(true);  
        ui->comboBox_parity->setEnabled(true);  
        ui->comboBox_serialPort->setEnabled(true);  
        ui->comboBox_stopBit->setEnabled(true);  
  
        // 更改按钮文本  
        ui->btn_openConsole->setText(tr("打开串口"));  
  
        // 禁用发送按钮  
        ui->btn_send->setEnabled(false);  
    }  
}  
  
// 发送数据按钮的槽函数实现  
void MainWindow::on_btn_send_clicked() {  
    // 将发送文本框中的内容以Latin1编码写入串口  
    serial->write(ui->textEdit_send->toPlainText().toLatin1());  
}  
  
// 清空接收数据按钮的槽函数实现  
void MainWindow::on_btn_clearRecv_clicked() {  
    ui->textEdit_recv->clear(); // 清空接收文本框的内容  
}  
  
// 清空发送数据按钮的槽函数实现  
void MainWindow::on_btn_clearSend_clicked() {  
    ui->textEdit_send->clear(); // 清空发送文本框的内容  
}  
  
// 读取串口数据的槽函数实现  
void MainWindow::readData() {  
    QByteArray buf; // 定义一个字节数组用于存储读取到的数据  
    qDebug() << "readData: " << endl; // 输出调试信息  
    buf = serial->readAll(); // 从串口读取所有可用数据  
    if (!buf.isEmpty()) { // 如果读取到的数据不为空  
        QString str = ui->textEdit_recv->toPlainText(); // 获取接收文本框的当前内容  
        str += tr(buf); // 将读取到的数据追加到字符串中(注意:这里tr的使用可能是不必要的,除非需要翻译字节数组的内容)  
        ui->textEdit_recv->clear(); // 清空接收文本框的内容  
        ui->textEdit_recv->append(str); // 将更新后的字符串添加到接收文本框中  
    }  
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2212381.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Excel:vba实现禁止新增工作表

实现效果&#xff1a;禁止新增工作表 步骤如下&#xff1a; 1.点击开发工具里面的Visual Basic 2.不要自己创建&#xff0c;点击ThisWorkbook&#xff0c;点击选择Workbook&#xff0c;点击选择NewSheet 这里的NewSheet就是工作簿事件 代码如下&#xff1a; 这是事件处理程序…

day∞-过滤器-拦截器

一、过滤器 二、拦截器

【Java面试——基础知识——Day5】

1. 异常 1.1 Exception 和 Error 有什么区别&#xff1f; 在 Java 中&#xff0c;所有的异常都有一个共同的祖先 java.lang 包中的 Throwable 类。Throwable 类有两个重要的子类: Exception :程序本身可以处理的异常&#xff0c;可以通过 catch 来进行捕获。Exception 又可以…

二叉树LeetCode刷题

二叉树LeetCode刷题 1. 检查两颗树是否相同2. 另一颗树的子树3. 翻转二叉树4. 判断一颗二叉树是否是平衡二叉树5. 二叉搜索树与双向链表6. 对称二叉树7. 二叉树的构建及遍历8. 二叉树的分层遍历9. 给定一个二叉树, 找到该树中两个指定节点的最近公共祖先10. 根据一棵树的前序遍…

算法竞赛(Python)-AI的思维模式(搜索)

文章目录 一 、深度优先搜索1 零钱搭配2“油漆桶”与连通性 二 、记忆化三、在游戏中制胜的AI1 永远的平局——井字棋2 一起来解谜——数独3 数字华容道 一 、深度优先搜索 深度优先搜索是最基本的搜索方法&#xff0c;在深度优先搜索的过程中&#xff0c;如果把所有的可行解看…

如果你的YOLO环境已经配置好了,如何打开项目文件

1.首先将【目标检测系统源码】下载完成之后&#xff0c;解压到某个路径下&#xff08;可以解压在D盘或者F盘都可&#xff09;。然后使用Pycharm打开这个项目文件。 2.使用 pip 命令安装所需的依赖&#xff0c;可以通过requirements.txt文件进行安装。请务必按照 requirements.t…

springboot第76集:线程,ThreadGroup

导出数据&#xff1a; 查询结果可以使用脚本或工具&#xff08;如 Python 的 Pandas 库&#xff09;将数据导出为 Excel 格式。例如&#xff0c;使用 Python&#xff1a; 当查询数组中有大量数据&#xff08;如一千多条&#xff09;时&#xff0c;可以使用 _mget&#xff08;多…

系统分析师17:系统安全分析与设计

1 内容概述 2 对称加密与非对称加密技术 在信息安全领域&#xff0c;对称加密和非对称加密是两种最常见的加密技术。它们各自有不同的特点和应用场景&#xff0c;下面将详细介绍这两种加密技术。 2.1 对称加密 2.1.1 概念 对称加密是指使用相同的密钥&#xff08;也称为密钥…

opencv学习:风格迁移对图像风格进行更改

介绍&#xff1a; 风格迁移是一种计算机视觉技术&#xff0c;它能够让一张图片看起来像是用另一种风格画出来的。想象一下&#xff0c;你有一张普通的照片&#xff0c;但你希望它看起来像是梵高的印象派画作&#xff0c;或者像是某个著名艺术家的作品&#xff0c;风格迁移就可以…

C语言 ——— oj题:搜索插入位置

目录 题目要求 代码实现 题目要求 给定一个排序数组和一个目标值&#xff0c;在数组中找到目标值&#xff0c;并返回其索引。如果目标值不存在于数组中&#xff0c;返回它将会被按顺序插入的位置 请必须使用时间复杂度为 O(long n) 的算法 示例 1: 输入: nums [1,3,5,6], t…

golang包管理

package 在工程化的Go语言开发项目中&#xff0c;Go语言的源码复用是建立在包&#xff08;package&#xff09;基础之上的。本文介绍了Go语言中如何定义包、如何导出包的内容及如何导入其他包。 包与依赖管理 本章学习目标 掌握包的定义和使用掌握init初始化函数的使用掌握…

一、el-table的滚动条加粗并解决遮挡内容问题

近期接到产品提的需求&#xff0c;反馈用户说table里面的滚动条过小&#xff0c;不方便拖动&#xff0c;希望加粗&#xff0c;然后我就研究了下如何加粗&#xff0c;发现加粗后会导致遮挡内容的问题&#xff0c;并予以解决。以下是实现和解决的方法和步骤。 先看看官网的滚动条…

[翻译]MOSIP 101

目录 Architecture Principles of MOSIP &#xff08;MOSIP架构原则&#xff09; MOSIP Functional Architecture&#xff08;MOSIP功能架构&#xff09; MOSIP Features&#xff08;MOSIP特点&#xff09; MOSIP Modules&#xff08;MOSIP模块&#xff09; MOSIP Logical…

manjaro kde 24 应该如何设置才能上网(2024-10-13亲测)

要在 Manjaro KDE 24 上设置网络连接&#xff0c;可以按照以下步骤进行设置&#xff0c;确保你能够连接到互联网&#xff1a; 是的&#xff0c;你可以尝试使用一个简单的自动修复脚本来解决 Manjaro KDE 中的网络连接问题。这个脚本将检查网络服务、重新启动 NetworkManager、…

R语言统计分析——相关图

参考资料&#xff1a;R语言实战【第2版】 相关系数矩阵是多元统计分析的一个基本方面。哪些被考察的变量与其他变量相关性很强&#xff0c;而哪些并不强&#xff1f;随着变量数的增加&#xff0c;这类问题将变得很难回答。相关图作为一种相对现代的方法&#xff0c;可以通过相关…

Node.js 中的 WebSocket 底层实现

WebSockets 是一种网络通信协议&#xff0c;可实现双向客户端-服务器通信。 WebSockets 通常用于需要即时更新的应用程序&#xff0c;使用 HTTP 之上的持久双工通道来支持实时交互&#xff0c;而无需持续进行连接协商。服务器推送是 WebSockets 的众多常见用例之一。 本文首先…

剖析DNS劫持攻击原理及其防御措施

DNS劫持可导致用户访问到虚假网站&#xff0c;还可能使攻击者获取用户的敏感信息或利用受感染的计算机进行其他恶意活动。了解清楚DNS劫持攻击的原理有助于我们提升安全意识&#xff0c;避免个人信息泄露及财产损失。 1. 基础概念 DNS劫持是一种网络攻击&#xff0c;通过修改域…

低代码开发技术:驱动MES系统创新与制造业数字化转型的融合之路

低代码开发与生产管理MES系统的融合&#xff0c;是当今制造业数字化转型的一个重要趋势。以下是对这一融合现象的详细分析&#xff1a; 一、低代码开发的概念与特点 低代码开发是一种通过图形化界面和预构建模块来简化应用程序开发过程的方法。它允许开发人员使用拖放组件和最…

MT1331-MT1340 码题集 (c 语言详解)

MT1341反比例函数 c 语言实现代码 #include <stdio.h>double f(double x) { return 1.0 / x; }double trapezoidal_integration(double a, double b, int n) {// computer step lengthdouble h (b - a) / n;// computer points valuedouble sum (f(a) f(b)) / 2.0;//…

linux的sed命令

学习链接 Linux文本处理器sed - B站视频 文章目录 学习链接基础介绍语法格式sed的处理过程sed的选项-n-e-f-r-i pattern的7种用法sed中的编辑命令详解p 打印d 删除a 行后追加i 行前追加r 行后追加指定文件内容w 行追加到其它文件中 替换操作s/pattern/strings/pattern/string/…