虚拟架子鼓正常情况下应该由2个鼓棒组成
为了方便我使用SensorTile通过BLE的广播方式把传感器数据发送到手机
这样一个手机就可以收到多个SensorTile的数据,无需建立连接
BlueMicrosystem2_V2.2.0例程已经实现了蓝牙和传感器整合功能
现在需要对其做些改动,让它实现广播数据的功能
STM32CubeExpansion_BLE1_V2.8.0库中包括一个Beacon例程,现在需要把里边的几个函数移植到BlueMicrosystem2_V2.2.0里
就可以让BlueMicrosystem2_V2.2.0实现数据广播功能
添加STM32CubeExpansion_BLE1_V2.8.0\Middlewares\ST\STM32_BlueNRG\SimpleBlueNRG_HCI\includes
和STM32CubeExpansion_BLE1_V2.8.0\Middlewares\ST\STM32_BlueNRG\SimpleBlueNRG_HCI\hci
中的hci_le.c和hci_le.h到BlueMicrosystem2_V2.2.0对应的文件夹
添加宏定义OSX_BMS_LICENSE_H_FILE到IAR工程
去掉除OSX_MOTION_FX以外的License_init代码
不然会提示其它初始化失败,因为头文件中定修改了osx_mfx_license
添加下边宏定义到main.c
#define MAC_ADDRESS 0x12, 0x34, 0x00, 0xE1, 0x80, 0x03 #define ADVERTISING_INTERVAL_INCREMENT (16) |
添加Beacon初始化代码到main.c
/* Initialize the BlueNRG SPI driver */ BNRG_SPI_Init();
/* Initialize the BlueNRG HCI */ HCI_Init();
/* Reset BlueNRG hardware */ BlueNRG_RST();
BlueNRG_Init();
Beacon_Init(); |
添加Beacon函数到main.c
/** * @brief Initialize the BlueNRG * * @param None * @retval None */ void BlueNRG_Init(void) { tBleStatus ret = BLE_STATUS_SUCCESS;
uint16_t service_handle, dev_name_char_handle, appearance_char_handle; uint8_t SERVER_BDADDR[] = { MAC_ADDRESS };
uint8_t hwVersion; uint16_t fwVersion; uint8_t bnrg_expansion_board = IDB04A1; /* at startup, suppose the X-NUCLEO-IDB04A1 is used */
/* get the BlueNRG HW and FW versions */ getBlueNRGVersion(&hwVersion, &fwVersion);
if (hwVersion > 0x30) { /* X-NUCLEO-IDB05A1 expansion board is used */ bnrg_expansion_board = IDB05A1; }
ret = aci_hal_write_config_data(CONFIG_DATA_PUBADDR_OFFSET, CONFIG_DATA_PUBADDR_LEN, SERVER_BDADDR);
if (ret != BLE_STATUS_SUCCESS) { __asm("nop"); }
ret = aci_gatt_init();
if (ret != BLE_STATUS_SUCCESS) { __asm("nop"); }
if (bnrg_expansion_board == IDB05A1) { ret = aci_gap_init_IDB05A1(GAP_PERIPHERAL_ROLE_IDB05A1, 0, 0x07, &service_handle, &dev_name_char_handle, &appearance_char_handle); } else { ret = aci_gap_init_IDB04A1(GAP_PERIPHERAL_ROLE_IDB04A1, &service_handle, &dev_name_char_handle, &appearance_char_handle); }
if (ret != BLE_STATUS_SUCCESS) { __asm("nop"); }
ret = aci_hal_set_tx_power_level(1,4);
if (ret != BLE_STATUS_SUCCESS) { __asm("nop"); }
}
tBleStatus Beacon_Init(void) { tBleStatus ret = BLE_STATUS_SUCCESS;
/* Disable scan response. */ hci_le_set_scan_resp_data(0, NULL);
uint16_t AdvertisingInterval = (10 * ADVERTISING_INTERVAL_INCREMENT / 10);
/* Put the device in a non-connectable mode. */ ret = aci_gap_set_discoverable(ADV_NONCONN_IND, /*< Advertise as non-connectable, undirected. */ AdvertisingInterval, AdvertisingInterval, /*< Set the advertising interval as 700 ms (0.625 us increment). */ PUBLIC_ADDR, NO_WHITE_LIST_USE, /*< Use the public address, with no white list. */ 0, NULL, /*< Do not use a local name. */ 0, NULL, /*< Do not include the service UUID list. */ 0, 0); /*< Do not set a slave connection interval. */
if (ret != BLE_STATUS_SUCCESS) { return ret; }
/* Remove the TX power level advertisement (this is done to decrease the packet size). */ ret = aci_gap_delete_ad_type(AD_TYPE_TX_POWER_LEVEL);
if (ret != BLE_STATUS_SUCCESS) { return ret; }
uint8_t service_data[] = { 23, /*< Length. */ AD_TYPE_SERVICE_DATA, /*< Service Data data type value. */ 0x00, /*< Reserved. */ 0x00, /*< Reserved. */ 0x00, /*< Reserved. */ 0x00, /*< Reserved. */ 0x00, /*< Reserved. */ 0x00, /*< Reserved. */ 0x00, /*< Reserved. */ 0x00, /*< Reserved. */ 0x00, /*< Reserved. */ 0x00, /*< Reserved. */ 0x00, /*< Reserved. */ 0x00, /*< Reserved. */ 0x00, /*< Reserved. */ 0x00, /*< Reserved. */ 0x00, /*< Reserved. */ 0x00, /*< Reserved. */ 0x00, /*< Reserved. */ 0x00, /*< Reserved. */ 0x00, /*< Reserved. */ 0x00, /*< Reserved. */ 0x00, /*< Reserved. */ 0x00 /*< Reserved. */ };
uint8_t service_uuid_list[] = { 3, /*< Length. */ AD_TYPE_16_BIT_SERV_UUID_CMPLT_LIST, /*< Complete list of 16-bit Service UUIDs data type value. */ 0xAA, 0xFE /*< 16-bit Eddystone UUID. */ };
uint8_t flags[] = { 2, /*< Length. */ AD_TYPE_FLAGS, /*< Flags data type value. */ (FLAG_BIT_LE_GENERAL_DISCOVERABLE_MODE | FLAG_BIT_BR_EDR_NOT_SUPPORTED) /*< BLE general discoverable, without BR/EDR support. */ };
/* Update the service data. */ ret = aci_gap_update_adv_data(sizeof(service_data), service_data);
if (ret != BLE_STATUS_SUCCESS) { return ret; }
/* Update the service UUID list. */ ret = aci_gap_update_adv_data(sizeof(service_uuid_list), service_uuid_list);
if (ret != BLE_STATUS_SUCCESS) { return ret; }
/* Update the adverstising flags. */ ret = aci_gap_update_adv_data(sizeof(flags), flags);
if (ret != BLE_STATUS_SUCCESS) { return ret; }
return ret; }
tBleStatus UpdateAdv(uint8_t * buff,uint8_t len) { tBleStatus ret = BLE_STATUS_SUCCESS; uint8_t service_data[] = { 23, /*< Length. */ AD_TYPE_SERVICE_DATA, /*< Service Data data type value. */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; memcpy(&service_data[2],buff,len); memset(&service_data[2+len],0,22-len); /* Update the service data. */ ret = aci_gap_update_adv_data(sizeof(service_data), service_data);
if (ret != BLE_STATUS_SUCCESS) { return ret; } return ret; } |
现在BlueMicrosystem2_V2.2.0已经可以广播想要的数据,接下来是修改整合算法,让它不需要手机连接就能发送数据
BlueMicrosystem2_V2.2.0例程里处理整合算法的函数是在main.c中的ComputeQuaternions里
ComputeQuaternions包含了9轴传感器的读取(加速度、脱落仪、磁场)和MotionFX融合数据计算和通过蓝牙发送
ComputeQuaternions函数是在主函数中调用的
通过判断Quaternion标志
/* osxMotionFX */ if(Quaternion) { Quaternion=0; ComputeQuaternions(); }
|
Quaternion标志是通过时器中断HAL_TIM_OC_DelayElapsedCallback置1
前提是SensorTile已经与手机中的BlueMS连接,并且BlueMS切换到对应的界面
if (W2ST_CHECK_CONNECTION(W2ST_CONNECT_QUAT)) { Quaternion=1; } |
如果要改成广播方式就不需要对是否与连接进行判断
可以把ComputeQuaternions函数的调用直接放在HAL_TIM_OC_DelayElapsedCallback定时器中断函数中
void HAL_TIM_OC_DelayElapsedCallback(TIM_HandleTypeDef *htim) { uint32_t uhCapture=0; /* Code for MotionFX and MotionGR integration - Start Section */ /* TIM1_CH1 toggling with frequency = 100Hz */ if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1) { uhCapture = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1); /* Set the Capture Compare Register value */ __HAL_TIM_SET_COMPARE(&TimCCHandle, TIM_CHANNEL_1, (uhCapture + DEFAULT_uhCCR1_Val));
ComputeQuaternions(); } } |
在ComputeQuaternions函数中把原来的通过蓝牙连接方式发送判断改为通过广播方式
再把要发送的数据改为与鼓棒相关的
int32_t y = ((int32_t)(MotionFX_Engine_Out->rotation_9X[2] * 100)); int32_t z = ((int32_t)(MotionFX_Engine_Out->rotation_9X[0] * 100)); STORE_LE_16(buff+0,drumCount); STORE_LE_16(buff+2,y); STORE_LE_16(buff+4,z); UpdateAdv(buff,6); drumCount += PeakCounter(((int32_t)(MotionFX_Engine_Out->rotation_9X[2] * 100)),100,6,250);
|
其中rotation_9X[0] 和rotation_9X[2] Android用来识别鼓棒的落点,并通过3D动画方式显示2根鼓棒
drumCount是通过落棒检测函数PeakCounter判断鼓棒是否落下
每次加1
由SensorTile实现是为了实时性更好,毕竟SensorTile通过蓝牙和手机通信的速率有限
通过上面的操作SensorTile就可以将相应的数据通过广播发送给手机
剩下就是通过手机接收数据并显示,再通过判断落点触发相应的鼓声播放
引用: alberthink 发表于 2017-4-20 09:07
虾哥,鼓槌敲击的数据的确不需要太大的带宽。然而用不建立蓝牙连接的方式是否会产生延迟和丢失数据的情况? ...