资讯详情

STM32C5开发LSM6DSV16X(9)--活动/静止检测

📅 2026/10/23 2:51:30 | 华诺云谱 👁 阅读
STM32C5开发LSM6DSV16X(9)--活动/静止检测
TOC概述本章介绍如何使用 STM32C5 驱动 IMU实现活动/静止检测Activity/Inactivity。传感器根据低量程加速度计经过滤波后的数据结合设定的阈值和持续时间判断设备状态持续满足静止条件后进入静止状态再次检测到符合条件的运动时恢复活动状态。视频教学样品申请https://www.wjx.top/vm/OhcKxJk.aspx#源码下载硬件准备首先需要准备一个开发板这里我准备的是自己绘制的开发板需要的可以进行申请。主控为STM32C542CCT6陀螺仪为LSM6DSV16X磁力计为LIS2MDL。参考程序https://github.com/CoreMaker-lab/STM32C542_LSM6DSV16X_LIS2MDLhttps://gitee.com/CoreMaker/STM32C542_LSM6DSV16X_LIS2MDL串口配置查看原理图PA9和PA10设置为开发板的串口。选择 Connectivity → USART1设置为 Async 异步模式波特率 115200、8 位数据、无校验、1 位停止位启用收发模式。串口的TX、RX 分别选择 PA9、PA10均设置为复用模式Alternate、无上下拉、推挽输出速度选择 Low。IIC配置STM32C542CCT6通过扩展接口与传感器模块连接其中PB6作为I²C时钟线SCLPB7作为I²C数据线SDA首先在 STM32CubeMX2 中进入 Peripherals 外设配置页面在 Connectivity 分类中选择 I2C1并将 I2C1 外设使能。如图所示本实验的 I2C1 配置步骤如下点击左侧 Peripherals 外设配置入口在 Connectivity 分类中选择 I2C1将 I2C1 Mode 设置为 I2C并确认 I2C1 显示为 ActiveSpeed frequency 设置为 Fast mode - 400 kHz确认 I2C1 的 GPIO 引脚映射SCL 为 PB6SDA 为 PB7CS和SA0设置确认I2C 模式选择和地址选择CS 需要处于 I2C 模式对应电平SA0 需要固定为高电平或低电平将 PA1 和 PB2 配置为普通 GPIO。在 Pinout 页面, set PA1 and PB2 to GPIO → Configured, used for SA0 (I²C address selection) respectively和 CS通信接口选择。进入 System → GPIO将 PA1、PB2 设置为推挽输出、无上下拉、低速由程序控制输出电平。板载 LIS2MDL 的 CS 引脚连接 PA6。在 Pinout 页面将 PA6 设置为 GPIO → Configured。进入 System → GPIO将 PA6 命名为 CS2设置为推挽输出、无上下拉、低速由程序控制输出电平。INT设置IMU 的 INT1Pin4连接 STM32C542 的 PB0用于接收陀螺仪数据就绪中断。将 PB0 配置为输入、无上下拉开启 EXTI0选择下降沿触发Falling edge使能中断及 IRQ Handler 生成。生成项目修改配置后左下角会提示 Click to save需要先保存当前工程配置点击左侧 Project settings进入工程生成设置页面在 IDE Project Generation 中选择工程格式和工具链本例选择 CMake GCC然后点击 Generate IDE project 生成工程导入STM32CubeIDE打开 STM32CubeIDE选择 File → Import导入 STM32CubeMX2 生成的 CMake 工程。展开 Import STM32 Project选择 STM32 CMake Project点击 Next进入工程路径选择页面。Project name填写导入到 STM32CubeIDE 中显示的工程名称Source directory选择 STM32CubeMX2 生成的 CMake 工程目录点击 Next继续完成工程导入Toolchain选择 MCU ARM GCC表示使用 ARM GCC 工具链进行编译MCU确认芯片型号为 STM32C542CCTx与前面 STM32CubeMX2 中选择的 MCU 保持一致CPU/Core确认内核为 Cortex-M33Core 为 0点击 Finish完成 CMake 工程导入设置工程编码在 Project Explorer 中选中工程点击 Project → Properties。选择 Resource将 Text file encoding 设置为 Other → GBK点击 Apply and Close 保存。串口 printf 重定向在 main.c 中添加以下头文件并在 main() 前实现 _write()将 printf() 输出重定向到 USART1用于打印 MEMS 数据和调试信息。#includemx_usart1.h#includestdio.h#includestring.hint_write(intfile,char*ptr,intlen){hal_uart_handle_t*huart1mx_usart1_uart_gethandle();if(huart1!NULL){HAL_UART_Transmit(huart1,ptr,len,1000);}returnlen;}参考程序https://github.com/STMicroelectronics/lsm6dsv16x-pid添加对应驱动程序。CMake 编译配置在 CMakeLists.txt 中将 .c 加入编译并添加 -u _printf_float启用 printf() 浮点输出支持。target_sources(${CMAKE_PROJECT_NAME}PRIVATE lsm6dsv16x_reg.c)target_link_options(${CMAKE_PROJECT_NAME}PUBLIC-u _printf_float)驱动接口与中断回调配置在 main.c 中引入 .h并定义启动等待时间 BOOT_TIME 为 10 ms、读取ID。变量 whoamI 用于保存读取到的设备 IDdev_ctx 用于绑定底层通信接口thread_wake 用于标记中断事件。声明 platform_write()、platform_read() 和 platform_delay()分别实现寄存器写入、读取及延时。同时通过 _write() 将 printf() 重定向至 USART1方便输出检测结果。在外部中断回调 HAL_EXTI_TriggerCallback() 中判断中断是否来自 GPIO EXTI0若匹配则将 thread_wake 置为 1。主循环随后读取传感器状态判断是否发生事件。回调中仅设置标志位寄存器读取和串口输出均在主循环中完成。#includelsm6dsv16x_reg.h#defineBOOT_TIME10U#defineBOARD_EXPECTED_IDLSM6DSV16X_ID#defineINACTIVITY_THRESHOLD4U#defineACTIVITY_THRESHOLD4U#defineINACTIVITY_DURATION2Ustaticstmdev_ctx_tdev_ctx;staticvolatileuint8_tthread_wake0;staticint32_tplatform_write(void*handle,uint8_treg,constuint8_t*bufp,uint16_tlen);staticint32_tplatform_read(void*handle,uint8_treg,uint8_t*bufp,uint16_tlen);staticvoidplatform_delay(uint32_tms);/** * brief EXTI trigger callback */voidHAL_EXTI_TriggerCallback(hal_exti_handle_t*hexti,hal_exti_trigger_ttrigger){(void)trigger;if(HAL_EXTI_GetInstance(hexti)HAL_EXTI_GPIO_0){thread_wake1;}}传感器接口初始化与设备检查系统初始化完成后设置 CS1、CS2 为高电平SA0 为低电平并将寄存器读写函数、延时函数及 I²C1 句柄绑定到 dev_ctx建立传感器通信接口。等待 10 ms 后读取并通过串口打印设备 ID。当 ID 不匹配 时程序停止运行检查通过后执行软件复位并再次等待 10 ms随后使能 BDU块数据更新为后续检测配置做好准备。printf(HELLO\r\n);HAL_GPIO_WritePin(CS1_PORT,CS1_PIN,HAL_GPIO_PIN_SET);HAL_GPIO_WritePin(SA0_PORT,SA0_PIN,HAL_GPIO_PIN_RESET);HAL_GPIO_WritePin(CS2_PORT,CS2_PIN,HAL_GPIO_PIN_SET);uint8_twhoamI0;lsm6dsv16x_reset_trst{0};lsm6dsv16x_if_cfg_tif_cfg{0};lsm6dsv16x_interrupt_mode_tirq{0};lsm6dsv16x_pin_int_route_tpin_int{0};lsm6dsv16x_act_thresholds_tact{0};lsm6dsv16x_act_wkup_time_windows_ttime_window{0};lsm6dsv16x_inactivity_dur_tinactivity_dur{0};/* Initialize driver interface. */dev_ctx.write_regplatform_write;dev_ctx.read_regplatform_read;dev_ctx.mdelayplatform_delay;dev_ctx.handlemx_i2c1_i2c_gethandle();platform_delay(BOOT_TIME);/* Check device ID. */lsm6dsv16x_device_id_get(dev_ctx,whoamI);printf(LSM6DSV16X_ID0x%x,id0x%x\r\n,(unsignedint)BOARD_EXPECTED_ID,(unsignedint)whoamI);if(whoamI!BOARD_EXPECTED_ID)while(1);/* Reset device. */lsm6dsv16x_reset_set(dev_ctx,LSM6DSV16X_GLOBAL_RST);do{lsm6dsv16x_reset_get(dev_ctx,rst);}while(rst!LSM6DSV16X_READY);platform_delay(BOOT_TIME);/* Enable Block Data Update. */lsm6dsv16x_block_data_update_set(dev_ctx,PROPERTY_ENABLE);加速度计配置将低量程加速度计设置为高性能模式输出数据率ODR为 480 Hz量程为 ±2 g为检测提供加速度数据。/* Avoid events during accelerometer filter settling. */lsm6dsv16x_filt_xl_fast_settling_set(dev_ctx,PROPERTY_ENABLE);lsm6dsv16x_mask_trigger_xl_settl_set(dev_ctx,PROPERTY_ENABLE);/* Low-G accelerometer: 480 Hz, /-2 g. */lsm6dsv16x_xl_data_rate_set(dev_ctx,LSM6DSV16X_ODR_AT_480Hz);lsm6dsv16x_xl_mode_set(dev_ctx,LSM6DSV16X_XL_HIGH_PERFORMANCE_MD);lsm6dsv16x_xl_full_scale_set(dev_ctx,LSM6DSV16X_2g);配置中断引脚的输出方式根据数据手册IF_CFG 寄存器中的 PP_OD 和 H_LACTIVE 用于设置中断引脚的输出类型和有效电平。代码先读取寄存器修改这两个位后再写回保留其他配置。配置完成后INT1 在中断有效时拉低未触发时通过上拉保持高电平。因此MCU 对应引脚需要配置上拉并采用下降沿触发 EXTI。/* INT1: open-drain active low. */lsm6dsv16x_read_reg(dev_ctx,LSM6DSV16X_IF_CFG,(uint8_t*)if_cfg,1);if_cfg.pp_od1;if_cfg.h_lactive1;lsm6dsv16x_write_reg(dev_ctx,LSM6DSV16X_IF_CFG,(uint8_t*)if_cfg,1);使能基本中断并开启锁存LIR 1 表示中断请求采用锁存方式。发生变化事件后中断请求被保留等待 MCU 读取处理。/* Enable basic interrupts in latched mode. */irq.enablePROPERTY_ENABLE;irq.lir1;lsm6dsv16x_interrupt_enable_set(dev_ctx,irq);选择高通滤波后的加速度作为检测输入高通滤波能够衰减静态重力和缓慢变化的分量使检测主要关注运动产生的加速度变化。板子静止、滤波器稳定后检测输入会减小移动或晃动板子时检测输入随运动发生变化。/* High-pass filtered acceleration for activity detection. */lsm6dsv16x_filt_wkup_act_feed_set(dev_ctx,LSM6DSV16X_WK_FEED_HIGH_PASS);配置活动/静止检测参数这段代码用于设置活动/静止检测的阈值及状态切换条件。首先将阈值分辨率设置为每级 7.8125 mg。本例活动/静止识别阈值和运动唤醒阈值均设置为 4对应 31.25 mg传感器根据经过滤波的加速度变化进行判断。设备处于静止状态时首次满足超阈值条件即可恢复活动状态进入静止状态则需要持续满足静止条件具体等待时间由后面的静止时间窗口配置。act.duration 设置为 0表示运动唤醒检测不增加额外的持续时间要求。此外代码将自动低功耗模式下的静止目标输出数据率设置为 15 Hz。不过本例后续选择保持加速度计和陀螺仪工作配置不变因此进入静止状态后加速度计仍保持原先设置的 480 Hz不会自动降低到 15 Hz。/* Configure activity/inactivity thresholds. */act.inactivity_cfg.wu_inact_ths_w0;act.inactivity_cfg.xl_inact_odrLSM6DSV16X_15Hz;act.inactivity_cfg.inact_durLSM6DSV16X_SLEEP_TO_ACT_AT_1ST_SAMPLE;act.inactivity_thsINACTIVITY_THRESHOLD;act.thresholdACTIVITY_THRESHOLD;act.duration0;lsm6dsv16x_act_thresholds_set(dev_ctx,act);设置进入静止状态前的等待时间这段代码配置 WAKE_UP_DUR 寄存器中的两个时间字段● quiet 对应 SLEEP_DUR用于设置进入静止状态前需要持续满足静止条件的时间。● shock 对应 WAKE_DUR用于设置 Wake-up 事件的持续时间要求。设备不会因为某一个采样点的变化较小就立即判断为静止。只有持续满足静止条件达到配置的时间窗口后才进入静止状态。增大 quiet 可以减少运动过程中短暂停顿造成的状态切换。/* Configure the quiet interval before entering inactivity. */time_window.quietINACTIVITY_DURATION;time_window.shock0;lsm6dsv16x_act_wkup_time_windows_set(dev_ctx,time_window);设置中断输出为状态变化通知这段代码设置 INACTIVITY_DUR 寄存器中的 SLEEP_STATUS_ON_INT 位选择活动/静止功能在中断引脚上的输出方式。本例设置为 0因此进入静止状态和恢复活动状态时都可以产生状态变化通知。主控收到中断后再读取状态寄存器判断当前属于活动还是静止。/* Report state changes on INT1. Set this bit separately because * act_thresholds_set() does not update sleep_status_on_int. */lsm6dsv16x_read_reg(dev_ctx,LSM6DSV16X_INACTIVITY_DUR,(uint8_t*)inactivity_dur,1);inactivity_dur.sleep_status_on_int0;lsm6dsv16x_write_reg(dev_ctx,LSM6DSV16X_INACTIVITY_DUR,(uint8_t*)inactivity_dur,1);保持加速度计和陀螺仪工作配置不变这段代码将 FUNCTIONS_ENABLE 寄存器中的 INACT_EN 设置为 00。按照数据手册该模式下仍然可以产生静止/运动中断但不会因为进入静止状态而自动改变加速度计和陀螺仪的工作配置。/* Keep XL/G operating modes unchanged during inactivity. */lsm6dsv16x_act_mode_set(dev_ctx,LSM6DSV16X_XL_AND_GY_NOT_AFFECTED);将活动/静止状态变化事件路由到 INT1这段代码通过 MD1_CFG 寄存器中的 INT1_SLEEP_CHANGE 位将活动/静止事件连接到 INT1 引脚。/* Route activity/inactivity state changes to INT1. */pin_int.sleep_changePROPERTY_ENABLE;lsm6dsv16x_pin_int1_route_set(dev_ctx,pin_int);printf(Activity/Inactivity detection start...\r\n);主循环当发生中断时EXTI 回调将 thread_wake 设置为 1。主循环检测到该标志后先将其清零再读取 WAKE_UP_SRC 寄存器获取事件标志和当前状态。在本例的锁存配置下读取对应中断源寄存器也用于清除锁存的中断请求便于接收后续事件。while(1){if(thread_wake){lsm6dsv16x_wake_up_src_tstatus{0};thread_wake0;/* Read the state and acknowledge the latched event. */if(lsm6dsv16x_read_reg(dev_ctx,LSM6DSV16X_WAKE_UP_SRC,(uint8_t*)status,1)!0){thread_wake1;platform_delay(100);continue;}if(status.sleep_change_ia){if(status.sleep_state)printf(Inactivity detected\r\n);elseprintf(Activity detected\r\n);}}}演示将开发板保持静止持续满足静止条件并达到配置的时间窗口后串口输出 Inactivity detected。随后移动开发板满足恢复活动的条件后串口输出 Activity detected。保持同一状态时不会因为主循环持续运行而重复打印。
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑