QT开发低功耗蓝牙BLE连接ECB02模块进行数据收发

时间记录:2024/1/22

一、注意点

(1)pro文件中引入bluetooth模块
(2)安卓端运行时需要同步打开定位功能才能扫描到蓝牙设备
(3)mingw套件不能在Windows上运行,需要使用MSVC套件编译才能在Windows上运行

二、使用步骤

(1)设备蓝牙操作类QBluetoothLocalDevice
    2.1.1 hostMode方法获取蓝牙打开状态
    2.1.2 powerOn方法打开蓝牙
    2.1.3 setHostMode方法关闭蓝牙
(2)蓝牙设备搜索类QBluetoothDeviceDiscoveryAgent
    2.2.1 setLowEnergyDiscoveryTimeout方法设置扫描超时时间,如果设置为0,则一直进行扫描
    2.2.2 为QBluetoothDeviceDiscoveryAgent对象的deviceDiscovered信号绑定槽,每发现一台蓝牙设备便会触发一次此信号,携带参数QBluetoothDeviceInfo,每台蓝牙设备的信息类
    2.2.3 使用start方法,开始搜索蓝牙设备,参数可以传递QBluetoothDeviceDiscoveryAgent::LowEnergyMethod表示搜索低功耗蓝牙设备
(3)低功耗蓝牙控制器类QLowEnergyController
    2.3.1 使用静态方法createCentral创建蓝牙控制器对象,参数为QBluetoothDeviceInfo对象
    2.3.2 为serviceDiscovered信号绑定槽,每发现一个服务触发一次此信号,携带参数QBluetoothUuid
    2.3.3 为connected信号绑定槽,用于判断是否已成功连接到蓝牙
    2.3.4 使用connectToDevice方法连接蓝牙
    2.3.5 使用disconnectFromDevice方法来断开连接
    2.3.6 连接成功后调用discoverServices方法获取连接蓝牙下的所有服务
(4)低功耗蓝牙服务类QLowEnergyService
    2.4.1 使用QLowEnergyController对象的createServiceObject方法创建QLowEnergyService对象
    2.4.2 为stateChanged信号绑定槽,监听服务状态
    2.4.3 为characteristicChanged信号绑定槽,收到信息时会触发此信号,信息为携带的参数newValue
    2.4.4 为descriptorWritten信号绑定槽,监听描述符是否成功写入
    2.4.5 使用discoverDetails方法获取服务详情
    2.4.6 服务状态改变以后写入描述符激活notify,否则无法收到消息,使用characteristics方法获取服务下所有的特征对象
(5)低功耗蓝牙特征值类QLowEnergyCharacteristic
    2.5.1 遍历特征值对象列表,使用isValid方法判断是否可用
    2.5.2 使用descriptor方法创建描述符对象,参数传递QBluetoothUuid::DescriptorType::ClientCharacteristicConfiguration,表示描述符类型由客户端特征值自行配置
(6)低功耗蓝牙描述符对象QLowEnergyDescriptor
    2.6.1 使用isValid方法判断描述符对象是否有效
    2.6.2 使用QLowEnergyService类的writeDescriptor方法向蓝牙写入描述符,激活notify,参数第一个为描述符对象,第二个为QByteArray::fromHex(“0100”)
(7)使用QLowEnergyService类的writeCharacteristic方法写入数据

三、参考代码

(1)头文件

#ifndef MWIDGET_H
#define MWIDGET_H

#include <QWidget>
#include <QBluetoothDeviceDiscoveryAgent> //蓝牙设备搜索对象
#include <QBluetoothLocalDevice> //本机蓝牙操作
#include <QBluetoothDeviceInfo>
#include <QList>
#include <QListWidgetItem>
#include <QLowEnergyController> //蓝牙控制器对象
#include <QBluetoothUuid>
#include <QLowEnergyService>
#include <QLowEnergyCharacteristic>
#include <QByteArray>

//static const QLatin1String serviceUUID("0000FFF0-0000-1000-8000-00805F9B34FB");
//static const QLatin1String readUUID("0000FFF1-0000-1000-8000-00805F9B34FB");
//static const QLatin1String writeUUID("0000FFF2-0000-1000-8000-00805F9B34FB");

QT_BEGIN_NAMESPACE
namespace Ui { class MWidget; }
QT_END_NAMESPACE

class MWidget : public QWidget
{
    Q_OBJECT

public:
    MWidget(QWidget *parent = nullptr);
    ~MWidget();

private:
    Ui::MWidget *ui;
    QBluetoothDeviceDiscoveryAgent *deviceDiscoveryAgent;
    QBluetoothLocalDevice *localDevice;
    QList<QBluetoothDeviceInfo> *deviceInfoList;
    QList<QBluetoothUuid> uuidList;
    QLowEnergyController *control;
    QLowEnergyService *mService;
    QLowEnergyCharacteristic mCharacter;
    QList<QLowEnergyCharacteristic> charList;

private slots:
    void mDeviceDiscovered(QBluetoothDeviceInfo deviceInfo);
    void on_openLocalDeviceBtn_clicked();
    void on_closeLocalDeviceBtn_clicked();
    void on_searchBtn_clicked();
    void on_listWidget_itemDoubleClicked(QListWidgetItem *item);
    void mServiceDiscovered(QBluetoothUuid serviceUuid);
    void mConnected();
    void on_uuidListWidget_itemDoubleClicked(QListWidgetItem *item);
    void mStateChanged(QLowEnergyService::ServiceState newState);
    void mCharacteristicChanged(QLowEnergyCharacteristic characteristic,QByteArray newValue);
    void mDescriptorWritten(QLowEnergyDescriptor descriptor,QByteArray newValue);
    void on_pushButton_clicked();
};
#endif // MWIDGET_H

(2)源文件

#include "mwidget.h"
#include "ui_mwidget.h"
#include <QTextCodec>

MWidget::MWidget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::MWidget)
{
    ui->setupUi(this);
    this->setLayout(ui->verticalLayout_2);

    //创建对象
    deviceDiscoveryAgent = new QBluetoothDeviceDiscoveryAgent(this);
    localDevice = new QBluetoothLocalDevice(this);
    deviceInfoList = new QList<QBluetoothDeviceInfo>();

    deviceDiscoveryAgent->setLowEnergyDiscoveryTimeout(5000);

    //连接槽
    connect(deviceDiscoveryAgent,SIGNAL(deviceDiscovered(QBluetoothDeviceInfo))
            ,this,SLOT(mDeviceDiscovered(QBluetoothDeviceInfo)));
}

MWidget::~MWidget()
{
    delete ui;
}

//蓝牙设备发现槽
void MWidget::mDeviceDiscovered(QBluetoothDeviceInfo deviceInfo)
{
    //如果名称不为空切为低功耗蓝牙
    if(deviceInfo.coreConfigurations() & QBluetoothDeviceInfo::LowEnergyCoreConfiguration){
        QString label = QString("%1 %2").arg(deviceInfo.name()).arg(deviceInfo.address().toString());
        ui->listWidget->addItem(label);
        deviceInfoList->append(deviceInfo);
    }
}

//打开本地蓝牙
void MWidget::on_openLocalDeviceBtn_clicked()
{
    if(localDevice->hostMode() == QBluetoothLocalDevice::HostPoweredOff){
        localDevice->powerOn();
    }
}

//关闭本地蓝牙
void MWidget::on_closeLocalDeviceBtn_clicked()
{
    localDevice->setHostMode(QBluetoothLocalDevice::HostPoweredOff);
}

void MWidget::on_searchBtn_clicked()
{
    ui->listWidget->clear();
    deviceInfoList->clear();
    deviceDiscoveryAgent->start(QBluetoothDeviceDiscoveryAgent::LowEnergyMethod);
}

//双击连接设备
void MWidget::on_listWidget_itemDoubleClicked(QListWidgetItem *item)
{
    deviceDiscoveryAgent->stop();
    Q_UNUSED(item);
    uuidList.clear();
    //创建蓝牙控制器对象
    control = QLowEnergyController::createCentral(deviceInfoList->at(ui->listWidget->currentRow()));
    connect(control,SIGNAL(serviceDiscovered(QBluetoothUuid))
            ,this,SLOT(mServiceDiscovered(QBluetoothUuid)));
    connect(control,SIGNAL(connected())
            ,this,SLOT(mConnected()));
    control->connectToDevice();
}

//发现服务uuid
void MWidget::mServiceDiscovered(QBluetoothUuid serviceUuid)
{
    QString label = QString("%1").arg(serviceUuid.toString());
    ui->uuidListWidget->addItem(label);
    uuidList.append(serviceUuid);
}

//成功连接到设备
void MWidget::mConnected()
{
    ui->textBrowser->append("成功连接"+deviceInfoList->at(ui->listWidget->currentRow()).name());
    //搜索服务
    uuidList.clear();
    control->discoverServices();
}

//双击创建服务UUID,写描述符,建立通讯
void MWidget::on_uuidListWidget_itemDoubleClicked(QListWidgetItem *item)
{
    Q_UNUSED(item);
    //创建服务
    mService = control->createServiceObject(uuidList.at(ui->uuidListWidget->currentRow()),this);
    if(mService == NULL){
        ui->textBrowser->append("创建服务失败");
    }else{
        ui->textBrowser->append("服务创建成功");
        ui->comboBox->clear();
        //监听服务状态变化
        connect(mService,SIGNAL(stateChanged(QLowEnergyService::ServiceState))
                ,this,SLOT(mStateChanged(QLowEnergyService::ServiceState)));
        //服务的characteristic变化,有数据传来
        connect(mService,SIGNAL(characteristicChanged(QLowEnergyCharacteristic,QByteArray))
                ,this,SLOT(mCharacteristicChanged(QLowEnergyCharacteristic,QByteArray)));
        //描述符成功被写
        connect(mService,SIGNAL(descriptorWritten(QLowEnergyDescriptor,QByteArray))
                ,this,SLOT(mDescriptorWritten(QLowEnergyDescriptor,QByteArray)));
        //服务详情发现函数
        mService->discoverDetails();
    }
}

//服务状态改变
void MWidget::mStateChanged(QLowEnergyService::ServiceState newState)
{
    Q_UNUSED(newState);
    //发现服务
    if(mService->state() == QLowEnergyService::ServiceDiscovered){
        charList = mService->characteristics();
        for(int i=0;i<charList.size();i++){
            mCharacter = charList.at(i);
            if(mCharacter.isValid()){
                ui->comboBox->addItem(mCharacter.uuid().toString());
                QLowEnergyDescriptor descriptor = mCharacter.descriptor(QBluetoothUuid::DescriptorType::ClientCharacteristicConfiguration);
                if(descriptor.isValid()){
                    mService->writeDescriptor(descriptor,QByteArray::fromHex("0100"));
                }
            }
        }
    }
}

//characteristic变化,数据传来
void MWidget::mCharacteristicChanged(QLowEnergyCharacteristic characteristic, QByteArray newValue)
{
    ui->textBrowser->append("接收值成功");
    Q_UNUSED(characteristic);
    QTextCodec *code = QTextCodec::codecForName("GBK");
    QString str = code->toUnicode(newValue);
    ui->textBrowser->append(str.toUtf8());
}

//描述符成功被写
void MWidget::mDescriptorWritten(QLowEnergyDescriptor descriptor, QByteArray newValue)
{
    ui->textBrowser->append(descriptor.uuid().toString()+":"+newValue);
    ui->textBrowser->append("描述符写入成功");
}

void MWidget::on_pushButton_clicked()
{
    QString text = ui->lineEdit->text();
    QTextCodec *code = QTextCodec::codecForName("GBK");
    QString str = code->toUnicode(text.toUtf8());
    mService->writeCharacteristic(charList.at(0),str.toUtf8());
}

四、与ECB02模块通信效果

(1)连接效果
连接效果
(2)写描述符,激活notify效果
激活notify效果

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

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

相关文章

UE5 C++学习笔记 FString FName FText相互转换

1.FString 是UE里的String。最接近std::string, 唯一可以修改的字符串类型。性能更低 TEXT(string) TEXT宏&#xff0c;作用是将字符串转换成Unicode&#xff0c;切记UE中使用字符串输出要使用该宏 2. FName 是UE里特有的类型。它更注重于表示名称不区分大小写&#xff0c;不…

c++学习第十一讲---文件操作

文件操作&#xff1a; c中对文件操作需要包含头文件 < fstream > 文本文件&#xff1a;以ASCII码形式储存 二进制文件&#xff1a;以二进制文件储存&#xff08;读不懂&#xff09; 操作文件三大类&#xff1a; 读&#xff1a;ifstream ; 写&#xff1a;ofstream ; 读…

旅游网站day13

1. 完善首页 1.1 首页banner查询接口 1.2 搜索服务 集成ES 1. 方式1&#xff1a;数据独立存储与独立搜索 2. 方式2&#xff1a;条件搜索与主键查询为搜索模块搭建一个服务 为什么需要api? 因为搜索也需要模型对象。 导入es依赖&#xff1a; 搜索api&#xff1a; ES工具类…

《WebKit 技术内幕》学习之十(1): 插件与JavaScript扩展

虽然目前的浏览器的功能很强 &#xff0c;但仍然有其局限性。早期的浏览器能力十分有限&#xff0c;Web前端开发者希望能够通过一定的机制来扩展浏览器的能力。早期的方法就是插件机制&#xff0c;现在流行次啊用混合编程&#xff08;Hybird Programming&#xff09;模式。插件…

transformer优化(二)-DETR 学习笔记

论文地址&#xff1a;https://arxiv.org/pdf/2005.12872.pdf 代码地址&#xff1a;https://github.com/bubbliiiing/detr-pytorch https://github.com/facebookresearch/detr 1.是什么&#xff1f; DETR&#xff08;Detection Transformer&#xff09;是一种基于Transforme…

rocketmq4.9.4有bug,生产勿用

周一早上,领导发来消息:xxxx用户:您有服务器因攻击被限制访问部分目的端口&#xff0c;详细信息请看https 排查了服务器上的异常进程后,与阿里云沟通得知,被人利用rocketmq的漏洞攻击了 服务器中毒的原因 您服务器中运行的 rocketmq 是 4.9.4 版本&#xff0c;该版本存在远程…

【.NET Core】多线程之线程池(ThreadPool)详解(一)

【.NET Core】多线程之线程池&#xff08;ThreadPool&#xff09;详解&#xff08;一&#xff09; 文章目录 【.NET Core】多线程之线程池&#xff08;ThreadPool&#xff09;详解&#xff08;一&#xff09;一、概述二、线程池的应用范围三、线程池特性3.1 线程池线程中的异常…

旅游项目day14

其他模块数据初始化 搜索实现 请求一样&#xff0c;但是参数不一样&#xff0c;根据type划分。 后台需要提供一个搜索接口。 请求分发器&#xff1a; 全部搜索 目的地搜索 精确搜索、无高亮展示 攻略搜索 全文搜索、高亮显示、分页 游记搜搜 用户搜索 丝袜哥

Python实现Lasso回归模型

• Tibshirani(1996)提出了Lasso(The Least Absolute Shrinkage and Selectionator operator)算法。 • 通过构造一个一阶惩罚函数获得一个精炼的模型&#xff1b;通过最终确定一些指标&#xff08;变量&#xff09;的系数为零&#xff08;岭回归估计系数等于0的机会微乎其微&a…

Mysql--创建数据库(1)

我们可以在登陆 MySQL 服务后&#xff0c;使用 create 命令创建数据库&#xff0c;语法如下: CREATE DATABASE 数据库名;以下命令简单的演示了创建数据库的过程&#xff0c;数据名为 R OB: [roothost]# mysql -u root -p Enter password:****** # 登录后进入终端mysql>…

什么是美颜SDK:解密视频美颜SDK背后的图像处理算法

美颜SDK是一种集成到应用程序中的工具包&#xff0c;能够通过图像处理算法实时改善或修改用户的面部外观。在本文中&#xff0c;我们将深入探讨美颜SDK的基本概念&#xff0c;并解密其背后的图像处理算法。 一、美颜SDK的基本概念 美颜SDK的应用范围广泛&#xff0c;涵盖了视…

《统计学习方法:李航》笔记 从原理到实现(基于python)-- 第1章 统计学习方法概论

文章目录 第1章 统计学习方法概论1.1 统计学习1&#xff0e;统计学习的特点2&#xff0e;统计学习的对象3&#xff0e;统计学习的目的4&#xff0e;统计学习的方法1.2.1 基本概念1.2.2 问题的形式化 1.3 统计学习三要素1.3.1 模型1.3.2 策略1.3.3 算法 1.4 模型评估与模型选择1…

助力焊接场景下自动化缺陷检测识别,基于YOLOv8【n/s/m/l/x】全系列参数模型开发构建工件表面焊接裂纹缺陷检测识别分析系统

焊接是一个不陌生但是对于开发来说相对小众的场景&#xff0c;在工件表面焊接场景下常常有对工件表面缺陷智能自动化检测识别的需求&#xff0c;工业AI结合落地是一个比较有潜力的场景&#xff0c;在我们前面的博文开发实践中也有一些相关的实践&#xff0c;感兴趣的话可以自行…

SpringBoot3.1.7集成Kafka和Kafka安装

一、背景 我们在很多系统开发都需要用到消息中间件&#xff0c;目前来说Kafka凭借其优秀的性能&#xff0c;使得它的使用率已经是名列前茅了&#xff0c;所以今天我们将它应用到我们的系统 二、版本选择 在使用一个中间件一定要考虑版本的兼容性&#xff0c;否则后面会遇到很…

搜索与图论第五期 拓扑序列

前言 拓扑排序是非常重要的一部分&#xff0c;希望大家都能够手撕代码&#xff01;&#xff01;&#xff01;&#xff08;嘿嘿嘿&#xff09; 一、拓扑排序定义&#xff08;百度须知嘿嘿嘿&#xff09; 拓扑排序 拓扑排序是一种对有向无环图&#xff08;Directed Acyclic Gra…

开始学习vue2基础篇(指令)

一、 内容渲染指令 > {{}} 模板渲染&#xff08;模板引擎&#xff09; 1. {{数据绑定}} 2. {{简单计算}} 3. {{简单逻辑运算}}&#xff08;三元运算&#xff09; 4. {{做简单 js 判断}} 注意&#xff1a;不能写语句、不能解析 html 渲染、不能放在在属性身上 > v-…

菜鸟导入导出assetbundle

因为菜鸟不会用unity c#什么的&#xff0c;所以最后参考贴吧的方法用的是UABE(Unity Assets Bundle Extractor)和UABEA(Unity Assets Bundle Extractor Avalonia) 可以去github上下载 对于txt、xml什么的可以直接改&#xff0c;但是byte文件里还是会有一些类似乱码的东西&…

算法通关村番外篇-面试150题一

大家好我是苏麟 , 今天开始LeetCode面试经典150题 . 大纲 26. 删除有序数组中的重复项80. 删除有序数组中的重复项 II 26. 删除有序数组中的重复项 描述 : 给你一个 非严格递增排列 的数组 nums &#xff0c;请你 原地 删除重复出现的元素&#xff0c;使每个元素 只出现一次 …

MIT - 线性代数-LU_LDU分解|单位矩阵

麻省理工学院 - MIT - 线性代数 第四讲 https://www.bilibili.com/video/BV1GD4y1x7Za/?spm_id_from333.1007.top_right_bar_window_history.content.click&vd_source54eff91a9ce326df74fd3b06c9fc2be322情况 老师&#xff0c;没讲明白的LU分解&#xff0c;MIT一张图就解…

【QT+QGIS跨平台编译】之五:【curl+Qt跨平台编译】(一套代码、一套框架,跨平台编译)

文章目录 一、curl介绍二、curl下载三、文件分析四、pro文件五、编译实践 一、curl介绍 curl&#xff08;CommandLine Uniform Resource Locator&#xff09;主要功能就是用不同的协议连接和沟通不同的服务器&#xff0c;相当封装了的socket。 libcurl支持http, https, ftp, g…