注意事项:

1.qt版本必须在5.14.2及以上

2.开发环境必须使用msvc 如果使用MingGW会导致无法发现任何设备

3. 必须添加qt中 bluetooth 库,qt中开发在.pro中添加 QT += quick bluetooth,vs中开发在创建qt项目时勾选bluetooth即可

4.使用bluetooth流程为 先使用QBluetoothDeviceDiscoveryAgent 扫描设备,获取到扫描的设备之后通过QLowEnergyController连接设备得到需要连接设备服务的uuid,然后通过服务的uuid连接设备,之后在获取特征(Write,Read,Notify),每一个特征都有对应的独立uuid,再通过特征去进行对应的操作

具体流程

1.扫描设备

bool Device::DevicesScan(int timeout)
{
        m_deviceDiscoveryAgent = new QBluetoothDeviceDiscoveryAgent(this);
        m_deviceDiscoveryAgent->setLowEnergyDiscoveryTimeout(timeout);    //设置超时时间
        connect(m_deviceDiscoveryAgent, SIGNAL(deviceDiscovered(QBluetoothDeviceInfo)), this,
            SLOT(addDevice(QBluetoothDeviceInfo)));//搜索到设备操作
        connect(m_deviceDiscoveryAgent, SIGNAL(finished()), this, SLOT(scanFinished()));//搜索结束
        connect(m_deviceDiscoveryAgent, QOverload<QBluetoothDeviceDiscoveryAgent::Error>::of(&QBluetoothDeviceDiscoveryAgent::error),
            this, &Device::deviceScanError);
        //connect(ui->bluemsg,SIGNAL(cursorPositionChanged()),this,SLOT(autoScroll()));    //信息一直在最下面显示
        m_deviceDiscoveryAgent->start(QBluetoothDeviceDiscoveryAgent::LowEnergyMethod);    //开始进行搜索
        return true;
    }

void Device::addDevice(const QBluetoothDeviceInfo &info) //每当扫描出一个设备就会触发该函数
{
    if (info.coreConfigurations() & QBluetoothDeviceInfo::LowEnergyCoreConfiguration)
    {//判断是否是BLE设备
        QString address = info.address().toString();
        QString name = info.name();
        QString uuid = info.deviceUuid().toString();
        QString text = QString("address :%1,name :%2,uuid :%3").arg(address).arg(name).arg(uuid);
        QHash <quint16, QByteArray> s = info.manufacturerData();
        QHash <quint16, QByteArray>::const_iterator i = s.constBegin();
        while (i != s.constEnd()) {
                qDebug() << text << text << "key:" << i.key() << "value:" << i.value();
                m_devices.append(info);
            i++;
        }
    }
}

void Device::scanFinished() //当扫描完成之后就会触发该函数
{

}

2.连接设备

注意事项:切忌不可在扫描设备对应的uuid过程中连接对应的uuid然后进行QLowEnergyService::discoverDetails操作,这样导致discoverDetails程序没有任何反应直接卡死,一定要在采用QLowEnergyController::discoveryFinished触发之后QTimer::singleShot(1000, [=] { this->serviceScanDone(); }方式调用

void Device::ConnectDevice(QString address) {
    for (int i = 0; i < m_devices.count(); i++)
    {
        if (m_devices.at(i).address().toString().left(17) == address)//地址对比
        {
            QBluetoothDeviceInfo choosenDevice = m_devices.at(i);
            ControllerConnect(choosenDevice);//发送设备信息
            m_deviceDiscoveryAgent->stop();//停止搜索服务            
            break;
        }
    }
}

void Device::ControllerConnect(QBluetoothDeviceInfo info)
{
 
    m_control = QLowEnergyController::createCentral(info, this);
          //开始连接目标设备
    
    connect(m_control, &QLowEnergyController::serviceDiscovered,
        this, &Device::serviceDiscovered);    //发现了目标设备后触发的操作

connect(m_control, &QLowEnergyController::discoveryFinished, [=] {
            QTimer::singleShot(1000, [=] { this->serviceScanDone(); });
        });    //配置服务
    connect(m_control, &QLowEnergyController::disconnected,
        this, &Device::deviceDisconnected);
    //connect(m_control, static_cast<void (QLowEnergyController::*)(QLowEnergyController::Error)>(&QLowEnergyController::error),
    //    this, [this](QLowEnergyController::Error error) {
    //        Q_UNUSED(error);
    //    });

connect(m_control, &QLowEnergyController::connected, this, &Device::ControllerConnected);

connect(m_control, &QLowEnergyController::disconnected, this, &Device::ControllerDisconnected);

m_control->connectToDevice();
  
}

void Device::ControllerConnected() {
    //成功连接触发的槽函数    
    m_control->discoverServices();
}
void Device::ControllerDisconnected() {
    //错误连接
    
}

void Device::serviceScanDone() {
    for (auto nextlist : m_BleHandleList) {
        nextlist->CreateServic();
    }
}

void Device::serviceDiscovered(const QBluetoothUuid& gatt)
{
    try {
        QList <QBluetoothUuid> uuids = m_control->services();
        //ui->bluemsg->insertPlainText(QString("%1").arg(gatt.toString()));
        //m_foundHeartRateService = true;

BleHandle* ble = new BleHandle(m_control, gatt);
        m_BleHandleList.append(ble);
    }
    catch (...) {
        qDebug() << "serviceDiscovered error";
    }
    
}

3.连接对应的uuid服务,获取对应的特征

备注:Notify的特征的数据回传触发的是QLowEnergyService::characteristicChanged,并不是QLowEnergyService::characteristicRead

bool BleHandle::CreateServic() {
    m_service = m_control->createServiceObject(QBluetoothUuid(serviceUuid), this);
    if (!m_service)
    {
        return false;
    }
    connect(m_service, &QLowEnergyService::stateChanged, this,&BleHandle::serviceStateChanged);
    connect(m_service, &QLowEnergyService::characteristicChanged, this,&BleHandle::BleServiceCharacteristicChanged);
    connect(m_service, SIGNAL(characteristicWritten(QLowEnergyCharacteristic, QByteArray)),
        this, SLOT(BleServiceCharacteristicWrite(QLowEnergyCharacteristic, QByteArray)));
    connect(m_service, SIGNAL(characteristicRead(QLowEnergyCharacteristic, QByteArray)),
        this, SLOT(BleServiceCharacteristicRead(QLowEnergyCharacteristic, QByteArray)));
  
    connect(m_service,static_cast<void(QLowEnergyService::*)(QLowEnergyService::ServiceError)>(&QLowEnergyService::error),
        [=](QLowEnergyService::ServiceError newErrorr)
    {
            
        if(QLowEnergyService::NoError == newErrorr)

{
    
            //ui->plainTextEdit_BluetoothInfiShow->insertPlainText("没有发生错误。\n");
    
        }
    
        if(QLowEnergyService::OperationError==newErrorr)
    
        {
    
            // ui->plainTextEdit_BluetoothInfiShow->insertPlainText("错误: 当服务没有准备好时尝试进行操作!\n");
    
        }
    
        if(QLowEnergyService::CharacteristicReadError==newErrorr)
    
        {
    
            // ui->plainTextEdit_BluetoothInfiShow->insertPlainText("尝试读取特征值失败!\n");
    
        }
    
        if(QLowEnergyService::CharacteristicWriteError==newErrorr)
    
        {
    
            //ui->plainTextEdit_BluetoothInfiShow->insertPlainText("尝试为特性写入新值失败!\n");
    
        }
    
        if(QLowEnergyService::DescriptorReadError==newErrorr)
    
        {
    
            //ui->plainTextEdit_BluetoothInfiShow->insertPlainText("尝试读取描述符值失败!\n");
    
        }
        if(QLowEnergyService::DescriptorWriteError==newErrorr)
        {
    
            // ui->plainTextEdit_BluetoothInfiShow->insertPlainText(" 尝试向描述符写入新值失败!\n");
    
        }
        if(QLowEnergyService::UnknownError==newErrorr)
    
        {
            // ui->plainTextEdit_BluetoothInfiShow->insertPlainText("与服务交互时发生未知错误!\n");
        }
    });

if (m_service->state() == QLowEnergyService::DiscoveryRequired)
    {
        m_service->discoverDetails();
    }
    else
    {
        searchCharacteristic();
    }
    
    return true;
}

void BleHandle::BleServiceCharacteristicChanged(const QLowEnergyCharacteristic& c, const QByteArray& value) {//特征为Notify收到ble回传的数据会触发该函数

}

void BleHandle::serviceStateChanged(QLowEnergyService::ServiceState s) {
    qDebug() << "serviceStateChanged:" << s;
    if (s == QLowEnergyService::ServiceDiscovered)
    {
        //        ui->bluemsg->append("服务已同步\n");
       // emit fromBle("服务已同步");

searchCharacteristic();
    }
}

void BleHandle::BleServiceCharacteristicRead(const QLowEnergyCharacteristic& c, const QByteArray& value) { //特征为red时收到ble回传的数据会触发该函数

}

void BleHandle::BleServiceCharacteristicWrite(const QLowEnergyCharacteristic& c, const QByteArray& value)
{
    //ui->bluemsg->append(QString("指令%1发送成功").arg(QString(value)));
}

void BleHandle::searchCharacteristic()
{
    if (m_service)
    {
        QList<QLowEnergyCharacteristic> list = m_service->characteristics();
        qDebug() << "list.count()=" << list.count() << "uuid" << m_service->serviceUuid().toString();
        //characteristics 获取详细特性
        SendMaxMode = list.count();  //设置模式选择上限
        for (int i = 0; i < list.count(); i++)
        {
            
            qDebug() << "index " << i << "uuid" << list.at(i).uuid().toString();
            QLowEnergyCharacteristic c = list.at(i);
            /*如果QLowEnergyCharacteristic对象有效,则返回true,否则返回false*/
            if (c.isValid())
            {
                //                返回特征的属性。
                //                这些属性定义了特征的访问权限。
                if (c.properties() & QLowEnergyCharacteristic::WriteNoResponse || c.properties() & QLowEnergyCharacteristic::Write)
                    // if(c.properties() & QLowEnergyCharacteristic::Write)
                {
                    //ui->bluemsg->insertPlainText("具有写权限!\n");
                    m_writeCharacteristic = c;  //保存写权限特性
                    if (c.properties() & QLowEnergyCharacteristic::WriteNoResponse)
                    {
                       //                        如果使用此模式写入特性,则远程外设不应发送写入确认。
                      //                        无法确定操作的成功,并且有效负载不得超过20个字节。
                      //                        一个特性必须设置QLowEnergyCharacteristic :: WriteNoResponse属性来支持这种写模式。
                      //                         它的优点是更快的写入操作,因为它可能发生在其他设备交互之间。
                        m_writeMode = QLowEnergyService::WriteWithoutResponse;
                        qDebug() << "WriteWithoutResponse " << "uuid" << list.at(i).uuid().toString();
                    }
                    else
                    {
                        //如果使用此模式写入特性,则外设应发送写入确认。
                        //如果操作成功,则通过characteristicWritten()信号发出确认。
                        //否则,发出CharacteristicWriteError。
                        //一个特性必须设置QLowEnergyCharacteristic :: Write属性来支持这种写模式。
                        m_writeMode = QLowEnergyService::WriteWithResponse;
                        qDebug() << "WriteWithResponse " << "uuid" << list.at(i).uuid().toString();
                    }
                 
                }

if (c.properties() & QLowEnergyCharacteristic::Read)
                {
                    m_readCharacteristic = c; //保存读权限特性
                    qDebug() << "Read " << "uuid" << list.at(i).uuid().toString();
                }
                
                if (c.properties() & QLowEnergyCharacteristic::Notify)
                {
                    QLowEnergyCharacteristicData* character = new QLowEnergyCharacteristicData();
                    character->setUuid(c.uuid());
                    character->setValue(c.value());
                    character->setProperties(c.properties());
                    
                    m_notifyCharacteristic = c; //保存通知权限特性
                    qDebug() << "Notify " << "uuid" << list.at(i).uuid().toString();
                }
                //描述符定义特征如何由特定客户端配置。
                m_notificationDesc = c.descriptor(QBluetoothUuid::ClientCharacteristicConfiguration);
                //值为真
                if (m_notificationDesc.isValid())
                {
                    //写描述符
                    m_service->writeDescriptor(m_notificationDesc, QByteArray::fromHex("0100"));
                    //   m_service->writeDescriptor(m_notificationDesc, QByteArray::fromHex("FEE1"));
                   // ui->bluemsg->insertPlainText("写描述符!\n");
                }
            }
        }
    }
}

void BleHandle::SendMsg(QString text) //发送消息
{
    QByteArray array = text.toLocal8Bit();

m_service->writeCharacteristic(m_writeCharacteristic, array, m_writeMode);
}

qt windows ble低功耗蓝牙相关推荐

  1. 13.6.3 程序案例:BLE低功耗蓝牙调试助手

    13.6.3 程序案例:BLE低功耗蓝牙调试助手 (配套代码CH13-02) (1) mainwindow.cpp文件代码 #include "mainwindow.h" #inc ...

  2. android studio蓝牙低功耗,arduino ESP32 AndroidStudio BLE低功耗蓝牙 物联网

    arduino ESP32 AndroidStudio BLE低功耗蓝牙 物联网 nodered开发: esp32采用的蓝牙于普通的蓝牙不同,是低功耗蓝牙,手机用一般的蓝牙代码是连不上的.在本文中,不 ...

  3. 自制智能插线板,内嵌BLE低功耗蓝牙,通过手机进行控制(一)

    一直都想做一个可以用手机控制的插线板,现在已经进入了智能家居的时代,家里没有个智能的插线板去控制一些简单的家用设备,怎么能算得上智能家居呢:有这个想法已经很久了,当时还特意买了一个插线板,拆开看看里面 ...

  4. Qt windows端的蓝牙串口服务

    Qt windows端的蓝牙串口服务 环境 系统 Qt 蓝牙模块 使用步骤 蓝牙模块参数获取 配对 扫描.连接.数据收发 扫描 连接 数据收发 环境 系统 只测试过自己电脑,系统版本如下: 查看方式按 ...

  5. BLE低功耗蓝牙和传统蓝牙的五大区别

    现在移动设备上使用的蓝牙大多是4.0,而蓝牙 4.0 有两个分支,经典 4.0 和 BLE4.0,经典 4.0 就是传统的3.0 蓝牙升级而成,向下兼容.而 BLE 4.0 是一个新的分支,不向下兼容 ...

  6. BT传统蓝牙和BLE低功耗蓝牙的区别

    蓝牙3.0及以下为传统蓝牙.   蓝牙4.0以上标准包含两个蓝牙标准,是一个双模的标准,它包含经典蓝牙部分(Classic Bluetooth)和低功耗蓝牙部分(Bluetooth Low Energ ...

  7. 基于uni-app的BLE低功耗蓝牙测试工具

    基于uni-app的BLE低功耗蓝牙测试工具 前言 开发环境:HBuilder X2.8.11,运行环境:微信小程序 本项目是从网上收集他人的源代码,经过测试.修改后的版本,在微信小程序上表现比较稳定 ...

  8. Android BLE低功耗蓝牙开发

    啦啦啦在上一个项目中有用到BLE低功耗蓝牙开发,当时baidu google了很多资料,但大多数都是千篇一律,英文文档我这种渣渣又看不懂...总之刚开始查的很痛苦.所以要把自己的踩坑之路写下来记录下, ...

  9. ble 低功耗蓝牙开发学习 嵌入式交流学习

    ble 低功耗蓝牙开发学习 嵌入式交流学习 提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 这篇文章教你学会低功耗蓝牙开发,从0到深入,适合自学的学生.初级工程师 前言 随着疫情爆发 ...

最新文章

  1. python中mainloop什么意思_Python Turtle mainloop()用法
  2. Hibernate Write operations are not allowed in read-only
  3. HTTP协议---HTTP请求中的常用请求字段和HTTP的响应状态码及响应头
  4. JVM调优:定位垃圾的常用算法
  5. 《销售从被拒绝开始》叶冠1
  6. Java中内存中的Heap、Stack与程序运行的关系
  7. JMeter定制功能实现
  8. 早晨爬山,三餐自备——程序员也可以这样生活、工作
  9. C++远征之封装篇——字符串类型
  10. mysql 用户管理系统_mysql 用户管理
  11. 查询引擎: SQL反解析(json2sql)(附源码)
  12. c++ 中断_「正点原子NANO STM32开发板资料连载」第十章 外部中断实验
  13. 矩阵分析与应用学习总结目录
  14. UTF-8 ,UTF8, GBK,GB2312 之间的关系和区别
  15. PHPExcel浏览器输出Excel2007出错
  16. 欧拉函数φ(x)相关性质及计算
  17. MathType开学季,半价倾情奉献
  18. 《我想进大厂》之kafka夺命连环11问
  19. CLIPS 的简单认识
  20. sqlserver数据库如何快速查看表结构sql

热门文章

  1. 机器学习中的聚类算法有哪几种?
  2. python 提取列表中长度大于3的字符串,列表中什么元素都有
  3. cad线性标注命令_CAD尺寸标注命令
  4. Linux ASPM 问题一个适合的解决方案
  5. 引力产生的原因是什么
  6. 修改电量android,安卓手机端修改电池电量图标的教程
  7. 54个提高PHP程序运行效率的方法(转载)
  8. 高通Linux Android 平台中的蓝牙功能学习 (4)-- Android Marshmallow 中的蓝牙 4.2
  9. 关于微软IIS7安全性
  10. 【机器学习】Tensorflow.js:我在浏览器中实现了迁移学习