从 BLE 传感器获取心脏频率
get heart frequency frome a BLE sensor
我尝试在需要心脏频率的Qt creator(C++) 上开发一个windows 10 软件。我买了下面的传感器,它通过蓝牙传输数据(BLE:蓝牙低能量):
但是当我尝试读取值时,我有一个空缓冲区。
传感器在 android 应用程序(Play 商店)上正常工作
我的代码:
初始化:OK
TWindowsStatistique::TWindowsStatistique(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::TWindowsStatistique)
{
QBluetoothDeviceDiscoveryAgent *discoveryAgent = new QBluetoothDeviceDiscoveryAgent(this);
connect(discoveryAgent, SIGNAL(deviceDiscovered(QBluetoothDeviceInfo)),this, SLOT(deviceDiscovered(QBluetoothDeviceInfo)));
discoveryAgent->start();
}
获取蓝牙设备列表:确定
void TWindowsStatistique::deviceDiscovered(const QBluetoothDeviceInfo &device)
{
if(device.name()=="Decathlon Dual HR")
{
m_device=device;
if (!controller)
{
controller = QLowEnergyController::createCentral(device);
connect(controller, &QLowEnergyController::connected,this, &TWindowsStatistique::deviceConnected);
connect(controller, QOverload<QLowEnergyController::Error>::of(&QLowEnergyController::error),this, &TWindowsStatistique::errorReceived);
connect(controller, &QLowEnergyController::disconnected,this, &TWindowsStatistique::deviceDisconnected);
}
controller->connectToDevice();
}
}
获取服务列表:确定
void TWindowsStatistique::deviceConnected()
{
connect(controller, &QLowEnergyController::serviceDiscovered,this, &TWindowsStatistique::addLowEnergyService);
connect(controller, &QLowEnergyController::discoveryFinished,this, &TWindowsStatistique::serviceScanDone);
controller->discoverServices();
}
void TWindowsStatistique::addLowEnergyService(const QBluetoothUuid &newService)
{
QLowEnergyService *service = controller->createServiceObject(newService);
if (!service) return;
if(service->serviceName()=="Heart Rate")
{
heart_rate_service=service;
}
}
void TWindowsStatistique::serviceScanDone()
{
if(heart_rate_service!=NULL)
{
connect(heart_rate_service, &QLowEnergyService::stateChanged, this, &TWindowsStatistique::serviceDetailsDiscovered);
heart_rate_service->discoverDetails();
}
}
获取特征列表:确定
有心率数据:NOK
void TWindowsStatistique::serviceDetailsDiscovered(QLowEnergyService::ServiceState newState)
{
const QList<QLowEnergyCharacteristic> chars = heart_rate_service->characteristics();
for (int i=0;i<chars.size();i++)
{
QLowEnergyCharacteristic tmp_char=chars.at(i);
if(tmp_char.name()=="Heart Rate Measurement")//the code go in : **OK**
{
qDebug() << "carac value" << chars.at(i).value().toHex();//return a empty buffer : **NOK**
//test by using a class with notify requerement : **NOK**
// in THeartRateCharacteristic.h: Q_PROPERTY(QString characteristicValue READ getValue NOTIFY characteristicChanged)
heart_rate_characteristic = new THeartRateCharacteristic(tmp_char);
//test by using characteristicChanged : slot isn't call : **NOK**
connect(heart_rate_characteristic, SIGNAL(characteristicChanged()), this, SLOT(heart_rate_update()));
//try tu use readCharacteristic : the sensor doesn't answer **NOK**
heart_rate_service->readCharacteristic(tmp_char);
//Test to put notification flag to 1 : **heart rate data stay empty**
for(int j=0;j<chars.at(i).descriptors().size();j++)
{
if(chars.at(i).descriptors().at(j).name()=="Client Characteristic Configuration")
{
QByteArray tmp=chars.at(i).descriptors().at(j).value();
tmp[1]=0;
tmp[0]=1;
if(chars.at(i).descriptors().at(j).value().compare(tmp)!=0)
{
connect(heart_rate_service, &QLowEnergyService::descriptorWritten,this, &TWindowsStatistique::descriptorWritten_slot);
connect(heart_rate_service, SIGNAL(error(QLowEnergyService::ServiceError)),this, SLOT(service_error_slot(QLowEnergyService::ServiceError)));
heart_rate_service->writeDescriptor(chars.at(i).descriptors().at(j),tmp);
}
}
}
}
}
}
void TWindowsStatistique::timer_1s_timeout()
{
if(heart_rate_characteristic)
{
qDebug() << "timer: data value:" << heart_rate_characteristic->getValue();//return a empty buffer : **NOK**
}
}
connect(heart_rate_characteristic, SIGNAL(characteristicChanged()), this, SLOT(heart_rate_update()));
将不起作用,因为信号 characteristicChanged
在 QLowEnergyService
服务 class 中声明,而不是在 QLowEnergyCharacteristic
特征 class 中声明, 因此您必须使用该服务将此信号连接到您的插槽。
顺便说一句,我建议您尝试 Qt 示例项目“蓝牙低功耗心率游戏”,它提供了完全符合您要求的完整代码。只需编译并 运行 它。然后,如果它在您的设备上运行良好,请将代码与您的代码进行比较,并可能使用调试器来了解为什么您的代码在该设备运行时失败。
我用 QT5.12 (MSVC 2017) 测试了 Qt 示例项目“蓝牙低功耗心率游戏”=> 我一直在等待屏幕。
我用 QT6.02 (MSVC 2019) 测试了 Qt 示例项目“蓝牙低功耗心率游戏”=> 成功了。
所以我将在 6.2 中使用 MSVC 2019 继续我的软件。
@jpo38 : 谢谢你的帮助
我尝试在需要心脏频率的Qt creator(C++) 上开发一个windows 10 软件。我买了下面的传感器,它通过蓝牙传输数据(BLE:蓝牙低能量):
但是当我尝试读取值时,我有一个空缓冲区。
传感器在 android 应用程序(Play 商店)上正常工作
我的代码:
初始化:OK
TWindowsStatistique::TWindowsStatistique(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::TWindowsStatistique)
{
QBluetoothDeviceDiscoveryAgent *discoveryAgent = new QBluetoothDeviceDiscoveryAgent(this);
connect(discoveryAgent, SIGNAL(deviceDiscovered(QBluetoothDeviceInfo)),this, SLOT(deviceDiscovered(QBluetoothDeviceInfo)));
discoveryAgent->start();
}
获取蓝牙设备列表:确定
void TWindowsStatistique::deviceDiscovered(const QBluetoothDeviceInfo &device)
{
if(device.name()=="Decathlon Dual HR")
{
m_device=device;
if (!controller)
{
controller = QLowEnergyController::createCentral(device);
connect(controller, &QLowEnergyController::connected,this, &TWindowsStatistique::deviceConnected);
connect(controller, QOverload<QLowEnergyController::Error>::of(&QLowEnergyController::error),this, &TWindowsStatistique::errorReceived);
connect(controller, &QLowEnergyController::disconnected,this, &TWindowsStatistique::deviceDisconnected);
}
controller->connectToDevice();
}
}
获取服务列表:确定
void TWindowsStatistique::deviceConnected()
{
connect(controller, &QLowEnergyController::serviceDiscovered,this, &TWindowsStatistique::addLowEnergyService);
connect(controller, &QLowEnergyController::discoveryFinished,this, &TWindowsStatistique::serviceScanDone);
controller->discoverServices();
}
void TWindowsStatistique::addLowEnergyService(const QBluetoothUuid &newService)
{
QLowEnergyService *service = controller->createServiceObject(newService);
if (!service) return;
if(service->serviceName()=="Heart Rate")
{
heart_rate_service=service;
}
}
void TWindowsStatistique::serviceScanDone()
{
if(heart_rate_service!=NULL)
{
connect(heart_rate_service, &QLowEnergyService::stateChanged, this, &TWindowsStatistique::serviceDetailsDiscovered);
heart_rate_service->discoverDetails();
}
}
获取特征列表:确定 有心率数据:NOK
void TWindowsStatistique::serviceDetailsDiscovered(QLowEnergyService::ServiceState newState)
{
const QList<QLowEnergyCharacteristic> chars = heart_rate_service->characteristics();
for (int i=0;i<chars.size();i++)
{
QLowEnergyCharacteristic tmp_char=chars.at(i);
if(tmp_char.name()=="Heart Rate Measurement")//the code go in : **OK**
{
qDebug() << "carac value" << chars.at(i).value().toHex();//return a empty buffer : **NOK**
//test by using a class with notify requerement : **NOK**
// in THeartRateCharacteristic.h: Q_PROPERTY(QString characteristicValue READ getValue NOTIFY characteristicChanged)
heart_rate_characteristic = new THeartRateCharacteristic(tmp_char);
//test by using characteristicChanged : slot isn't call : **NOK**
connect(heart_rate_characteristic, SIGNAL(characteristicChanged()), this, SLOT(heart_rate_update()));
//try tu use readCharacteristic : the sensor doesn't answer **NOK**
heart_rate_service->readCharacteristic(tmp_char);
//Test to put notification flag to 1 : **heart rate data stay empty**
for(int j=0;j<chars.at(i).descriptors().size();j++)
{
if(chars.at(i).descriptors().at(j).name()=="Client Characteristic Configuration")
{
QByteArray tmp=chars.at(i).descriptors().at(j).value();
tmp[1]=0;
tmp[0]=1;
if(chars.at(i).descriptors().at(j).value().compare(tmp)!=0)
{
connect(heart_rate_service, &QLowEnergyService::descriptorWritten,this, &TWindowsStatistique::descriptorWritten_slot);
connect(heart_rate_service, SIGNAL(error(QLowEnergyService::ServiceError)),this, SLOT(service_error_slot(QLowEnergyService::ServiceError)));
heart_rate_service->writeDescriptor(chars.at(i).descriptors().at(j),tmp);
}
}
}
}
}
}
void TWindowsStatistique::timer_1s_timeout()
{
if(heart_rate_characteristic)
{
qDebug() << "timer: data value:" << heart_rate_characteristic->getValue();//return a empty buffer : **NOK**
}
}
connect(heart_rate_characteristic, SIGNAL(characteristicChanged()), this, SLOT(heart_rate_update()));
将不起作用,因为信号 characteristicChanged
在 QLowEnergyService
服务 class 中声明,而不是在 QLowEnergyCharacteristic
特征 class 中声明, 因此您必须使用该服务将此信号连接到您的插槽。
顺便说一句,我建议您尝试 Qt 示例项目“蓝牙低功耗心率游戏”,它提供了完全符合您要求的完整代码。只需编译并 运行 它。然后,如果它在您的设备上运行良好,请将代码与您的代码进行比较,并可能使用调试器来了解为什么您的代码在该设备运行时失败。
我用 QT5.12 (MSVC 2017) 测试了 Qt 示例项目“蓝牙低功耗心率游戏”=> 我一直在等待屏幕。 我用 QT6.02 (MSVC 2019) 测试了 Qt 示例项目“蓝牙低功耗心率游戏”=> 成功了。
所以我将在 6.2 中使用 MSVC 2019 继续我的软件。
@jpo38 : 谢谢你的帮助