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);
}
更多推荐


所有评论(0)