qt windows ble低功耗蓝牙
注意事项:
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低功耗蓝牙相关推荐
- 13.6.3 程序案例:BLE低功耗蓝牙调试助手
13.6.3 程序案例:BLE低功耗蓝牙调试助手 (配套代码CH13-02) (1) mainwindow.cpp文件代码 #include "mainwindow.h" #inc ...
- android studio蓝牙低功耗,arduino ESP32 AndroidStudio BLE低功耗蓝牙 物联网
arduino ESP32 AndroidStudio BLE低功耗蓝牙 物联网 nodered开发: esp32采用的蓝牙于普通的蓝牙不同,是低功耗蓝牙,手机用一般的蓝牙代码是连不上的.在本文中,不 ...
- 自制智能插线板,内嵌BLE低功耗蓝牙,通过手机进行控制(一)
一直都想做一个可以用手机控制的插线板,现在已经进入了智能家居的时代,家里没有个智能的插线板去控制一些简单的家用设备,怎么能算得上智能家居呢:有这个想法已经很久了,当时还特意买了一个插线板,拆开看看里面 ...
- Qt windows端的蓝牙串口服务
Qt windows端的蓝牙串口服务 环境 系统 Qt 蓝牙模块 使用步骤 蓝牙模块参数获取 配对 扫描.连接.数据收发 扫描 连接 数据收发 环境 系统 只测试过自己电脑,系统版本如下: 查看方式按 ...
- BLE低功耗蓝牙和传统蓝牙的五大区别
现在移动设备上使用的蓝牙大多是4.0,而蓝牙 4.0 有两个分支,经典 4.0 和 BLE4.0,经典 4.0 就是传统的3.0 蓝牙升级而成,向下兼容.而 BLE 4.0 是一个新的分支,不向下兼容 ...
- BT传统蓝牙和BLE低功耗蓝牙的区别
蓝牙3.0及以下为传统蓝牙. 蓝牙4.0以上标准包含两个蓝牙标准,是一个双模的标准,它包含经典蓝牙部分(Classic Bluetooth)和低功耗蓝牙部分(Bluetooth Low Energ ...
- 基于uni-app的BLE低功耗蓝牙测试工具
基于uni-app的BLE低功耗蓝牙测试工具 前言 开发环境:HBuilder X2.8.11,运行环境:微信小程序 本项目是从网上收集他人的源代码,经过测试.修改后的版本,在微信小程序上表现比较稳定 ...
- Android BLE低功耗蓝牙开发
啦啦啦在上一个项目中有用到BLE低功耗蓝牙开发,当时baidu google了很多资料,但大多数都是千篇一律,英文文档我这种渣渣又看不懂...总之刚开始查的很痛苦.所以要把自己的踩坑之路写下来记录下, ...
- ble 低功耗蓝牙开发学习 嵌入式交流学习
ble 低功耗蓝牙开发学习 嵌入式交流学习 提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 这篇文章教你学会低功耗蓝牙开发,从0到深入,适合自学的学生.初级工程师 前言 随着疫情爆发 ...
最新文章
- python中mainloop什么意思_Python Turtle mainloop()用法
- Hibernate Write operations are not allowed in read-only
- HTTP协议---HTTP请求中的常用请求字段和HTTP的响应状态码及响应头
- JVM调优:定位垃圾的常用算法
- 《销售从被拒绝开始》叶冠1
- Java中内存中的Heap、Stack与程序运行的关系
- JMeter定制功能实现
- 早晨爬山,三餐自备——程序员也可以这样生活、工作
- C++远征之封装篇——字符串类型
- mysql 用户管理系统_mysql 用户管理
- 查询引擎: SQL反解析(json2sql)(附源码)
- c++ 中断_「正点原子NANO STM32开发板资料连载」第十章 外部中断实验
- 矩阵分析与应用学习总结目录
- UTF-8 ,UTF8, GBK,GB2312 之间的关系和区别
- PHPExcel浏览器输出Excel2007出错
- 欧拉函数φ(x)相关性质及计算
- MathType开学季,半价倾情奉献
- 《我想进大厂》之kafka夺命连环11问
- CLIPS 的简单认识
- sqlserver数据库如何快速查看表结构sql