【问题标题】:get heart frequency frome a BLE sensor从 BLE 传感器获取心脏频率
【发布时间】:2021-08-15 16:03:55
【问题描述】:

我尝试在需要心脏频率的 Qt creator(C++) 上开发一个 windows 10 软件。我买了下面的传感器,通过蓝牙传输数据(BLE:蓝牙低能量):

https://www.decathlon.fr/p/ceinture-cardiofrequencemetre-course-a-pied-dual-ant-bluetooth-smart/_/R-p-128085

但是当我尝试读取值时,我有一个空缓冲区。

传感器在安卓应用程序上正常工作(在 Play 商店中)

我的代码:

初始化:确定

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();
}

获取蓝牙设备列表:OK

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();
    }
}

获取特征列表:OK 有心率数据: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**
    }
}

【问题讨论】:

  • 新:我测试了其他数据并且可以读取它们。与心率的区别在于它的类型是“通知”而不是“读取”。我看到 BLE 通知出现问题:[forum.qt.io/topic/122098/…我尝试在 .pro 中使用 exe 路径的“BLUETOOTH_FORCE_DBUS_LE_VERSION=5.41 /path”,但它什么也没做。
  • “测试将通知标志置为 1:心率数据保持为空”是什么意思?将 CCCD 设置为 1 后,考虑到您的代码,只要通知新的 HRM 值,就应该执行 heart_rate_update()。不是这样吗?

标签: c++ qt bluetooth-lowenergy heartrate


【解决方案1】:

connect(heart_rate_characteristic, SIGNAL(characteristicChanged()), this, SLOT(heart_rate_update())); 将不起作用,因为信号 characteristicChanged 是在 QLowEnergyService 服务类中声明的,而不是在 QLowEnergyCharacteristic 特征类中声明的,因此您必须使用该服务将此信号连接到您的插槽。

顺便说一句,我建议您尝试 Qt 示例项目“蓝牙低能量心率游戏”,它提供了完全符合您要求的完整代码。只需编译并运行它。然后,如果它在您的设备上运行良好,请将代码与您的进行比较,并可能使用调试器来了解为什么您的代码在这个工作时会失败。

【讨论】:

  • 如代码中所说:插槽“heart_rate_update()”永远不会被调用,即使 CCCD 为 1。
  • 我尝试了“蓝牙低能量心率游戏”,我无法直接编译它,因为我使用 MSVC 2017 5.12.11 并且该项目是在 6.2 中开发的。在回归修改后完成(信号(错误发生)->信号(错误)//重命名QLowEnergyService::ServiceState标志)函数停留在第一个屏幕(等待屏幕)。我会尝试下载 MSVC 2019
  • 查看我编辑的答案,在建立从characteristicChanged 信号到您的插槽的连接时,您没有使用好对象。
【解决方案2】:

我使用 QT5.12 (MSVC 2017) 测试了 Qt 示例项目“蓝牙低能量心率游戏”=> 我一直在等待屏幕。 我用 QT6.02 (MSVC 2019) 测试了 Qt 示例项目“蓝牙低能量心率游戏” => 它的工作。

所以我将在 6.2 中使用 MSVC 2019 继续我的软件。

@jpo38 : 谢谢你的帮助

【讨论】:

  • 那么你应该在我的回答中加入评论并接受它。
猜你喜欢
  • 2016-02-03
  • 2021-10-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-11-28
相关资源
最近更新 更多