本次计步手环设计基于F103核心板与X-NUCLEO-IKS01A3传感器开发板。计步功能通过X-NUCLEO-IKS01A3上的LSM6DSO传感器来实现。
LSM6DSO是一款6轴传感器,包含3轴加速度与3轴陀螺仪。供电电压1.7V-3.6V,可以通过常用的SPI与I2C进行通讯。LSM6DSO带有丰富的运动检测功能,包含计步器、自由落体、唤醒、6d/4d方向、点击和双击等。
计步手环使用LSM6DSO的计步检测来实现计步功能。在正常移植X-NUCLEO-IKS01A3的驱动的程序(可参看《基于F103与X-NUCLEO-IKS01A3的计步手环之驱动移植》)上进行功能添加。
首先对之前的程序作了一些改动,让多传感器可以同时工作,并增加了一个检测LSM6DSO的INT1的中断的引脚PB7。接着就是添加计步功能。在完成对LSM6DSO的初始化之后,需要使能LSM6DSO的计步功能,并配置相应的参数及中断输出,以及清除当前步数。然后是检测步行及计算步数。
1.设置LSM6DSO的输出频率与满量程值
2.启用计步算法,设置模式。
可选模式如下:
根据选择的模式,会对一下三个寄存器进行配置,达到计步模式设置。
3.设置计步中断通过INT1输出
INT1 pin可以绑定多个功能或状态同时使用。当检测到中断后,通过读取对应的事件状态寄存器来确定事件源。
计步中断属于INT1_EMB_FUNC这个分类
使能LSM6DSO的计步功能,并配置相应的参数及中断输出
/**
* @brief Enable pedometer
* @param pObj the device pObj
* @retval 0 in case of success, an error code otherwise
*/
int32_t LSM6DSO_ACC_Enable_Pedometer(LSM6DSO_Object_t *pObj)
{
lsm6dso_pin_int1_route_t val;
/* Output Data Rate selection */
if (LSM6DSO_ACC_SetOutputDataRate(pObj, 26.0f) != LSM6DSO_OK)
{
return LSM6DSO_ERROR;
}
/* Full scale selection */
if (LSM6DSO_ACC_SetFullScale(pObj, 2) != LSM6DSO_OK)
{
return LSM6DSO_ERROR;
}
/* Enable pedometer algorithm. */
if (lsm6dso_pedo_sens_set(&(pObj->Ctx), LSM6DSO_PEDO_BASE_MODE) != LSM6DSO_OK)
{
return LSM6DSO_ERROR;
}
/* Enable step detector on INT1 pin */
if (lsm6dso_pin_int1_route_get(&(pObj->Ctx), &val) != LSM6DSO_OK)
{
return LSM6DSO_ERROR;
}
val.emb_func_int1.int1_step_detector = PROPERTY_ENABLE;
if (lsm6dso_pin_int1_route_set(&(pObj->Ctx), &val) != LSM6DSO_OK)
{
return LSM6DSO_ERROR;
}
return LSM6DSO_OK;
}
4.事件确认及处理
检测EMB_FUNC_SRC中的STEP_DETECTED标志位,为1,则表示检测到有步行行为。计步数量加1。
/**
* @brief Get the status of all hardware events
* @param pObj the device pObj
* @param Status the status of all hardware events
* @retval 0 in case of success, an error code otherwise
*/
int32_t LSM6DSO_ACC_Get_Event_Status(LSM6DSO_Object_t *pObj, LSM6DSO_Event_Status_t *Status)
{
uint8_t tilt_ia;
lsm6dso_wake_up_src_t wake_up_src;
lsm6dso_tap_src_t tap_src;
lsm6dso_d6d_src_t d6d_src;
lsm6dso_emb_func_src_t func_src;
lsm6dso_md1_cfg_t md1_cfg;
lsm6dso_md2_cfg_t md2_cfg;
lsm6dso_emb_func_int1_t int1_ctrl;
lsm6dso_emb_func_int2_t int2_ctrl;
(void)memset((void *)Status, 0x0, sizeof(LSM6DSO_Event_Status_t));
if (lsm6dso_read_reg(&(pObj->Ctx), LSM6DSO_WAKE_UP_SRC, (uint8_t *)&wake_up_src, 1) != LSM6DSO_OK)
{
return LSM6DSO_ERROR;
}
if (lsm6dso_read_reg(&(pObj->Ctx), LSM6DSO_TAP_SRC, (uint8_t *)&tap_src, 1) != LSM6DSO_OK)
{
return LSM6DSO_ERROR;
}
if (lsm6dso_read_reg(&(pObj->Ctx), LSM6DSO_D6D_SRC, (uint8_t *)&d6d_src, 1) != LSM6DSO_OK)
{
return LSM6DSO_ERROR;
}
if (lsm6dso_mem_bank_set(&(pObj->Ctx), LSM6DSO_EMBEDDED_FUNC_BANK) != LSM6DSO_OK)
{
return LSM6DSO_ERROR;
}
if (lsm6dso_read_reg(&(pObj->Ctx), LSM6DSO_EMB_FUNC_SRC, (uint8_t *)&func_src, 1) != LSM6DSO_OK)
{
return LSM6DSO_ERROR;
}
if (lsm6dso_read_reg(&(pObj->Ctx), LSM6DSO_EMB_FUNC_INT1, (uint8_t *)&int1_ctrl, 1) != LSM6DSO_OK)
{
return LSM6DSO_ERROR;
}
if (lsm6dso_read_reg(&(pObj->Ctx), LSM6DSO_EMB_FUNC_INT2, (uint8_t *)&int2_ctrl, 1) != LSM6DSO_OK)
{
return LSM6DSO_ERROR;
}
if (lsm6dso_mem_bank_set(&(pObj->Ctx), LSM6DSO_USER_BANK) != 0)
{
return LSM6DSO_ERROR;
}
if (lsm6dso_read_reg(&(pObj->Ctx), LSM6DSO_MD1_CFG, (uint8_t *)&md1_cfg, 1) != LSM6DSO_OK)
{
return LSM6DSO_ERROR;
}
if (lsm6dso_read_reg(&(pObj->Ctx), LSM6DSO_MD2_CFG, (uint8_t *)&md2_cfg, 1) != LSM6DSO_OK)
{
return LSM6DSO_ERROR;
}
if (lsm6dso_tilt_flag_data_ready_get(&(pObj->Ctx), &tilt_ia) != LSM6DSO_OK)
{
return LSM6DSO_ERROR;
}
if ((md1_cfg.int1_ff == 1U) || (md2_cfg.int2_ff == 1U))
{
if (wake_up_src.ff_ia == 1U)
{
Status->FreeFallStatus = 1;
}
}
if ((md1_cfg.int1_wu == 1U) || (md2_cfg.int2_wu == 1U))
{
if (wake_up_src.wu_ia == 1U)
{
Status->WakeUpStatus = 1;
}
}
if ((md1_cfg.int1_single_tap == 1U) || (md2_cfg.int2_single_tap == 1U))
{
if (tap_src.single_tap == 1U)
{
Status->TapStatus = 1;
}
}
if ((md1_cfg.int1_double_tap == 1U) || (md2_cfg.int2_double_tap == 1U))
{
if (tap_src.double_tap == 1U)
{
Status->DoubleTapStatus = 1;
}
}
if ((md1_cfg.int1_6d == 1U) || (md2_cfg.int2_6d == 1U))
{
if (d6d_src.d6d_ia == 1U)
{
Status->D6DOrientationStatus = 1;
}
}
if (int1_ctrl.int1_step_detector == 1U)
{
if (func_src.step_detected == 1U)
{
Status->StepStatus = 1;
}
}
if ((int1_ctrl.int1_tilt == 1U) || (int2_ctrl.int2_tilt == 1U))
{
if (tilt_ia == 1U)
{
Status->TiltStatus = 1;
}
}
return LSM6DSO_OK;
}