win32下Qt5BLE蓝牙开发笔记

Qt 同时被 3 个专栏收录
10 篇文章 0 订阅
1 篇文章 0 订阅
6 篇文章 0 订阅

BLE简介

BLE蓝牙是蓝牙2.0以上的蓝牙模块,经典蓝牙是蓝牙2.0以下的蓝牙。蓝牙分为客户端和服务器两端,经典蓝牙可以通过socket编程进行客户端与服务器之间的通信(与网络socket相似),BLE蓝牙则无法使用这种方式进行通信。BLE蓝牙下有服务、特征值,所谓的BLE蓝牙通信其实就是对特征值的一个读写操作。微软的Windows下的API关于BLE蓝牙的C++API相对较少,C#的API会相对较多一点。我实现这个蓝牙的demo则是使用了Qt进行一个开发。

需要注意的是Qt中开发所用到的QBlueTooth库在Windows下的只支持win10以上系统,而且需要Qt版本在5.15以上,编译器一定要用MSVC编译,否则无法支持Windows平台。

Qt5BLE蓝牙开发

本文环境为Qt5.15.2
若要在Qt中使用蓝牙库需要在.pro文件添加一下一句话

QT += bluetooth

BLE蓝牙开发流程

首先讲一下我自己对BLE蓝牙的理解,BLE蓝牙有名字和地址,蓝牙设备下又有服务,服务有特定的的uuid,可以理解为服务的识别码,服务下有特征,BLE蓝牙服务可以有0-3个特征,分别是读、写、特征值通知这三个。如果服务拥有读特征,就可以从此服务中读消息,如果服务拥有写特征,就可以发送消息给服务,如果服务有特征值改变通知这个特征,则当服务的特征值发生改变时会发送消息通知。

  1. 蓝牙的权限问题(Windows平台下不存在此问题,可以忽略,在安卓平台下不管是Qt还是Java都需要考虑这个问题)
  2. 搜索周边蓝牙
  3. 连接蓝牙
  4. 获取服务
  5. 获取服务下特征,每个服务下都有0-3个特性,分别对应了读,写,以及特性发生改变时是否通知
  6. 与BLE设备通信(其实就是对某个服务进行读写操作)

Bluetooth在Qt中所涉及Class与APIQt中所涉及到的蓝牙头文件与类

#include <QBluetoothLocalDevice>
#include <QBluetoothUuid>
#include <QBluetoothDeviceDiscoveryAgent>
#include <QLowEnergyService>
#include <QLowEnergyController>

在windows平台和ios平台下QBluetoothLocalDevice类无法使用
因为平台不会公开任何可能在本地Bluetooth设备上提供信息的数据或API

QBluetoothDeviceDiscoveryAgent -- 蓝牙搜索类(BLE蓝牙或经典蓝牙都使用此类进行搜索)
LowEnergyController -- BLE蓝牙设备进行访问类
QLowEnergyService -- BLE蓝牙服务类

具体实现

1.实现附近BLE蓝牙的搜索


	QBluetoothDeviceDiscoveryAgent *Discovery = new QBluetoothDeviceDiscoveryAgent;
	Discovery->setLowEnergyDiscoveryTimeout(30000);//设置搜索时间为30000us
	
	//当搜索蓝牙完成之后会发射[Signal]finished()
	connect(Discovery, SIGNAL(finished()), 
			this, SLOT(findFinish()));
	
	//找到蓝牙设备会发送[Signal]deviceDiscovered(QBluetoothDeviceInfo)
	connect(Discovery, SIGNAL(deviceDiscovered(QBluetoothDeviceInfo)), 
			this, SLOT(addBlueToothDevicesToList(QBluetoothDeviceInfo)));
	
	//start启动搜索,若查找为BLE蓝牙需要写入参数		 	   
	//QBluetoothDeviceDiscoveryAgent::LowEnergyMethod
	Discovery->start(QBluetoothDeviceDiscoveryAgent::LowEnergyMethod);

2.实现连接BLE蓝牙

//void QLowEnergyController::creatCentral(const QBluetoothDeviceInfo &remotedevice,QObject *parent)
	//参数:remotedevice -- 远端设备的信息 parent -- 父类
	//返回值:无
	//功能:初始化对远程蓝牙访问的控制器
	mController = QLowEnergyController::createCentral(currentDevice,this);
	
	connect(mController, &QLowEnergyController::serviceDiscovered,this, &MainWindow::serviceDiscovered);//扫描目标BLE服务,获取一次触发一次
	connect(mController, &QLowEnergyController::discoveryFinished,this, &MainWindow::serviceScanDone);  //扫描完成之后会触发此信号
	
	connect(mController, static_cast<void (QLowEnergyController::*)(QLowEnergyController::Error)>(&QLowEnergyController::error),
	        this, [this](QLowEnergyController::Error error) {
	        Q_UNUSED(error);
	        QMessageBox::information(this,tr("Info"),tr("Cannot connect to remote device."));
	    });//连接出错
	connect(mController, &QLowEnergyController::connected, this, [this]() {
	        QMessageBox::information(this,tr("Info"),tr("Controller connected. Search services..."));
	        mController->discoverServices();
	    });//连接成功
	connect(mController, &QLowEnergyController::disconnected, this, [this]() {
	        QMessageBox::information(this,tr("Info"),tr("LowEnergy controller disconnected"));
	    });//断开连接
	mController->connectToDevice();//建立连接,若连接没有出错,会自动搜索连接设备的服务

3.获取服务

//mController->connectToDevice();建立连接后若无出错,会自动进行远程设备的服务扫描
//当服务被找到时触发此槽函数

//服务被找到
void MainWindow::serviceDiscovered(const QBluetoothUuid & serviceUuid)
{
    QLowEnergyService *service = mController->createServiceObject(serviceUuid);
//同步服务
    if (!service)
    {
        QMessageBox::information(NULL,"error","Cannot create service for uuid");
        return;
    }

    connect(service, &QLowEnergyService::stateChanged, this,&MainWindow::serviceStateChanged);
//服务状态值发生改变
    connect(service, &QLowEnergyService::characteristicChanged, this,&MainWindow::BleServiceCharacteristicChanged);
//特征值发生改变
    connect(service, &QLowEnergyService::characteristicRead, this,&MainWindow::BleServiceCharacteristicRead);
//读信息成功
    connect(service, SIGNAL(characteristicWritten(QLowEnergyCharacteristic,QByteArray)),this, SLOT(BleServiceCharacteristicWrite(QLowEnergyCharacteristic,QByteArray)));
//写信息成功

    if(service->state() == QLowEnergyService::DiscoveryRequired)
        service->discoverDetails();
//扫描特征值

    serviceList.append(service);
}

//服务状态值改变会触发此槽函数
//当蓝牙服务被扫描到时状态值会发生改变,改变为QLowEnergyService::ServiceDiscovered
void MainWindow::serviceStateChanged(QLowEnergyService::ServiceState s)
{
    if(s == QLowEnergyService::ServiceDiscovered)
    {
        //QMessageBox::information(NULL,"tips",QObject::tr("Service synchronization"));
        //TODO....
    }
}

4.扫描服务特征值

void MainWindow::searchCharacteristic()
{
    if(currentService)
    {
        memset(m_Characteristic,0,sizeof(m_Characteristic));
        QList<QLowEnergyCharacteristic> list = currentService->characteristics();
        //characteristics 获取详细特性
        foreach(QLowEnergyCharacteristic c,list)
        {
            /*如果QLowEnergyCharacteristic对象有效,则返回true,否则返回false*/
            if(c.isValid())
            {
                //返回特征的属性。
                //这些属性定义了特征的访问权限。
				//保存特性(读、写、改变时是否通知)
                if(c.properties() & QLowEnergyCharacteristic::WriteNoResponse || c.properties() & QLowEnergyCharacteristic::Write)//write
                // if(c.properties() & QLowEnergyCharacteristic::Write)
                {
                    ui->checkBox_write->setChecked(true);
                    m_Characteristic[0] = c;
                }
                else
                    ui->checkBox_write->setChecked(false);
                if(c.properties() & QLowEnergyCharacteristic::Read)//读
                {
                    ui->checkBox_read->setChecked(true);
                    m_Characteristic[1] = c;
                }
                else
                    ui->checkBox_read->setChecked(true);
                if(c.properties() & QLowEnergyCharacteristic::Notify)//特性发生改变时是否通知
                {
                    ui->checkBox_notify->setChecked(true);
                    m_Characteristic[2] = c;
                }
                else
                    ui->checkBox_notify->setChecked(false);
            }
        }
    }
}

5.BLE蓝牙的读、写操作

//void QLowEnergyService::writeCharacteristic(const QLowEnergyCharacteristic &characteristic, const QByteArray &newValue, QLowEnergyService::WriteMode mode = WriteWithResponse)
//参数:characteristic -- 当前服务的某个特性值 newValue -- 写入数据 WriteMode mode -- 写入模式
//返回值:无
//功能:发送信息给BLE
currentService->writeCharacteristic(m_Characteristic[0], QByteArray(text.toUtf8()));
//发送消息成功触发此槽函数
void MainWindow::BleServiceCharacteristicWrite(const QLowEnergyCharacteristic &c, const QByteArray &value)
{
    QString str(c.uuid().toString());
    QString str2("instructions %1 send to success!");
    QString str3 = str + QString(":") + str2.arg(QString(value));
    QMessageBox::information(NULL,"tips",str3);
}
//void QLowEnergyService::readCharacteristic(const QLowEnergyCharacteristic &characteristic)
//参数:characteristic -- 当前服务的某个特性值
//返回值:无
//功能:从BLE中读取信息
currentService->readCharacteristic(m_Characteristic[1]);
//读到消息触发此槽函数
void MainWindow::BleServiceCharacteristicRead(const QLowEnergyCharacteristic &c, const QByteArray &value)
{
    QTextCodec *codec = QTextCodec::codecForName("GBK");//指定QString的编码方式
    QString showMsg = c.uuid().toString() + codec->toUnicode(value);//Unicode编码格式输出信息
    QString valuetoHexString = value.toHex();//16进制输出信息

    qDebug()<<value;
    qDebug()<<valuetoHexString;
    ui->listWidget_recv->addItem(showMsg);
    ui->listWidget_recv->setCurrentRow(ui->listWidget_recv->count()-1);
}

源码下载

https://download.csdn.net/download/weixin_46276101/19686524?spm=1001.2014.3001.5503

  • 1
    点赞
  • 10
    评论
  • 6
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

©️2021 CSDN 皮肤主题: 游动-白 设计师:白松林 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值