BLE加速度计
BLE Accelerometer
我想通过 BLE 将加速度计值发送到使用北欧 nRF52 的 iOS 应用程序。该应用程序与标准 BLE 服务(心率测量、温度计等)完美配合,但当我尝试定义自定义 BLE 加速度计服务时却不行。在定义 UUID 和其他东西时,我需要做些什么吗?任何帮助将不胜感激,谢谢。
下面是我的自定义加速度计class,main.cpp上传到下面的nRF52。
#ifndef __BLE_ACCELEROMETER_SERVICE__
#define __BLE_ACCELEROMETER_SERVICE__
#include "ble/BLE.h"
#define UUID_ACCELEROMETER_SERVICE "00000000-0000-1000-7450-BE2E44B06B00"
#define UUID_X_CHARACTERISTIC "00000000-0000-1000-7450-BE2E44B06B01"
#define UUID_Y_CHARACTERISTIC "00000000-0000-1000-7450-BE2E44B06B02"
#define UUID_Z_CHARACTERISTIC "00000000-0000-1000-7450-BE2E44B06B03"
/**
* @class AccelerometerService
* @brief BLE Custom Accelerometer Service. This provides the x, y and z values of the SEEED 101020051 Grove accelerometer connected to the Nordic nRF52 DK.
*/
class AccelerometerService
{
public:
/**
* @brief Add the Accelerometer Service to an existing BLE object, initialize with values for x, y and z readings, represented as doubles.
* @param _ble Reference to the BLE device
* @param _x Initial value for the x axis
* @param _y Initial value for the y axis
* @param _z Initial value for the z axis
*/
AccelerometerService(BLE &_ble, double _x = 0, double _y = 0, double _z = 0) :
ble(_ble),
x(_x),
y(_y),
z(_z),
xAngleCharacteristic(UUID_X_CHARACTERISTIC, &x, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY),
yAngleCharacteristic(UUID_Y_CHARACTERISTIC, &y, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY),
zAngleCharacteristic(UUID_Z_CHARACTERISTIC, &z, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY) {
GattCharacteristic *readings[] = {&xAngleCharacteristic, &yAngleCharacteristic, &zAngleCharacteristic, };
GattService accelerometerService(UUID_ACCELEROMETER_SERVICE, readings, sizeof(readings) / sizeof(GattCharacteristic *));
ble.addService(accelerometerService);
}
/**
* @brief Update the x axis rotation with a new value.
* @param _x - New x value from accelerometer
*/
void update_x(uint8_t _x) {
x = _x;
ble.gattServer().write(xAngleCharacteristic.getValueHandle(), &x, 1);
}
/**
* @brief Update the y axis rotation with a new value.
* @param _z - New y value from accelerometer
*/
void update_y(uint8_t _y) {
y = _y;
ble.gattServer().write(yAngleCharacteristic.getValueHandle(), &y, 1);
}
/**
* @brief Update the z axis rotation with a new value.
* @param _z - New z value from accelerometer
*/
void update_z(uint8_t _z) {
z = _z;
ble.gattServer().write(zAngleCharacteristic.getValueHandle(), &z, 1);
}
protected:
/**
* A reference to the underlying BLE instance that this object is attached to.
* The services and characteristics will be registered in this BLE instance.
*/
BLE &ble;
/**
* The current x axis rotation, represented as a double
*/
uint8_t x;
/**
* The current y axis rotation, represented as a double
*/
uint8_t y;
/**
* The current z axis rotation, represented as a double
*/
uint8_t z;
/**
* A ReadOnlyGattCharacteristic that allows access to the peer device to the
* x axis rotation value through BLE.
*/
ReadOnlyGattCharacteristic<uint8_t> xAngleCharacteristic;
/**
* A ReadOnlyGattCharacteristic that allows access to the peer device to the
* y axis rotation value through BLE.
*/
ReadOnlyGattCharacteristic<uint8_t> yAngleCharacteristic;
/**
* A ReadOnlyGattCharacteristic that allows access to the peer device to the
* z axis rotation value through BLE.
*/
ReadOnlyGattCharacteristic<uint8_t> zAngleCharacteristic;
};
#endif /* __BLE_ACCELEROMETER_SERVICE__ */
下面是我通过 mbed.org 使用的 main.cpp 文件。
#include "mbed.h"
#include "ble/BLE.h"
#include "AccelerometerService.h"
DigitalOut led1(LED1);
DigitalOut led2(LED2);
static AccelerometerService *accelerometerServicePtr;
// Function declarations
void bleInitComplete(BLE::InitializationCompleteCallbackContext *);
void disconnectionCallback(const Gap::DisconnectionCallbackParams_t *);
// Set device name and inital setup options
static const char DEVICE_NAME[] = "nRF52";
static const uint16_t uuid16_list[] = {0xFFFF};
static volatile bool triggerSensorPolling = false;
static float x = 10.0; // Dummy values for accelerometer for now
static float y = 15.0;
static float z = 18.0;
/*
* Initialization callback
*/
void bleInitComplete(BLE::InitializationCompleteCallbackContext *params)
{
BLE &ble = params->ble;
ble_error_t error = params->error;
if (error != BLE_ERROR_NONE){
printf("*** Error occured ***\n");
return;
}
/* Ensure that it is the default instance of BLE */
if(ble.getInstanceID() != BLE::DEFAULT_INSTANCE) {
return;
}
ble.gap().onDisconnection(disconnectionCallback);
// Setup primary service
accelerometerServicePtr = new AccelerometerService(ble, x, y, z);
// Setup advertising
ble.gap().setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
// Advertising payload has a maximum of 31 bytes
// BLE only, no classic BT
ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED |
GapAdvertisingData::LE_GENERAL_DISCOVERABLE);
// Add name
ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)DEVICE_NAME, sizeof(DEVICE_NAME));
// UUIDs broadcast in advertising packet
ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_128BIT_SERVICE_IDS, (uint8_t *)uuid16_list, sizeof(uuid16_list));
// Set advertising interval
ble.gap().setAdvertisingInterval(100); //100ms
// Start advertising
ble.gap().startAdvertising();
}
/**
* Restart advertising on disconnection
*/
void disconnectionCallback(const Gap::DisconnectionCallbackParams_t *)
{
BLE::Instance(BLE::DEFAULT_INSTANCE).gap().startAdvertising();
}
/**
* This function is called when the ble initialization process has failed
*/
void onBleInitError(BLE &ble, ble_error_t error)
{
/* Avoid compiler warnings */
(void) ble;
(void) error;
/* Initialization error handling should go here */
}
int main()
{
// Initialize program
printf("\n\r *** Starting Main Loop *** \r\n");
BLE &ble = BLE::Instance(BLE::DEFAULT_INSTANCE);
ble.init(bleInitComplete);
while (ble.hasInitialized() == false)
{
while (true)
{
if (triggerSensorPolling && ble.gap().getState().connected) {
triggerSensorPolling = false;
accelerometerServicePtr->update_x(x);
accelerometerServicePtr->update_y(y);
accelerometerServicePtr->update_z(z);
}
else {
ble.waitForEvent(); // Infinite loop waiting for BLE interrupt events
}
}
}
}
这是错误的,您正在发送错误的广告数据包。 (0xFFFF == 在这里插入 16 位服务)
...
uuid16_list[] = {0xFFFF};
...
...
COMPLETE_LIST_128BIT_SERVICE_IDS, (uint8_t *)uuid16_list, sizeof(uuid16_list)
有为蓝牙预留的16位标识符,使用预留的UUIDspace。
查看此页面:What range of Bluetooth UUIDs can be used for vendor defined profiles?
您需要做的是在 128 位列表中指定完整的 UUID。
我不能编译这个但是试试这样的东西
char 128bitlist[] = {,0x00,0x00,0x00,0x00 ,0x00,0x00 ,0x10,0x00 ,0x74,0x50 ,0xBE,0x2E,0x44,0xB0,0x6B,0x00};
...
...
ble.gap().accumulateAdvertisingPayload (GapAdvertisingData::COMPLETE_LIST_128BIT_SERVICE_IDS, (uint8_t *) 128bitlist, 1);
用于检查广告数据的出色工具是 Lightblue。它是免费的,而且非常有用。您应该使用此工具检查 Android 和 IOS 上的广告。
另一件要检查的事情是你没有填满广告数据包。如果您的设备名称太长,加上 128 位 UUID,您可能会溢出并损坏数据包。尝试删除名称或使其非常短。
有两点需要考虑。
首先,
要与具有自定义服务及其特性的 BLE 设备进行通信,您需要在中央端(例如移动端)匹配一个应用程序。因为标准应用程序将始终只查找预期的标准配置文件。
其次,
为了在您的设备固件中实施自定义配置文件,Nordic 为其 UART (NUS) 配置文件提供了一个示例。您可以将该示例用作参考,并根据需要进行更改,例如服务和特征的 UUID。
我想通过 BLE 将加速度计值发送到使用北欧 nRF52 的 iOS 应用程序。该应用程序与标准 BLE 服务(心率测量、温度计等)完美配合,但当我尝试定义自定义 BLE 加速度计服务时却不行。在定义 UUID 和其他东西时,我需要做些什么吗?任何帮助将不胜感激,谢谢。
下面是我的自定义加速度计class,main.cpp上传到下面的nRF52。
#ifndef __BLE_ACCELEROMETER_SERVICE__
#define __BLE_ACCELEROMETER_SERVICE__
#include "ble/BLE.h"
#define UUID_ACCELEROMETER_SERVICE "00000000-0000-1000-7450-BE2E44B06B00"
#define UUID_X_CHARACTERISTIC "00000000-0000-1000-7450-BE2E44B06B01"
#define UUID_Y_CHARACTERISTIC "00000000-0000-1000-7450-BE2E44B06B02"
#define UUID_Z_CHARACTERISTIC "00000000-0000-1000-7450-BE2E44B06B03"
/**
* @class AccelerometerService
* @brief BLE Custom Accelerometer Service. This provides the x, y and z values of the SEEED 101020051 Grove accelerometer connected to the Nordic nRF52 DK.
*/
class AccelerometerService
{
public:
/**
* @brief Add the Accelerometer Service to an existing BLE object, initialize with values for x, y and z readings, represented as doubles.
* @param _ble Reference to the BLE device
* @param _x Initial value for the x axis
* @param _y Initial value for the y axis
* @param _z Initial value for the z axis
*/
AccelerometerService(BLE &_ble, double _x = 0, double _y = 0, double _z = 0) :
ble(_ble),
x(_x),
y(_y),
z(_z),
xAngleCharacteristic(UUID_X_CHARACTERISTIC, &x, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY),
yAngleCharacteristic(UUID_Y_CHARACTERISTIC, &y, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY),
zAngleCharacteristic(UUID_Z_CHARACTERISTIC, &z, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY) {
GattCharacteristic *readings[] = {&xAngleCharacteristic, &yAngleCharacteristic, &zAngleCharacteristic, };
GattService accelerometerService(UUID_ACCELEROMETER_SERVICE, readings, sizeof(readings) / sizeof(GattCharacteristic *));
ble.addService(accelerometerService);
}
/**
* @brief Update the x axis rotation with a new value.
* @param _x - New x value from accelerometer
*/
void update_x(uint8_t _x) {
x = _x;
ble.gattServer().write(xAngleCharacteristic.getValueHandle(), &x, 1);
}
/**
* @brief Update the y axis rotation with a new value.
* @param _z - New y value from accelerometer
*/
void update_y(uint8_t _y) {
y = _y;
ble.gattServer().write(yAngleCharacteristic.getValueHandle(), &y, 1);
}
/**
* @brief Update the z axis rotation with a new value.
* @param _z - New z value from accelerometer
*/
void update_z(uint8_t _z) {
z = _z;
ble.gattServer().write(zAngleCharacteristic.getValueHandle(), &z, 1);
}
protected:
/**
* A reference to the underlying BLE instance that this object is attached to.
* The services and characteristics will be registered in this BLE instance.
*/
BLE &ble;
/**
* The current x axis rotation, represented as a double
*/
uint8_t x;
/**
* The current y axis rotation, represented as a double
*/
uint8_t y;
/**
* The current z axis rotation, represented as a double
*/
uint8_t z;
/**
* A ReadOnlyGattCharacteristic that allows access to the peer device to the
* x axis rotation value through BLE.
*/
ReadOnlyGattCharacteristic<uint8_t> xAngleCharacteristic;
/**
* A ReadOnlyGattCharacteristic that allows access to the peer device to the
* y axis rotation value through BLE.
*/
ReadOnlyGattCharacteristic<uint8_t> yAngleCharacteristic;
/**
* A ReadOnlyGattCharacteristic that allows access to the peer device to the
* z axis rotation value through BLE.
*/
ReadOnlyGattCharacteristic<uint8_t> zAngleCharacteristic;
};
#endif /* __BLE_ACCELEROMETER_SERVICE__ */
下面是我通过 mbed.org 使用的 main.cpp 文件。
#include "mbed.h"
#include "ble/BLE.h"
#include "AccelerometerService.h"
DigitalOut led1(LED1);
DigitalOut led2(LED2);
static AccelerometerService *accelerometerServicePtr;
// Function declarations
void bleInitComplete(BLE::InitializationCompleteCallbackContext *);
void disconnectionCallback(const Gap::DisconnectionCallbackParams_t *);
// Set device name and inital setup options
static const char DEVICE_NAME[] = "nRF52";
static const uint16_t uuid16_list[] = {0xFFFF};
static volatile bool triggerSensorPolling = false;
static float x = 10.0; // Dummy values for accelerometer for now
static float y = 15.0;
static float z = 18.0;
/*
* Initialization callback
*/
void bleInitComplete(BLE::InitializationCompleteCallbackContext *params)
{
BLE &ble = params->ble;
ble_error_t error = params->error;
if (error != BLE_ERROR_NONE){
printf("*** Error occured ***\n");
return;
}
/* Ensure that it is the default instance of BLE */
if(ble.getInstanceID() != BLE::DEFAULT_INSTANCE) {
return;
}
ble.gap().onDisconnection(disconnectionCallback);
// Setup primary service
accelerometerServicePtr = new AccelerometerService(ble, x, y, z);
// Setup advertising
ble.gap().setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
// Advertising payload has a maximum of 31 bytes
// BLE only, no classic BT
ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED |
GapAdvertisingData::LE_GENERAL_DISCOVERABLE);
// Add name
ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)DEVICE_NAME, sizeof(DEVICE_NAME));
// UUIDs broadcast in advertising packet
ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_128BIT_SERVICE_IDS, (uint8_t *)uuid16_list, sizeof(uuid16_list));
// Set advertising interval
ble.gap().setAdvertisingInterval(100); //100ms
// Start advertising
ble.gap().startAdvertising();
}
/**
* Restart advertising on disconnection
*/
void disconnectionCallback(const Gap::DisconnectionCallbackParams_t *)
{
BLE::Instance(BLE::DEFAULT_INSTANCE).gap().startAdvertising();
}
/**
* This function is called when the ble initialization process has failed
*/
void onBleInitError(BLE &ble, ble_error_t error)
{
/* Avoid compiler warnings */
(void) ble;
(void) error;
/* Initialization error handling should go here */
}
int main()
{
// Initialize program
printf("\n\r *** Starting Main Loop *** \r\n");
BLE &ble = BLE::Instance(BLE::DEFAULT_INSTANCE);
ble.init(bleInitComplete);
while (ble.hasInitialized() == false)
{
while (true)
{
if (triggerSensorPolling && ble.gap().getState().connected) {
triggerSensorPolling = false;
accelerometerServicePtr->update_x(x);
accelerometerServicePtr->update_y(y);
accelerometerServicePtr->update_z(z);
}
else {
ble.waitForEvent(); // Infinite loop waiting for BLE interrupt events
}
}
}
}
这是错误的,您正在发送错误的广告数据包。 (0xFFFF == 在这里插入 16 位服务)
...
uuid16_list[] = {0xFFFF};
...
...
COMPLETE_LIST_128BIT_SERVICE_IDS, (uint8_t *)uuid16_list, sizeof(uuid16_list)
有为蓝牙预留的16位标识符,使用预留的UUIDspace。
查看此页面:What range of Bluetooth UUIDs can be used for vendor defined profiles?
您需要做的是在 128 位列表中指定完整的 UUID。
我不能编译这个但是试试这样的东西
char 128bitlist[] = {,0x00,0x00,0x00,0x00 ,0x00,0x00 ,0x10,0x00 ,0x74,0x50 ,0xBE,0x2E,0x44,0xB0,0x6B,0x00};
...
...
ble.gap().accumulateAdvertisingPayload (GapAdvertisingData::COMPLETE_LIST_128BIT_SERVICE_IDS, (uint8_t *) 128bitlist, 1);
用于检查广告数据的出色工具是 Lightblue。它是免费的,而且非常有用。您应该使用此工具检查 Android 和 IOS 上的广告。
另一件要检查的事情是你没有填满广告数据包。如果您的设备名称太长,加上 128 位 UUID,您可能会溢出并损坏数据包。尝试删除名称或使其非常短。
有两点需要考虑。
首先, 要与具有自定义服务及其特性的 BLE 设备进行通信,您需要在中央端(例如移动端)匹配一个应用程序。因为标准应用程序将始终只查找预期的标准配置文件。
其次, 为了在您的设备固件中实施自定义配置文件,Nordic 为其 UART (NUS) 配置文件提供了一个示例。您可以将该示例用作参考,并根据需要进行更改,例如服务和特征的 UUID。