QT开发--串口通信
第十六章 串口通信
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); // 将更新后的字符串添加到接收文本框中 }
}



相关文章:
QT开发--串口通信
第十六章 串口通信 16.1 串口通信基础 串口通信主要通过DB9接口,适用于短距离(<10米)。关键参数包括: 波特率:每秒传输bit数,如9600。数据位:信息包中的有效数据位数。停止位:…...
数据库(至少还的再花两天 )
1 连接查询 左连接 右连接 2 聚合函数 SQL 统计求和 求最值 count sum avg max min 3 SQL关键字 limit 分页 group by 分组 distinct 去重 4 Select执行顺序 from where group by order by 5 数据库三范式 原子性 唯一性 直接性 6 存储引擎 MyISAM InnoDB 7 …...
网络安全公司及其主要产品介绍
以下是一些全球领先的网络安全公司及其主要产品介绍: 一、思科(Cisco) 思科是全球最大的网络设备供应商之一,其网络安全产品以企业级解决方案为主,覆盖多种安全需求。 Cisco ASA(Adaptive Security Appli…...
orjson:高性能的Python JSON库
在Python中处理JSON数据是一项常见任务,标准库的json模块虽然功能齐全,但在性能方面还有提升空间。今天我要向大家介绍一个出色的第三方JSON库 - orjson。 orjson简介 orjson是一个快速、正确的Python JSON库。它具有以下主要特点: 性能卓越 - 在序列化和反序列化方面都比标准…...
常见几大排序算法
排序算法是计算机科学中的基本算法,它们将一个无序的数组或列表按特定顺序进行排列(如升序或降序)。常见的排序算法可以根据其时间复杂度、空间复杂度和适用场景分类。以下是几种常见的排序算法: 1. 冒泡排序(Bubble …...
Linux下CMake入门
CMake的基础知识 什么是 CMake CMake 是一个跨平台的构建工具,主要用于管理构建过程。CMake 不直接构建项目,而是生成特定平台上的构建系统(如 Unix 下的 Makefile,Windows 下的 Visual Studio 工程),然后…...
网络资源模板--Android Studio 实现简易记事本App
目录 一、项目演示 二、项目测试环境 三、项目详情 四、完整的项目源码 一、项目演示 网络资源模板--基于Android studio 实现的简易记事本App 二、项目测试环境 三、项目详情 首页 创建一个空的笔记本列表 mNotebookList。使用该列表和指定的布局资源 item_notebook 创建…...
根据Vue对比来深入学习React 下 props 组件传值 插槽 样式操作 hooks 高阶组件 性能优化
文章目录 函数组件的特点props组件间的传值父传子看上例子传父兄弟组件传值祖先组件传值 插槽基础插槽具名插槽作用域插槽 样式操作**CSS Modules** 生命周期useRef常用hookuseStateuseEffectuseContextuseReduceruseMemouseCallback 高阶组件什么时候使用 react性能问题和优化…...
HTML(六)超链接
HTML讲解(一)body部分_html body-CSDN博客 <!DOCTYPE html> <html><head><meta charset"UTF-8" /><title>title</title> </head><body><a href"https://blog.csdn.net/2301_8034953…...
【Coroutines】Implement Lua Coroutine by Kotlin - 2
Last Chapter Link 文章目录 Symmetric CoroutinesNon-Symmetric Coroutine SampleSymmetric Coroutine SampleHow to Implement Symmetric CoroutinesWonderful TricksCode DesignTail Recursion OptimizationFull Sources Symmetric Coroutines in last blog, we have talk…...
java计算机毕设课设—扫雷游戏(附源码、文章、相关截图、部署视频)
这是什么系统? 资源获取方式再最下方(本次10月份活动福利,免费提供下载,自行到对应的方式1下载,csdn的0积分下载) java计算机毕设课设—扫雷游戏(附源码、文章、相关截图、部署视频) 基于Java的扫雷游戏…...
AndroidLogger 使用问题
Q1:解压zip后,启动Notepad未看到AndroidLogger工具栏 请检查plugins下安装位置是否正确,必须与下图一致,再确认Notepad 是否为 x64 ? Q2:使用 adb 可以显示已连接,但是获取不到日志 暂时不确定问…...
数据库常见面试
8道面试题 目录 目录 7道面试题 1.怎样进行sql优化 4、group by优化 5、limit优化 6、count优化 7、update优化 2.。怎样查看sql执行情况呢(哪个关键字),说说你对这个关键字的认识 4) possible_key: 5) key 3.说说你对innodb和 myisam的理解 …...
boxplot 绘制箱线图,添加数据点
先看效果图 import matplotlib.pyplot as plt #! 解决不显示的问题:中文设置为宋体格式 plt.rcParams[font.family] ["Times New Roman", SimSun]def plot_boxplot(data_list, out_file, x_custom_labels):# 画图fig, ax plt.subplots(figsize(90, 6…...
用sdkman管理多个jdk切换
前言 最近项目前后端进行升级,需要在jdk8和jdk17两个版本切换。最简单的是通过手动切换,但切换过程太繁琐,修改环境变量,达到切换目的。于是尝试其它解决方案,最终确实使用sdkman工具。 sdkman 是一款面向Java开发者的…...
【AIGC】ChatGPT提示词Prompt高效编写模式:结构化Prompt、提示词生成器与单样本/少样本提示
💯前言 在如今AI技术迅猛发展的背景下,尽管像ChatGPT这样的大型语言模型具备强大的生成能力,但它们的输出质量有时仍难以完全满足我们的预期。为了让ChatGPT生成更加准确、可靠的内容,掌握高效的Prompt编写技巧变得尤为重要。本文…...
反调式实战(有道翻译窗口弹出)
1.添加脚本断点实现源码获取 2.Function构造器构造debugger 因为是窗口被弹出的情况,所以window.closefunction()构造debugger。 3.定位到影响弹出的JavaScript代码片段 反调试思想:置空和替换,所以将其JavaScript进行注释或者删除。 这里主…...
verilog端口使用注意事项
下图存在组合逻辑反馈环,即组合逻辑的输出反馈到输入(赋值的左右2边存在相同的信号),此种情况会造成系统不稳定。比如在data_in20的情况下,在data_out0 时候,输出的数据会反馈到输入,输入再输出,从而造成不…...
Docker常用命令大全汇总
Docker是一种流行的容器化平台,可以在一个独立的、隔离的环境中构建、部署和运行应用程序。了解Docker常用命令可以帮助我们更高效地管理容器,快速开发和部署应用。本文将整理一系列Docker的常用命令,便于日常使用和学习。 1 Docker基础命令 1.1 启动/停止/重启docker # …...
LVS-DR+Keepalived 高可用群集部署
LVS-DRKeepalived 高可用群集部署 Keepalived 的工作原理LVSKeepalived 高可用群集部署配置负载调度器(主、备相同)关闭防火墙和核心防护及准备IPVS模块配置keeplived(主、备DR 服务器上都要设置)启动 ipvsadm 服务调整 proc 响应…...
【SpringBoot】100、SpringBoot中使用自定义注解+AOP实现参数自动解密
在实际项目中,用户注册、登录、修改密码等操作,都涉及到参数传输安全问题。所以我们需要在前端对账户、密码等敏感信息加密传输,在后端接收到数据后能自动解密。 1、引入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId...
React Native在HarmonyOS 5.0阅读类应用开发中的实践
一、技术选型背景 随着HarmonyOS 5.0对Web兼容层的增强,React Native作为跨平台框架可通过重新编译ArkTS组件实现85%以上的代码复用率。阅读类应用具有UI复杂度低、数据流清晰的特点。 二、核心实现方案 1. 环境配置 (1)使用React Native…...
剑指offer20_链表中环的入口节点
链表中环的入口节点 给定一个链表,若其中包含环,则输出环的入口节点。 若其中不包含环,则输出null。 数据范围 节点 val 值取值范围 [ 1 , 1000 ] [1,1000] [1,1000]。 节点 val 值各不相同。 链表长度 [ 0 , 500 ] [0,500] [0,500]。 …...
苍穹外卖--缓存菜品
1.问题说明 用户端小程序展示的菜品数据都是通过查询数据库获得,如果用户端访问量比较大,数据库访问压力随之增大 2.实现思路 通过Redis来缓存菜品数据,减少数据库查询操作。 缓存逻辑分析: ①每个分类下的菜品保持一份缓存数据…...
令牌桶 滑动窗口->限流 分布式信号量->限并发的原理 lua脚本分析介绍
文章目录 前言限流限制并发的实际理解限流令牌桶代码实现结果分析令牌桶lua的模拟实现原理总结: 滑动窗口代码实现结果分析lua脚本原理解析 限并发分布式信号量代码实现结果分析lua脚本实现原理 双注解去实现限流 并发结果分析: 实际业务去理解体会统一注…...
前端开发面试题总结-JavaScript篇(一)
文章目录 JavaScript高频问答一、作用域与闭包1.什么是闭包(Closure)?闭包有什么应用场景和潜在问题?2.解释 JavaScript 的作用域链(Scope Chain) 二、原型与继承3.原型链是什么?如何实现继承&a…...
Unit 1 深度强化学习简介
Deep RL Course ——Unit 1 Introduction 从理论和实践层面深入学习深度强化学习。学会使用知名的深度强化学习库,例如 Stable Baselines3、RL Baselines3 Zoo、Sample Factory 和 CleanRL。在独特的环境中训练智能体,比如 SnowballFight、Huggy the Do…...
让回归模型不再被异常值“带跑偏“,MSE和Cauchy损失函数在噪声数据环境下的实战对比
在机器学习的回归分析中,损失函数的选择对模型性能具有决定性影响。均方误差(MSE)作为经典的损失函数,在处理干净数据时表现优异,但在面对包含异常值的噪声数据时,其对大误差的二次惩罚机制往往导致模型参数…...
安宝特案例丨Vuzix AR智能眼镜集成专业软件,助力卢森堡医院药房转型,赢得辉瑞创新奖
在Vuzix M400 AR智能眼镜的助力下,卢森堡罗伯特舒曼医院(the Robert Schuman Hospitals, HRS)凭借在无菌制剂生产流程中引入增强现实技术(AR)创新项目,荣获了2024年6月7日由卢森堡医院药剂师协会࿰…...
解析奥地利 XARION激光超声检测系统:无膜光学麦克风 + 无耦合剂的技术协同优势及多元应用
在工业制造领域,无损检测(NDT)的精度与效率直接影响产品质量与生产安全。奥地利 XARION开发的激光超声精密检测系统,以非接触式光学麦克风技术为核心,打破传统检测瓶颈,为半导体、航空航天、汽车制造等行业提供了高灵敏…...
