本文将介绍如何通过中断机制获取LSM6DSV16X传感器的SFLP(Sensor Fusion Low Power)四元数数据。 LSM6DSV16X 是一款高性能6 轴惯性传感器,支持传感器低功耗融合(SFLP) 功能。 SFLP 功能允许在低功耗模式下实时融合加速度计和陀螺仪数据,以生成设备姿态的四元数表示。
为了优化系统功耗,我们将配置中断引脚,使其在四元数数据更新时触发中断。这样可以避免频繁轮询传感器数据,从而降低功耗,特别适合需要实时手势检测但对功耗敏感的场景,例如可穿戴设备和手势识别系统。
我目前正在学习ST 和Renesas RA 课程。如果需要样品,可以进群申请:615061293。
[https://www.bilibili.com/video/BV1kg54zaEc4/]
[https://www.wjx.top/vm/OhcKxJk.aspx#]
[https://download.csdn.net/download/qq_24312945/91359794]
首先需要准备一块开发板。我这里准备的是自己画的开发板。如果您需要的话,可以申请。
主控为STM32H503CB,陀螺仪为LSM6DSV16X,磁力计为LIS2MDL。
[https://github.com/CoreMaker-lab/STM32H503_LSM6DSV16X_LIS2MDL]
[https://gitee.com/CoreMaker/STM32H503_LSM6DSV16X_LIS2MDL]
LSM6DSV16X 的功能涉及低功耗传感器融合算法(Sensor Fusion Low Power,SFLP)。
传感器低功耗融合(SFLP) 算法:
该算法旨在以节能的方式组合来自加速度计和陀螺仪的数据。传感器融合算法通过结合不同传感器的优点,提供更准确、更可靠的数据。
6轴游戏旋转矢量:
SFLP算法能够生成游戏旋转向量。该矢量是设备在空间中的方向的数据表示,对于理解设备的方向和运动至关重要的游戏和增强现实应用特别有用。
四元数表示:
旋转向量表示为四元数。四元数是一种编码3D 旋转的方法,可以避免其他表示形式的一些限制,例如欧拉角(如万向节锁定)。四元数有四个分量(X、Y、Z 和W),其中X、Y、Z 表示矢量部分,W 表示标量部分。
先进先出存储:
四元数的X、Y、Z 分量存储在LSM6DSV16X 的FIFO(先进先出)缓冲区中。 FIFO 缓冲区是一种允许临时存储传感器数据的数据存储方法。这对于有效管理数据流非常有用,特别是在数据处理可能不如数据收集快的系统中。
该图像包含LSM6DSV16X 传感器的传感器融合低功耗(SFLP) 功能的描述。下面是图片内容的解释: SFLP特征:
SFLP单元用于基于加速度计和陀螺仪数据处理生成以下数据: 游戏旋转矢量:以四元数形式表示设备的姿态。重力矢量:提供表示重力方向的三维矢量。陀螺仪偏差:提供表示陀螺仪偏差的三维矢量。激活和复位:通过将EMB_FUNC_EN_A (04h) 嵌入功能寄存器中的SFLP_GAME_EN 位设置为1 来激活SFLP 单元。通过将EMB_FUNC_INIT_A (66h) 嵌入式功能寄存器中的SFLP_GAME_INIT 位设置为1 来重置SFLP 单元。性能参数表:该表显示了SFLP功能在不同条件下的性能,包括静态精度、低动态精度和高动态精度,以及校准时间和方向稳定时间。这些参数反映了传感器在不同运动状态下的精度和响应速度。
陀螺仪LSM6DSV16X的中断引脚连接到PB0,PB0需要设置为中间端口。
打开中断。
INT1_CTRL(0Dh)是LSM6DSV16X传感器的中断控制寄存器,用于配置和使能INT1引脚的各种中断信号。该寄存器的每一位对应不同的中断源,通过设置这些位可以使能或禁止相应的中断信号。
INT1_FIFO_TH(位3):
使能FIFO 阈值中断并将其路由至INT1 引脚。当FIFO 达到设定阈值时,会触发该中断。默认值为0(禁用)。
变量在main.c 中定义。
/* USER CODE BEGIN 0 */uint8_t fifo_flag=0;/* USER CODE END 0 */在mian.c 中启用中断。
lsm6dsv16x_pin_int_route_t pin_int; pin_int.fifo_th=PROPERTY_ENABLE; lsm6dsv16x_pin_int1_route_set(dev_ctx, pin_int);在stm32h5xx_it.c中添加回调函数引用。
/* USER CODE BEGIN 0 */extern void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin);/* USER CODE END 0 */处理PB0外部中断线0(EXTI Line0)的中断。
/** * @brief 该函数处理EXTI Line0 中断。 */void EXTI0_IRQHandler(void){ /* 用户代码开始EXTI0_IRQn 0 */HAL_GPIO_EXTI_Callback(GPIO_PIN_0); /* 用户代码结束EXTI0_IRQn 0 */HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0); /* USER CODE BEGIN EXTI0_IRQn 1 *//* USER CODE END EXTI0_IRQn 1 */}在main.c中添加回调函数的定义,并检查中断是否由GPIO_PIN_0引脚触发。
/* 用户代码开始4 */void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin){ if(GPIO_Pin==GPIO_PIN_0) { fifo_flag=1; } }/* 用户代码结束4 */
/* 无限循环*//* 用户代码开始WHILE */while (1) { if(fifo_flag==1) { fifo_flag=0; uint16_t 数=0; /* 读取水印标志*/lsm6dsv16x_fifo_status_get(dev_ctx, fifo_status); if (fifo_status.fifo_th==1) { num=fifo_status.fifo_level; printf('-- FIFO num %d rn', num); while (num--) { lsm6dsv16x_fifo_out_raw_t f_data; uint8_t *轴; float_t quat[4]; float_t重力_mg[3]; float_t gbias_mdps[3]; /* 读取FIFO 传感器值*/lsm6dsv16x_fifo_out_raw_get(dev_ctx, f_data); switch (f_data.tag) { case LSM6DSV16X_SFLP_GYROSCOPE_BIAS_TAG://axis=f_data.data[0];//gbias_mdps[0]=lsm6dsv16x_from_fs125_to_mdps(axis[0] | (axis[1] 8));//gbias_mdps[1]=lsm6dsv16x_from_fs125_to_mdps(axis[2] | (axis[3] 8));//gbias_mdps[2]=lsm6dsv16x_from_fs125_to_mdps(axis[4] | (axis[5] 8));//printf('GBIAS [mdps]:%4.2ft%4.2ft%4.2frn',//(double_t)gbias_mdps[0], (double_t)gbias_mdps[1], (double_t)gbias_mdps[2]);休息; case LSM6DSV16X_SFLP_GRAVITY_VECTOR_TAG://axis=f_data.data[0];//gravity_mg[0]=lsm6dsv16x_from_sflp_to_mg(axis[0] | (axis[1] 8));//gravity_mg[1]=lsm6dsv16x_from_sflp_to_mg(axis[2] | (axis[3] 8));//gravity_mg[2]=lsm6dsv16x_from_sflp_to_mg(axis[4] | (axis[5] 8));//printf('重力[mg]:%4.2ft%4.2ft%4.2frn',//(double_t)gravity_mg[0], (double_t)gravity_mg[1], (double_t)gravity_mg[2]);休息; case LSM6DSV16X_SFLP_GAME_ROTATION_VECTOR_TAG: sflp2q(quat, (uint16_t *)f_data.data[0]);//printf('游戏旋转tX: %2.3ftY: %2.3ftZ: %2.3ftW: %2.3frn',//(double_t)quat[0], (double_t)quat[1], (double_t)quat[2], (double_t)quat[3]);浮点数sx=quat[1];浮点数sy=quat[2];浮动sz=quat[0];浮动sw=quat[3]; if (sw 0.0f) { sx*=-1.0f;西* 西;浮点数sqz=sz * sz;浮点欧拉[3]; euler[0]=-atan2f(2.0f* (sy*sw+sx*sz), 1.0f-2.0f*(sqy+sqx)); euler[1]=-atan2f(2.0f * (sx*sy+sz*sw),1.0f-2.0f*(sqx+sqz));欧拉[2]=-asinf(2.0f* (sx*sw-sy*sz)); if (euler[0] 0.0f) euler[0] +=2.0f*3.1415926; for(uint8_t i=0; i 3; i++){ euler[i]=57.29578 * (euler[i]); printf('欧拉[0]=%f,欧拉[1]=%f,欧拉[2]=%fn',欧拉[0],欧拉[1],欧拉[2]);休息;默认:中断; } } printf('------rnrn'); } } /* USER CODE END WHILE *//* USER CODE BEGIN 3 */} /* USER CODE END 3 */需要注意优化级别。