Qt应用软件【串口篇】串口通信

文章目录

  • 1.串口概述
  • 2.串口传输数据的基本原理
    • 电信号的传输过程
  • 3.串口的几个概念
    • 数据位(Data Bits)
    • 奇偶校验位(Parity Bit)
    • 停止位(Stop Bits)
    • 流控制(Flow Control)
    • 波特率(Baud Rate)
    • 串口名(Port Name)
  • 4.CH340串口接线方法
    • 简述
    • 接线步骤
      • 接线步骤
      • 注意事项
  • 5.Qt串口API
    • QSerialPort 类
    • QSerialPortInfo 类
    • 信号和槽
  • 6.串口通信代码示例
  • 7.串口编程技巧

1.串口概述

串口通信是计算机与外部设备进行数据交换的一种基础通信方式。它使用串行通信协议,其中数据按位顺序传输,通常用于较低速率的通信。串口通信广泛应用于各种设备,如打印机、鼠标、调制解调器等

串口通信通常使用 RS-232、RS-422 或 RS-485 等标准。其中,RS-232 是最常用的串口通信标准,它在计算机、通信设备和其他类型的设备之间广泛使用。

2.串口传输数据的基本原理

  1. 数字信号到电信号的转换:在串口通信中,数据首先以二进制形式存在。这些二进制数据(0和1)被转换为电信号。在 RS-232 标准中,一般情况下,负电压代表二进制位“1”(逻辑高),正电压代表二进制位“0”(逻辑低)。电压的具体值可以根据标准的不同而有所变化。
  2. 串行数据传输:与并行传输不同,串行传输是指数据位按顺序一个接一个地通过单个线路传输。这意味着数据位(比特)是连续发送的,而不是同时发送。
  3. 起始位和停止位:每个数据包通常以一个起始位开始,该起始位通知接收设备一个新字节的开始。数据位随后按顺序发送。最后,数据包以一个或多个停止位结束,表示数据字节的结束。
  4. 奇偶校验位(可选):为了错误检测,有时会在数据位之后添加一个奇偶校验位。这个位可以用来检查数据在传输过程中是否出现错误

电信号的传输过程

  1. 线路驱动器:串口通信中的发送设备包含一个线路驱动器,该驱动器负责将二进制数据转换为适合在物理介质上传输的电信号。
  2. 传输介质:电信号通过串行接口的物理线路传输,例如使用双绞线。
  3. 线路接收器:接收设备包含一个线路接收器,负责将收到的电信号转换回二进制数据。
  4. 同步:为了正确地解释接收到的数据,接收设备需要与发送设备同步。这通常通过观察起始位和停止位来实现,以确定数据位的边界
  • 时序图
二进制数据 转换器(驱动器) 物理线路(电缆) 接收器 解码数据 数据 (0和1) 将二进制转换为电信号 电信号 通过电缆传输 电信号 数据 (0和1) 将电信号转换为二进制 二进制数据 转换器(驱动器) 物理线路(电缆) 接收器 解码数据
  • 串口连线图
2 (RXD)
3 (TXD)
5 (GND)
2 (TXD)
3 (RXD)
7 (GND)
DB9 Connector
DB25 Connector
  • 对于 DB9 连接器:
    • 引脚 2 是接收数据(RXD)
    • 引脚 3 是发送数据(TXD)
    • 引脚 5 是地线(GND)
  • 对于 DB25 连接器:
    • 引脚 2 是发送数据(TXD)
    • 引脚 3 是接收数据(RXD)
    • 引脚 7 是地线(GND)

3.串口的几个概念

数据位(Data Bits)

数据位是串口通信中每个数据包的大小,表示每个数据字节中用于承载信息的位数。常见的数据位设置有 7 位或 8 位。例如,8 数据位意味着每个数据字节包含 8 个位。

奇偶校验位(Parity Bit)

奇偶校验位是一种错误检测机制。它在每个数据字节后添加一个额外的校验位,用于检测数据传输过程中的单比特错误。奇偶校验可以是无校验、奇校验或偶校验。

停止位(Stop Bits)

停止位用于标记每个数据包的结束。它在每个数据字节后添加一定数量的额外位,以指示数据包的终止。常见的停止位设置有 1 位、1.5 位和 2 位。

流控制(Flow Control)

流控制是用于管理数据传输速率和确保数据完整性的一种机制。它可以防止发送方在接收方来得及处理之前发送过多数据。流控制可以是无流控制、硬件流控制(RTS/CTS)或软件流控制(XON/XOFF)。

波特率(Baud Rate)

波特率是衡量串口通信速度的单位,表示每秒钟可以传输多少比特(位)的数据。常见的波特率设置有 9600、19200、38400、57600 和 115200 等。选择合适的波特率取决于设备的能力和通信距离。

串口名(Port Name)

串口名是用于标识计算机上特定串口的名称。在 Windows 系统中,串口名通常是以 “COM” 开头的,如 “COM1”、“COM2” 等。在 Unix/Linux 系统中,串口名通常以 “/dev/tty” 开头,如 “/dev/ttyS0”、“/dev/ttyUSB0” 等。

这些参数共同定义了串口通信的基本特性,包括数据的格式、速率和传输控制方式。正确配置这些参数对于确保串口通信的可靠性和效率至关重要。

4.CH340串口接线方法

简述

CH340 是一种常见的 USB 转串口芯片,广泛用于提供 USB 到串行通信的接口

  • 安装官方驱动

http://sparks.gogo.co.nz/ch340.html

  • USB转串口CH340接线

在这里插入图片描述

  • VCC:电源输入,通常为 3.3V 或 5V。
    TXD (Transmit Data):数据发送线,用于发送数据到另一设备
    RXD (Receive Data):数据接收线,用于接收来自另一设备的数据。
    GND (Ground):地线,用于电气接地

接线步骤

USB 转 TTL 串口模块(如基于 CH340 芯片的模块)可以用来将 USB 接口转换为 TTL 串口(即逻辑电平串口)。这种模块通常用于连接电脑的 USB 端口和使用 TTL 电平通信的设备,如微控制器或其他串口设备。以下是 USB 转 TTL 串口模块(CH340)的一般接线方法:

USB 转 TTL 模块(CH340)的典型管脚

  1. VCC:提供电源(通常为 3.3V 或 5V)。
  2. GND:地线,用于接地。
  3. TXD:发送数据(Transmit Data),CH340 的 TXD 连接到目标设备的 RXD。
  4. RXD:接收数据(Receive Data),CH340 的 RXD 连接到目标设备的 TXD。
  5. DTRRTS 等(如果有):用于流控制,根据需要连接。

接线步骤

  1. 连接 VCC 和 GND

    • 将 CH340 模块的 VCC 连接到目标设备的 VCC(注意电压匹配,通常为 3.3V 或 5V)。
    • 将 CH340 模块的 GND 连接到目标设备的 GND。
  2. 连接 TXD 和 RXD

    • 将 CH340 模块的 TXD(发送数据)连接到目标设备的 RXD(接收数据)。
    • 将 CH340 模块的 RXD(接收数据)连接到目标设备的 TXD(发送数据)。

    这种交叉连接确保一方的发送线连接到另一方的接收线。

  3. 连接流控制引脚(可选)

    • 如果您的应用需要流控制,可以连接 CH340 模块的 DTR、RTS 等管脚到目标设备相应的引脚。

注意事项

  • 确保电源电压匹配,避免对设备造成损害。
  • 确认目标设备的 TTL 电平是否与 CH340 模块兼容(通常为 3.3V 或 5V TTL 电平)。
  • 如果设备需要特殊的初始化序列(例如进入引导模式),可能需要特别处理 DTR 或 RTS 等控制信号。

在连接之前,请检查目标设备的文档以确认正确的接线方法。每个设备的接线要求可能略有不同。

5.Qt串口API

QSerialPort 类

QSerialPort(QObject *parent = nullptr) // 构造函数,创建一个 QSerialPort 对象。
void setPortName(const QString &name) // 设置串口的端口名。
QString portName() const // 获取当前串口的端口名。
void setBaudRate(qint32 baudRate, QSerialPort::Directions directions = AllDirections) // 设置波特率。
qint32 baudRate(QSerialPort::Directions directions = AllDirections) const // 获取当前波特率。
void setDataBits(QSerialPort::DataBits dataBits) // 设置数据位。
QSerialPort::DataBits dataBits() const // 获取当前设置的数据位。
void setParity(QSerialPort::Parity parity) // 设置奇偶校验位。
QSerialPort::Parity parity() const // 获取当前奇偶校验设置。
void setStopBits(QSerialPort::StopBits stopBits) // 设置停止位。
QSerialPort::StopBits stopBits() const // 获取当前停止位设置。
void setFlowControl(QSerialPort::FlowControl flowControl) // 设置流控制。
QSerialPort::FlowControl flowControl() const // 获取当前流控制设置。
bool open(QIODevice::OpenMode mode) // 打开串口,设置打开模式(读、写、读写)。
void close() // 关闭串口。
bool isOpen() const // 检查串口是否打开。
bool isReadable() const // 检查串口是否可读。
bool isWritable() const // 检查串口是否可写。
bool writeData(const char *data, qint64 len) // 向串口写入数据。
bool readData(char *data, qint64 maxSize) // 从串口读取数据。
QByteArray readAll() // 读取串口接收到的所有数据。
qint64 bytesAvailable() const // 获取可读取的字节数。
bool waitForReadyRead(int msecs) // 等待数据可读,带有超时。
bool waitForBytesWritten(int msecs) // 等待数据写入完成,带有超时。
QSerialPort::SerialPortError error() const // 获取当前的错误状态。
void clearError() // 清除当前的错误状态。

QSerialPortInfo 类

static QList<QSerialPortInfo> availablePorts() // 获取系统中所有可用的串口列表。
QString portName() const // 获取串口的端口名。
QString description() const // 获取串口的描述信息。
QString manufacturer() const // 获取串口的制造商信息。
QString serialNumber() const // 获取串口的序列号。
QString systemLocation() const // 获取串口在系统中的位置。
qint16 vendorIdentifier() const // 获取串口的供应商标识符。
qint16 productIdentifier() const // 获取串口的产品标识符。
bool hasVendorIdentifier() const // 检查是否有供应商标识符。
bool hasProductIdentifier() const // 检查是否有产品标识符。
bool isBusy() const // 检查串口是否正在使用中。

信号和槽

void readyRead() // 当串口有数据可读时发出的信号。
void bytesWritten(qint64 bytes) // 当串口有数据写入时发出的信号。
void errorOccurred(QSerialPort::SerialPortError error) // 当串口发生错误时发出的信号。

这些函数提供了在 Qt 中进行串口通信所需的基本功能,包括配置串口参数、打开/关闭串口、读写数据以及处理错误和事件。

6.串口通信代码示例

#include <QApplication>
#include <QWidget>
#include <QSerialPort>
#include <QSerialPortInfo>
#include <QPushButton>
#include <QTextEdit>
#include <QVBoxLayout>
#include <QDebug>
#include <QLabel>
#include <QComboBox>
#include <QMessageBox>

class SerialPortWidget : public QWidget
{
    Q_OBJECT

public:
    SerialPortWidget(QWidget *parent = nullptr) : QWidget(parent)
    {
        serial = new QSerialPort(this);

        auto layout = new QVBoxLayout(this);
        auto sendButton = new QPushButton(tr("Send"), this);
        auto refreshButton = new QPushButton(tr("Refresh Ports"), this);
        comboBox = new QComboBox(this);
        textEdit = new QTextEdit(this);
        textEdit->setReadOnly(true);

        layout->addWidget(new QLabel(tr("Select Serial Port:")));
        layout->addWidget(comboBox);
        layout->addWidget(sendButton);
        layout->addWidget(refreshButton);
        layout->addWidget(textEdit);

        refreshSerialPorts();

        connect(sendButton, &QPushButton::clicked, this, &SerialPortWidget::sendData);
        connect(refreshButton, &QPushButton::clicked, this, &SerialPortWidget::refreshSerialPorts);
        //串口可以读取事件
        connect(serial, &QSerialPort::readyRead, this, &SerialPortWidget::readData);
        //串口发生错误
        connect(serial, &QSerialPort::errorOccurred, this, &SerialPortWidget::handleError);
    }

private slots:
    void sendData()
    {
        QString data = "Hello, Serial Port!";
        serial->write(data.toLocal8Bit());
    }

    void readData()
    {
        QByteArray data = serial->readAll();
        textEdit->append(QString(data));
    }

    void handleError(QSerialPort::SerialPortError error)
    {
        if (error == QSerialPort::ResourceError) {
            QMessageBox::critical(this, tr("Critical Error"), serial->errorString());
            serial->close();
        }
    }

    void refreshSerialPorts()
    {
        comboBox->clear();
        //获取所有可用串口
        const auto infos = QSerialPortInfo::availablePorts();
        for (const QSerialPortInfo &info : infos) {
            comboBox->addItem(info.portName());
        }
    }

    void openSerialPort()
    {
    	//打开串口名
        serial->setPortName(comboBox->currentText());
        //波特率
        serial->setBaudRate(QSerialPort::Baud9600);
        //数据位
        serial->setDataBits(QSerialPort::Data8);
        //奇偶校验位
        serial->setParity(QSerialPort::NoParity);
        //停止位
        serial->setStopBits(QSerialPort::OneStop);
        //流控制
        serial->setFlowControl(QSerialPort::NoFlowControl);

        if (!serial->open(QIODevice::ReadWrite)) {
            QMessageBox::critical(this, tr("Error"), serial->errorString());
            return;
        }
    }

    void closeSerialPort()
    {
        if (serial->isOpen())
            serial->close();
    }

private:
    QSerialPort *serial;
    QTextEdit *textEdit;
    QComboBox *comboBox;
};

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    SerialPortWidget widget;
    widget.show();
    return app.exec();
}

7.串口编程技巧

  1. 串口枚举和检测

    • 在开发串口应用程序时,首先需要检测和枚举系统中可用的串口。QSerialPortInfo 类可以用来获取系统中所有可用串口的详细信息,包括端口名、描述、制造商等。
  2. 异步通信

    • Qt 串口模块支持异步通信,即你可以在不阻塞主线程的情况下进行读写操作。通过使用信号和槽机制,你可以实现非阻塞式的数据读写。例如,readyRead() 信号可用于在有数据可读时通知应用程序。
  3. 线程和串口通信

    • 在某些情况下,可能需要在单独的线程中处理串口通信,以避免主界面线程因长时间的 I/O 操作而变得不响应。在这种情况下,你需要确保线程之间正确地共享串口资源并同步数据。
  4. 错误处理

    • 处理串口通信中可能出现的错误是非常重要的。QSerialPort 提供了 errorOccurred() 信号和 error() 方法来报告和查询错误状态。
  5. 信号调制和解调

    • 通常,串口通信涉及信号的调制和解调,特别是在涉及长距离或无线传输时。虽然这些功能超出了 Qt 串口模块的直接支持范围,但了解这些概念对于设计健壮的通信系统是有益的。
  6. 跨平台兼容性

    • Qt 串口模块是跨平台的,这意味着你可以在 Windows、Linux、macOS 等操作系统上以相同的方式使用这些 API。
  7. 测试和调试

    • 在开发串口通信应用程序时,测试和调试是非常重要的。你可能需要使用串口调试工具来模拟串口设备,或者捕获和分析串口数据。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

第九篇【传奇开心果短博文系列】鸿蒙开发技术点案例示例:ArkUI强大的状态管理机制解读

传奇开心果短博文系列 系列短博文目录鸿蒙开发技术点案例示例系列 短博文目录一、前言二、ArkUI强大的状态管理机制介绍三、以官方helloworld示例为例说明ArkUI的状态定义和管理四、以官方 HelloWorld 示例代码为例说明ArkUI状态依赖和自动更新五、以官方helloworld示例代码为例…

PHP语法

#本来是在学命令执行&#xff0c;所以学了学&#xff0c;后来发现&#xff0c;PHP语法和命令执行的关系好像没有那么大&#xff0c;不如直接学php的一些命令执行函数了。# #但是还是更一下&#xff0c;毕竟还是很多地方都要求掌握php作为脚本语言&#xff0c;所以就学了前面的…

多维时序 | Matlab实现DBO-GRU蜣螂算法优化门控循环单元多变量时间序列预测

多维时序 | Matlab实现DBO-GRU蜣螂算法优化门控循环单元多变量时间序列预测 目录 多维时序 | Matlab实现DBO-GRU蜣螂算法优化门控循环单元多变量时间序列预测效果一览基本介绍程序设计参考资料 效果一览 基本介绍 1.Matlab实现DBO-GRU蜣螂算法优化门控循环单元多变量时间序列预…

第四十一周:文献阅读+GAN存在的问题和改进

目录 摘要 Abstract 文献阅读&#xff1a;基于Transformer的时间序列生成对抗网络 现有问题 提出方法 相关前提 GAN&#xff08;生成对抗网络&#xff09; Transformer 方法论 时间序列处理 TTS-GAN &#xff08;基于Transformer的时间序列生成对抗网络&#xff09;…

STM32学习笔记(二) —— 调试串口

我们在调试程序时&#xff0c;经常会使用串口打印相关的调试信息&#xff0c;但是单片机串口不能直接与 PC 端的 USB 接口通讯&#xff0c;需要用到一个USB转串口的芯片来充当翻译的角色。我们使用的开发板上有这个芯片&#xff0c;所以在打印调试信息的时候直接使用USB线连接开…

05.领域驱动设计:认识领域事件,解耦微服务的关键

目录 1、概述 2、领域事件 2.1 如何识别领域事件 1.微服务内的领域事件 2.微服务之间的领域事件 3、领域事件总体架构 3.1 事件构建和发布 3.2 事件数据持久化 3.3 事件总线 (EventBus) 3.4 消息中间件 3.5 事件接收和处理 4、案例 5、总结 1、概述 在事件风暴&a…

Jmeter连接数据库报错Cannot load JDBC driver class‘com.mysql.jdbc.Driver’解决

问题产生: 我在用jmeter连接数据库查询我的接口是否添加数据成功时,结果树响应Cannot load JDBC driver class com.mysql.jdbc.Driver 产生原因: 1、连接数据库的用户密码等信息使用的变量我放在了下面,导致没有取到用户名密码IP等信息,导致连接失败 2、jmeter没有JDB…

scrapy的入门使用

1 安装scrapy 命令: sudo apt-get install scrapy或者&#xff1a; pip/pip3 install scrapy2 scrapy项目开发流程 创建项目: scrapy startproject mySpider生成一个爬虫: scrapy genspider itcast itcast.cn提取数据:     根据网站结构在spider中实现数据采集相关内…

MATLAB - 仿真单摆的周期性摆动

系列文章目录 前言 本例演示如何使用 Symbolic Math Toolbox™ 模拟单摆的运动。推导摆的运动方程&#xff0c;然后对小角度进行分析求解&#xff0c;对任意角度进行数值求解。 一、步骤 1&#xff1a;推导运动方程 摆是一个遵循微分方程的简单机械系统。摆最初静止在垂直位置…

2024年数学建模美赛 分析与编程

2024年数学建模美赛 分析与编程 1、本专栏将在2024年美赛题目公布后&#xff0c;进行深入分析&#xff0c;建议收藏&#xff1b; 2、本专栏对2023年赛题&#xff0c;其它题目分析详见专题讨论&#xff1b; 2023年数学建模美赛A题&#xff08;A drought stricken plant communi…

uniapp组件库Card 卡片 的使用方法

目录 #平台差异说明 #基本使用 #配置卡片间距 #配置卡片左上角的缩略图 #配置卡片边框 #设置内边距 #API #Props #Slot #Event 卡片组件一般用于多个列表条目&#xff0c;且风格统一的场景。 #平台差异说明 AppH5微信小程序支付宝小程序百度小程序头条小程序QQ小程…

147基于matlab的信号多层分解和重构

基于matlab的信号多层分解和重构&#xff0c;进行多频率分析的源程序&#xff0c;一般步骤:取样、分解、信号处理、重构&#xff1b;采用离散滤波器对近似系数和小波系数进行操作;程序已调通&#xff0c;可直接运行。 147 离散小波变换 多频率分析 信号重构 (xiaohongshu.com)…

JDK 8 - SerializedLambda

SerializedLambda是Java提供的关于lambda表达式的序列化方案&#xff0c;会将实现了Serializable接口的lambda表达式转换成 SerializedLambda 对象之后再去做序列化。其核心在于Java在对lambda表达式序列化时&#xff0c;虚拟机会添加一个writeReplace()方法。 根据Java的序列化…

mac docker desktop被禁用了,如何使用虚拟机lima运行docker

安装lima brew install lima创建配置 echo "\\ndynamic:\n big-sur:\n image: docker://docker:git\n linux:\n image: docker.io/limasoftware/ubuntu:20.04 \\n" > ~/.lima/default.yaml启动名叫default的虚拟机 limactl start default测试 limactl …

echarts多个折线图共用X轴,实现tooltip合并和分离

echarts共享X轴案例&#xff1a; <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><meta name"viewport" content"widthdevice-width, initial-scale1.0" /><title>Document</…

【办公类-23-01】20240128《百家姓》单姓与复姓

结果展示 背景需求&#xff1a; 20240128我去了苏州吴江的黎里古镇游玩&#xff0c;哪里有一面墙上都是百家姓做装饰。 这让我又想到我班级里的7个王姓的重姓率&#xff01; 【办公类-19-02-01】20240119统计班级幼儿姓名的长度、汉字重复、拼音重复&#xff08;有无声调&…

【ArcGIS遇上Python】python实现批量XY坐标生成shp点数据文件

单个手动生成:【ArcGIS风暴】ArcGIS 10.2导入Excel数据X、Y坐标(经纬度、平面坐标),生成Shapefile点数据图层 文章目录 一、问题分析二、解决办法三、注意事项一、问题分析 现有多个excel、txt或者csv格式的坐标数据,需要根据其坐标批量一键生成shp点数据,如下X为经度,…

回归预测 | MATLAB实现PSO-GRNN粒子群优化广义回归神经网络多输入单输出预测(含优化前后预测可视化)

回归预测 | MATLAB实现PSO-GRNN粒子群优化广义回归神经网络多输入单输出预测 目录 回归预测 | MATLAB实现PSO-GRNN粒子群优化广义回归神经网络多输入单输出预测预测效果基本介绍程序设计参考资料预测效果 <

力扣3. 无重复字符的最长子串(滑动窗口)

Problem: 3. 无重复字符的最长子串 文章目录 题目描述思路及解法复杂度Code 题目描述 思路及解法 由于题目要求求出字符串中最长的连续无重复字符的最长子串&#xff0c;所以利用这个特性我们可以比较容易的想到利用双指针中的滑动窗口技巧来解决&#xff0c;但在实际的求解中…

【学网攻】 第(14)节 -- 动态路由(EIGRP)

系列文章目录 目录 系列文章目录 文章目录 前言 一、动态路由EIGRP是什么&#xff1f; 二、实验 1.引入 实验步骤 实验拓扑图 实验配置 看到D开头是便是我们的EIGRP动态路由 总结 文章目录 【学网攻】 第(1)节 -- 认识网络【学网攻】 第(2)节 -- 交换机认识及使用【学…