当前位置: 首页 > news >正文

第六章 QT基础:2、编程基础及串口助手案例

一、QT下的三驾马车

1、QT的串口编程

QT的串口编程使用QtSerialPort模块,它提供了对串口设备的支持,使得应用程序能够方便地与硬件设备通过串口进行通信。串口编程常用于设备通信、数据采集等领域。

  • 初始化串口: 使用 QSerialPort 类来创建串口对象,设置串口的基本属性,如波特率、数据位、停止位等。
QSerialPort *serial = new QSerialPort(this);
serial->setPortName("COM1");  // 设置串口名称
serial->setBaudRate(QSerialPort::Baud9600);  // 设置波特率
serial->setDataBits(QSerialPort::Data8);  // 数据位
serial->setParity(QSerialPort::NoParity);  // 校验位
serial->setStopBits(QSerialPort::OneStop);  // 停止位
  • 打开串口
if (serial->open(QIODevice::ReadWrite)) {qDebug() << "串口打开成功!";
} else {qDebug() << "串口打开失败!";
}
  • 数据发送与接收: 发送数据可以通过 write() 方法,接收数据可以使用 readyRead() 信号来监听。
serial->write("Hello, Serial Port!");  // 发送数据
connect(serial, &QSerialPort::readyRead, this, &MainWindow::onReadyRead);
  • 数据接收方法
void MainWindow::onReadyRead() {QByteArray data = serial->readAll();  // 读取串口数据qDebug() << data;
}

2、QT下的网络编程

QT支持多种网络协议的编程,主要使用 QTcpSocket 和 QTcpServer 类来进行TCP协议的编程。

  • 客户端网络编程: 使用 QTcpSocket 类来创建客户端与服务器进行通信。
QTcpSocket *socket = new QTcpSocket(this);
socket->connectToHost("localhost", 1234);  // 连接到服务器
socket->write("Hello, Server!");  // 发送数据
  • 服务器端编程: 使用 QTcpServer 类来创建一个简单的服务器。
QTcpServer *server = new QTcpServer(this);
if (server->listen(QHostAddress::Any, 1234)) {qDebug() << "服务器已启动!";
} else {qDebug() << "服务器启动失败!";
}connect(server, &QTcpServer::newConnection, this, &MainWindow::onNewConnection);

客户端连接到服务器后,接收到的连接可以通过 newConnection 信号来处理。

3、QT下的GPIO

在QT中,GPIO(通用输入输出)通常通过操作底层硬件接口来进行控制,例如通过/dev/下的文件进行输入输出。在QT中并没有直接的GPIO模块,因此通常需要借助底层操作系统的接口进行GPIO编程。

二、仿写串口助手

步骤一:做好UI界面

仿写串口助手的第一步是创建一个界面,界面通常包括以下组件:

  • 接收框:显示从串口接收到的数据
    ![[Pasted image 20250415110752.png]]

  • 发送框:用户输入要发送的数据
    ![[Pasted image 20250415110823.png]]

  • 发送按钮:点击后将发送框中的数据发送出去

  • 串口配置区:包括串口号选择、波特率选择、数据位选择、校验位选择、停止位选择等

  • 打开/关闭串口按钮:用于打开或关闭串口

步骤二:实现串口操作功能

  • 打开串口
void MainWindow::on_OpenButton_clicked() {QString portName = ui->comboBoxPortName->currentText();int baudRate = ui->comboBoxBaudRate->currentText().toInt();QString dataBits = ui->comboBoxDataBits->currentText();QString parity = ui->comboBoxParity->currentText();QString stopBits = ui->comboBoxStopBits->currentText();serial->setPortName(portName);serial->setBaudRate(baudRate);// 设置其他串口参数...if (serial->open(QIODevice::ReadWrite)) {ui->OpenButton->setText("关闭");qDebug() << "串口打开成功!";} else {qDebug() << "串口打开失败!";}
}
  • 关闭串口
void MainWindow::on_CloseButton_clicked() {serial->close();ui->OpenButton->setText("打开");qDebug() << "串口已关闭!";
}
  • 发送数据
void MainWindow::on_SendButton_clicked() {QString data = ui->SendTextEdit->toPlainText();serial->write(data.toUtf8());qDebug() << "发送数据: " << data;
}
  • 接收数据
void MainWindow::onReadyRead() {QByteArray data = serial->readAll();ui->ReceiveTextEdit->append(data);qDebug() << "接收到数据: " << data;
}

步骤三:实现其他功能

  • 自动换行:在接收框中实现自动换行功能,方便查看数据
  • 清空接收框:添加一个按钮,点击后清空接收框中的内容
  • 保存接收数据:将接收的数据保存到文件中
  • 打开串口时的错误处理:处理打开串口时可能出现的各种错误

串口代码案例:

#include "widget.h"
#include "ui_widget.h"
#include <QSerialPortInfo>
#include <QString>
#include <QMessageBox>// 构造函数:初始化 UI 和串口设置
Widget::Widget(QWidget *parent) :QWidget(parent),  // 调用 QWidget 构造函数ui(new Ui::Widget)  // 初始化 UI 对象
{ui->setupUi(this);  // 设置 UI 界面QStringList serialNamePort;  // 创建一个字符串列表,用于存储串口名称serialPort = new QSerialPort(this);  // 创建 QSerialPort 对象,用于串口通信// 连接串口的 readyRead 信号到槽函数 serialPortReadyRead_slotconnect(serialPort, SIGNAL(readyRead()), this, SLOT(serialPortReadyRead_slot()));// 遍历可用的串口,并将串口名称添加到 combobox 中foreach (const QSerialPortInfo &info, QSerialPortInfo::availablePorts()) {serialNamePort << info.portName();  // 将串口名称加入列表ui->serialCb->addItems(serialNamePort);  // 将串口名称添加到界面上的 comboBox 中}
}// 析构函数:清理内存
Widget::~Widget()
{delete ui;  // 删除 UI 对象,释放内存
}// 串口数据读取槽函数:每次串口有数据时被调用
void Widget::serialPortReadyRead_slot()
{QString buf;  // 创建字符串变量,用于存储接收到的数据buf = QString(serialPort->readAll());  // 读取串口的所有数据并转换为 QString 格式ui->recvEdit->appendPlainText(buf);  // 将接收到的数据添加到界面上的接收框中
}// 打开串口按钮的点击事件
void Widget::on_OpenBt_clicked()
{QSerialPort::BaudRate bauRates;  // 声明变量,用于存储波特率QSerialPort::DataBits dataBits;  // 声明变量,用于存储数据位QSerialPort::StopBits stopBits;  // 声明变量,用于存储停止位QSerialPort::Parity checkBits;  // 声明变量,用于存储校验位// 根据 combobox 中选择的波特率设置 bauRatesif(ui->baundrateCb->currentText() == "4800"){bauRates = QSerialPort::Baud4800;}else if(ui->baundrateCb->currentText() == "9600") {bauRates = QSerialPort::Baud9600;}else if(ui->baundrateCb->currentText() == "115200") {bauRates = QSerialPort::Baud115200;}// 根据 combobox 中选择的数据位设置 dataBitsif(ui->dataCb->currentText() == "5") {dataBits = QSerialPort::Data5;}else if(ui->dataCb->currentText() == "6") {dataBits = QSerialPort::Data6;}else if(ui->dataCb->currentText() == "7") {dataBits = QSerialPort::Data7;} else if(ui->dataCb->currentText() == "8") {dataBits = QSerialPort::Data8;}// 根据 combobox 中选择的停止位设置 stopBitsif(ui->stopCb->currentText() == "1") {stopBits = QSerialPort::OneStop;} else if(ui->stopCb->currentText() == "1.5") {stopBits = QSerialPort::OneAndHalfStop;} else if(ui->stopCb->currentText() == "2") {stopBits = QSerialPort::TwoStop;}// 根据 combobox 中选择的校验位设置 checkBitsif(ui->checkCb->currentText() == "none") {checkBits = QSerialPort::NoParity;}// 设置串口的各种属性serialPort->setPortName(ui->serialCb->currentText());  // 设置串口名称serialPort->setBaudRate(bauRates);  // 设置波特率serialPort->setDataBits(dataBits);  // 设置数据位serialPort->setStopBits(stopBits);  // 设置停止位serialPort->setParity(checkBits);  // 设置校验位// 打开串口,如果成功则弹出提示框if(serialPort->open(QIODevice::ReadWrite)) {QMessageBox::information(this, "提示", "成功打开串口");  // 打开成功,弹出提示框} else {QMessageBox::critical(this, "错误", "无法打开串口");  // 打开失败,弹出错误框}
}// 关闭串口按钮的点击事件
void Widget::on_CloseBt_clicked()
{serialPort->close();  // 关闭串口
}// 发送数据按钮的点击事件
void Widget::on_SendBt_clicked()
{// 获取文本框中的内容并发送到串口serialPort->write(ui->sendEdit->text().toLocal8Bit().data());
}// 清空接收区按钮的点击事件
void Widget::on_ClearBt_clicked()
{ui->recvEdit->clear();  // 清空接收框中的内容
}// 串口回车换行按钮的点击事件
void Widget::on_checkBox_stateChanged(int arg1)
{QString a = "\r\n";  // 定义回车换行字符serialPort->write(a.toLocal8Bit().data());  // 向串口发送回车换行字符
}
http://www.xdnf.cn/news/83827.html

相关文章:

  • 一文读懂什么是 MCP、A2A、ANP
  • TypeScript十大关键语法
  • 第44讲:玩转土壤数据!用机器学习挖掘地球皮肤的秘密 [特殊字符][特殊字符]
  • 集成算法学习案例
  • Open GL ES -> 模版测试,绘制SurfaceView中某个目标区域
  • 【目标检测】对YOLO系列发展的简单理解
  • SharpMap与TerraLib:C#与C++开源GIS库
  • Docker Compose常用命令
  • S32K144学习(16)-Bootloader
  • NLP高频面试题(五十)——大模型(LLMs)分词(Tokenizer)详解
  • uniapp-商城-33-shop 布局搜索页面以及u-search
  • QTextDocument 入门
  • 多路转接poll服务器
  • MySQL 启动报错:InnoDB 表空间丢失问题及解决方法
  • 基于STM32的室内环境监测系统
  • .NET下 using 块的作用
  • 正则表达式
  • 【AAudio】A2dp sink创建音频轨道的源码流程分析
  • 【OSG源码阅读】Day 1: 从Viewer的run函数开始
  • Sentinel数据S2_SR_HARMONIZED连续云掩膜+中位数合成
  • Spark-SQL(总结)
  • Saliency Driven Perceptual Image Compression阅读
  • 如何解决消费者高频触发订单更新?
  • ProxySQL 的性能优化需结合实时监控数据与动态配置调整
  • pip install torchsummary报错
  • 5个Go接口常见错误及避免方法
  • 机器学习基础 - 分类模型之逻辑回归
  • 是否可以使用非被动 S4P 文件进行反嵌?
  • Redis—内存淘汰策略
  • Nginx:前后端分离配置(静态资源+反向代理)