陀螺仪LSM6DSV80X开发.6--单双击检测
- 概述
- 视频教学
- 样品申请
- 源码下载
- 硬件准备
- 参考程序
- 生成STM32CUBEMX
- 串口配置
- IIC配置
- CS和SA0设置
- INT配置
- ICASHE
- 修改堆栈
- 串口重定向
- 参考程序
- 变量定义
- 初始换管脚
- 获取ID
- 软件上电复位
- BDU设置
- [Tap 中断配置说明](#Tap 中断配置说明)
- 使能中断输出
- [使能 Z 轴 Tap 检测](#使能 Z 轴 Tap 检测)
- [配置 Tap 阈值](#配置 Tap 阈值)
- [配置 Tap 时间窗口](#配置 Tap 时间窗口)
- [配置 Single Tap / Double Tap 检测模式](#配置 Single Tap / Double Tap 检测模式)
- 设置量程和速率
- 外部中断回调函数
- 主程序
- 演示
概述
本实验主要演示如何使用 LSM6DSV80X 的 Tap Detection 功能,实现对单击和双击动作的识别。通过配置传感器的 Tap 检测轴、敲击阈值、时间窗口以及中断输出,将 Single Tap 和 Double Tap 事件映射到 INT1 引脚。当检测到敲击动作后,MCU 通过外部中断唤醒主循环,并读取 LSM6DSV80X 的事件源寄存器,判断当前触发的是单击还是双击事件,最后通过串口打印检测结果。
需要样片的可以加群申请:925643491/615061293 。

视频教学
https://www.bilibili.com/video/BV1tYGJ6vEHK/
样品申请
https://www.wjx.top/vm/OhcKxJk.aspx#
源码下载
硬件准备
首先需要准备一个开发板,这里我准备的是自己绘制的开发板,需要的可以进行申请。
主控为STM32H503CB,陀螺仪为LSM6DSV80X,磁力计为LIS2MDL。

参考程序
https://github.com/CoreMaker-lab/LSM6DSV80X
https://gitee.com/CoreMaker/LSM6DSV80X
生成STM32CUBEMX
用STM32CUBEMX生成例程,这里使用MCU为STM32H503CB。
配置时钟树,配置时钟为250M。

串口配置
查看原理图,PA9和PA10设置为开发板的串口。

配置串口,速率为2000000。

IIC配置


LSM6DSV80X最大IIC通讯速率为1M,配置IIC速度为400k

CS和SA0设置



由于还有一个磁力计,需要把该CS也使能。



INT配置
INT1管脚为PB0。


配置如下所示。

开启中断。

ICASHE

修改堆栈

串口重定向
打开魔术棒,勾选MicroLIB

在main.c中,添加头文件,若不添加会出现 identifier "FILE" is undefined报错。
c
/* USER CODE BEGIN Includes */
#include "stdio.h"
/* USER CODE END Includes */
函数声明和串口重定向:
c
/* USER CODE BEGIN PFP */
int fputc(int ch, FILE *f){
HAL_UART_Transmit(&huart1 , (uint8_t *)&ch, 1, 0xFFFF);
return ch;
}
/* USER CODE END PFP */
参考程序
https://github.com/STMicroelectronics/lsm6dsv80x-pid
变量定义
c
/* USER CODE BEGIN 0 */
#define SENSOR_BUS hi2c1
/* Private macro -------------------------------------------------------------*/
#define BOOT_TIME 10 //ms
#define CNT_FOR_OUTPUT 100
/* Private variables ---------------------------------------------------------*/
static int16_t data_raw_motion[3];
static int16_t data_raw_temperature;
static float_t acceleration_mg[3];
static float_t angular_rate_mdps[3];
static float_t temperature_degC;
static uint8_t whoamI;
static uint8_t tx_buffer[1000];
static lsm6dsv80x_filt_settling_mask_t filt_settling_mask;
/* Extern variables ----------------------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
/*
* WARNING:
* Functions declare in this section are defined at the end of this file
* and are strictly related to the hardware platform used.
*
*/
static int32_t platform_write(void *handle, uint8_t reg, const uint8_t *bufp,
uint16_t len);
static int32_t platform_read(void *handle, uint8_t reg, uint8_t *bufp,
uint16_t len);
static void tx_com( uint8_t *tx_buffer, uint16_t len );
static void platform_delay(uint32_t ms);
static void platform_init(void);
static stmdev_ctx_t dev_ctx;
static volatile uint8_t stap_event_catched = 0;
static volatile uint8_t dtap_event_catched = 0;
static uint8_t thread_wake = 0;
static lsm6dsv80x_interrupt_mode_t irq;
static lsm6dsv80x_tap_detection_t tap;
static lsm6dsv80x_tap_thresholds_t tap_ths;
static lsm6dsv80x_tap_time_windows_t tap_win;
/* USER CODE END 0 */
初始换管脚
由于需要向LSM6DSV80X_I2C_ADD_L写入以及为IIC模式。

所以使能CS为高电平,配置为IIC模式。
配置SA0为低电平。
c
printf("HELLO!\n");
HAL_GPIO_WritePin(CS1_GPIO_Port, CS1_Pin, GPIO_PIN_SET);
HAL_GPIO_WritePin(SA0_GPIO_Port, SA0_Pin, GPIO_PIN_RESET);
HAL_GPIO_WritePin(CS2_GPIO_Port, CS2_Pin, GPIO_PIN_SET);
HAL_Delay(100);
lsm6dsv80x_pin_int_route_t pin_int = { 0 };
/* Initialize mems driver interface */
dev_ctx.write_reg = platform_write;
dev_ctx.read_reg = platform_read;
dev_ctx.mdelay = platform_delay;
dev_ctx.handle = &SENSOR_BUS;
/* Init test platform */
// platform_init();
/* Wait sensor boot time */
platform_delay(BOOT_TIME);
获取ID
可以向WHO_AM_I (0Fh)获取固定值,判断是否为0x73。

lsm6dsv80x_device_id_get为获取函数。

对应的获取ID驱动程序,如下所示。
c
/* Check device ID */
lsm6dsv80x_device_id_get(&dev_ctx, &whoamI);
printf("LSM6DSV80X_ID=0x%x,whoamI=0x%x",LSM6DSV80X_ID,whoamI);
if (whoamI != LSM6DSV80X_ID)
while (1);
软件上电复位
写 0x01(FUNC_CFG_ACCESS)这个寄存器,把 SW_POR 置 1,然后等待芯片完成复位。

lsm6dsv80x_sw_por为 软件上电复位 / 全局复位 函数。

对应的驱动程序,如下所示。
c
/* Perform device power-on-reset */
lsm6dsv80x_sw_por(&dev_ctx);
BDU设置
在很多传感器中,数据通常被存储在输出寄存器中,这些寄存器分为两部分:MSB和LSB。这两部分共同表示一个完整的数据值。例如,在一个加速度计中,MSB和LSB可能共同表示一个加速度的测量值。
连续更新模式(BDU = '0'):在默认模式下,输出寄存器的值会持续不断地被更新。这意味着在你读取MSB和LSB的时候,寄存器中的数据可能会因为新的测量数据而更新。这可能导致一个问题:当你读取MSB时,如果寄存器更新了,接下来读取的LSB可能就是新的测量值的一部分,而不是与MSB相对应的值。这样,你得到的就是一个"拼凑"的数据,它可能无法准确代表任何实际的测量时刻。
块数据更新(BDU)模式(BDU = '1'):当激活BDU功能时,输出寄存器中的内容不会在读取MSB和LSB之间更新。这就意味着一旦开始读取数据(无论是先读MSB还是LSB),寄存器中的那一组数据就被"锁定",直到两部分都被读取完毕。这样可以确保你读取的MSB和LSB是同一测量时刻的数据,避免了读取到代表不同采样时刻的数据。
简而言之,BDU位的作用是确保在读取数据时,输出寄存器的内容保持稳定,从而避免读取到拼凑或错误的数据。这对于需要高精度和稳定性的应用尤为重要。
可以向CTRL3 (12h)的BDU寄存器写入1进行开启。

对应的驱动程序,如下所示。
c
/* Enable Block Data Update */
lsm6dsv80x_block_data_update_set(&dev_ctx, PROPERTY_ENABLE);
Tap 中断配置说明
LSM6DSV80X 内部可以识别 Single Tap 和 Double Tap 事件,但如果希望 MCU 通过外部中断方式响应这些事件,需要将对应的事件映射到传感器的中断引脚上。
将 Single Tap 和 Double Tap 事件都映射到 INT1 引脚。
Single Tap 和 Double Tap 事件映射到 INT1 引脚,对应 MD1_CFG 寄存器 5Eh。

对应的驱动程序,如下所示。
c
pin_int.double_tap = PROPERTY_ENABLE;
pin_int.single_tap = PROPERTY_ENABLE;
lsm6dsv80x_pin_int1_route_set(&dev_ctx, &pin_int);
使能中断输出
完成中断路由配置后,还需要使能 LSM6DSV80X 的中断输出功能。
中断信号触发后不会一直保持,需要及时读取事件源寄存器。
如果希望中断保持到软件读取状态寄存器后再清除,可以考虑将 lir 配置为 1。

对应的驱动程序,如下所示。
c
irq.enable = 1;
irq.lir = 0;
lsm6dsv80x_interrupt_enable_set(&dev_ctx, irq);
使能 Z 轴 Tap 检测
Tap 检测是基于加速度计数据实现的。LSM6DSV80X 可以配置 X、Y、Z 三个方向的 Tap 检测轴。
本实验中只开启 Z 轴 Tap 检测,也就是主要检测垂直于模块表面的敲击动作。
具体是否需要开启多个方向,需要根据实际产品安装方向和敲击方向来决定。
Tap 检测轴配置对应 TAP_CFG0 寄存器 56h。

对应的驱动程序,如下所示。
c
tap.tap_z_en = 1;
lsm6dsv80x_tap_detection_set(&dev_ctx, tap);
配置 Tap 阈值
Z 轴 Tap 阈值对应 TAP_THS_6D 寄存器 59h。
该配置实际对应的是写入 TAP_THS_6D(59h) 寄存器的低 5 位 TAP_THS_Z4:0。在当前 ±8g 量程下,1 LSB 对应 0.25g,因此阈值 3 对应约 0.75g。

对应的驱动程序,如下所示。
c
tap_ths.z = 3;
lsm6dsv80x_tap_thresholds_set(&dev_ctx, tap_ths);
配置 Tap 时间窗口
LSM6DSV80X 的单击 / 双击识别不仅需要配置 Tap 阈值,还需要配置 Tap 识别的时间窗口。时间窗口主要用于判断一次敲击的持续时间、敲击后的静默时间,以及两次敲击之间的最大间隔。
Tap 时间窗口由 TAP_DUR 寄存器 配置,该寄存器地址为 5Ah.
c
bit7~bit4:DUR[3:0]
用于配置双击识别时,两次 Tap 之间允许的最大时间间隔。
c
bit3~bit2:QUIET[1:0]
用于配置第一次 Tap 检测后的静默时间。在 quiet time 内,不能再出现超过阈值的事件,否则可能会影响 Tap 判断。
c
bit1~bit0:SHOCK[1:0]
用于配置一次 Tap 允许的最大冲击持续时间。如果超过阈值的时间太长,传感器可能不会将其识别为一次有效 Tap。

在当前 ODR_XL = 480Hz 条件下,双击最大间隔约为 466.7 ms,Tap 后静默时间约为 25 ms,单次 Tap 最大冲击持续时间约为 50 ms。实际产品调试时,如果双击不容易触发,可以适当增大 tap_gap;如果单击容易被误识别为双击,可以适当调整 quiet 和 tap_gap;如果敲击动作持续时间较长但无法识别,可以适当调整 shock 参数。
对应的驱动程序,如下所示。
c
tap_win.tap_gap = 7;
tap_win.shock = 3;
tap_win.quiet = 3;
lsm6dsv80x_tap_time_windows_set(&dev_ctx, tap_win);
配置 Single Tap / Double Tap 检测模式
LSM6DSV80X 的单击 / 双击模式选择由 WAKE_UP_THS 寄存器 配置,该寄存器地址为 5Bh.
LSM6DSV80X 会同时支持 Single Tap 和 Double Tap 检测。
当只检测到一次有效敲击时,可以产生 Single Tap 事件;
当在设定的 TAP_DUR(5Ah) 时间窗口内连续检测到两次有效敲击时,可以产生 Double Tap 事件。

对应的驱动程序,如下所示。
c
lsm6dsv80x_tap_mode_set(&dev_ctx, LSM6DSV80X_BOTH_SINGLE_DOUBLE);
设置量程和速率
c
/* Set Output Data Rate.*/
lsm6dsv80x_xl_setup(&dev_ctx, LSM6DSV80X_ODR_AT_480Hz, LSM6DSV80X_XL_HIGH_PERFORMANCE_MD);
/* Set full scale */
lsm6dsv80x_xl_full_scale_set(&dev_ctx, LSM6DSV80X_8g);
外部中断回调函数
当 LSM6DSV80X 检测到 Single Tap 或 Double Tap 后,INT1 引脚会产生中断信号。
c
void HAL_GPIO_EXTI_Rising_Callback(uint16_t GPIO_Pin)
{
if (GPIO_Pin == INT1_Pin) {
thread_wake = 1;
}
}
主程序
c
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
if(thread_wake==1)
{
thread_wake=0;
lsm6dsv80x_all_sources_t status;
/* Read output only if new xl value is available */
lsm6dsv80x_all_sources_get(&dev_ctx, &status);
if (status.single_tap) {
stap_event_catched = 1;
}
if (status.double_tap) {
dtap_event_catched = 1;
}
if (stap_event_catched) {
stap_event_catched = 0;
printf("Single TAP\r\n");
}
if (dtap_event_catched) {
dtap_event_catched = 0;
printf("Double TAP\r\n");
}
}
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
演示
