[原创] 虚拟架子鼓------移植Beacon到BlueMicrosystem2

littleshrimp   2017-4-19 21:09 楼主

虚拟架子鼓正常情况下应该由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.chci_le.hBlueMicrosystem2_V2.2.0对应的文件夹

 

添加宏定义OSX_BMS_LICENSE_H_FILEIAR工程

 

去掉除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_DelayElapsedCallback1

前提是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就可以将相应的数据通过广播发送给手机

剩下就是通过手机接收数据并显示,再通过判断落点触发相应的鼓声播放

 

 

 

 

虾扯蛋,蛋扯虾,虾扯蛋扯虾

回复评论 (3)

虾哥,鼓槌敲击的数据的确不需要太大的带宽。然而用不建立蓝牙连接的方式是否会产生延迟和丢失数据的情况? 在是如何来设计和处理的呢?
点赞  2017-4-20 09:07
引用: alberthink 发表于 2017-4-20 09:07
虾哥,鼓槌敲击的数据的确不需要太大的带宽。然而用不建立蓝牙连接的方式是否会产生延迟和丢失数据的情况?  ...

延时应该不会,数据丢失有可能
SensorTile每次在检测到敲击时都是在原有数据基础上+1
只要广播的数据够快,即使有数据丢失,手机在下一次收到数据后也能检测到有敲击发生
不会有太大影响
虾扯蛋,蛋扯虾,虾扯蛋扯虾
点赞  2017-4-20 09:19
虾大加油↖(^ω^)↗ 顶一下
点赞  2017-4-20 11:26
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复