ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

三轴加速度计活动静止检测:LIS2DW12寄存器配置与低功耗实现

2026/9/15 16:27:43 拓冰建站 浏览量
三轴加速度计活动静止检测:LIS2DW12寄存器配置与低功耗实现 简介基于STM32WB55与CubeMX围绕LIS2DW12加速度计实现活动/静止状态检测是一份面向嵌入式开发者的完整工程。工程通过配置阈值和时长判断运动状态适用于可穿戴设备、安全监测等场景可通过调整参数改变检测灵敏度。压缩包共181个文件约3.04MB以C源码和头文件为主包含寄存器驱动、HAL库、IOC工程配置与Keil项目另有PDF文档、文本说明及编译产物方便直接编译烧录或对照学习。已有553人浏览学习。通过配套图文教程和B站视频可系统掌握LIS2DW12的寄存器读写、中断配置、状态判断流程并基于示例快速二次开发节省从零调试的时间。1. 检测活动和静止状态是三轴加速度计最有实用价值的场景之一穿戴手环的计步、物流标签的跌落报警、工业设备的振动监测背后都在做同一件事判断物体当前是“在动”还是“静止”。LIS2DW12这颗三轴加速度计在 ST 的 MEMS 产品线里定位是超低功耗数据手册标称 50Hz 采样率下的电流只有个位数微安级别这意味着它可以长时间挂在电池供电的系统里做运动检测而不必频繁唤醒主控。本系列前两篇通常已经解决了寄存器读写和原始数据读取的问题到了第三篇重点从“能读到数”转向“会用数据”。活动与静止检测有两种实现路线一是主控持续读取加速度数据自己做阈值判断二是在传感器内部完成检测并输出中断。LIS2DW12 的硬件方案里其实已经把后一条路的寄存器都铺垫好了我们真正要解决的是三件事怎么配置阈值、怎么处理持续时间的抖动、怎么让静态判断足够稳定而不被噪声误触发。适合的人群是有 STM32 或其他 MCU 基础、正在做低功耗运动检测方案的嵌入式开发工程师。2. 活动/静止检测的原理与 LIS2DW12 的寄存器设计2.1 加速度模值与阈值比较的物理基础静止状态下三轴加速度的矢量和近似等于重力加速度 g约为 9.8 m/s²换算成 LIS2DW12 的 LSB 数值取决于量程和分辨率配置。以 ±2g 量程、14 位模式下为例灵敏度约为 0.244 mg/LSB静止时的模值读数会稳定在 1g 附近。当设备开始移动三轴上的加速度分量会产生变化模值会明显偏离 1g这是活动检测的基本依据。但直接比较“当前模值是否超过阈值”是不够的。实际场景里手持设备轻微抖动、桌面共振、传感器自身噪声都会让模值在静止时产生几十到几百 mg 的波动。如果阈值设置得太小静止状态会被频繁误判为活动太大则慢速移动检测不到。这是整个检测逻辑里第一个需要工程化处理的矛盾点。float calc_magnitude(int16_t x, int16_t y, int16_t z, float sensitivity_mg) { float fx x * sensitivity_mg; float fy y * sensitivity_mg; float fz z * sensitivity_mg; return sqrtf(fx * fx fy * fy fz * fz); }这段代码把三轴原始值转换成 mg 单位后求矢量和。sensitivity_mg是灵敏度系数需要在初始化时根据量程设置传入。实际使用中可以只判断模值是否落在(1000 - threshold, 1000 threshold)区间内超过区间即为活动。需要留意的是模值计算使用了 sqrtf涉及浮点运算在 Cortex-M0 这类没有 FPU 的内核上会比较耗时,可以用比较平方值的方式来规避浮点开销。2.2 自由落体与活动中断共用的 INT_FF_WU_CFG 寄存器LIS2DW12 把自由落体检测和活动/静止检测放在同一组配置里寄存器地址是 0x14名为 INT_FF_WU_CFG。这个设计初看有点绕实际逻辑是统一的自由落体本质上是“模值接近 0”活动检测本质上是“模值显著偏离 1g”两者共享同一套使能机制只是阈值和持续时间不同。寄存器中每个轴有两个位对应轴的「低于阈值」使能和「高于阈值」使能。自由落体关心的是三轴同时低于阈值即三轴都接近 0活动检测则使用高于阈值的使能位即任一轴的加速度超过设定值就视为活动。这一设计的好处是在一个中断引脚上可以配置多种运动事件不需要外部额外组合逻辑。以检测运动为例通常配置 0x15 给 INT_FF_WU_CFG 寄存器使能 X、Y、Z 三轴的高阈值检测。观察中断源时需要读 0x27 寄存器FF_WU_SRC来区分是哪个轴触发了中断这有助于调试时定位传感器的安装方向。2.3 活动检测阈值与持续时间的寄存器映射活动检测相关的关键寄存器有三个0x17ACT_THS配置活动阈值0x18ACT_DUR)配置活动持续时间0x16FF_THS和 0x19FF_DUR)分别配置静止/自由落体的阈值和持续时间。很多初学者在这里容易搞混把活动阈值设置到自由落体的寄存器里导致检测行为完全不符合预期。static void lis2dw12_config_activity_detection(uint8_t threshold_mg, uint8_t duration_ms) { uint8_t ths_reg threshold_mg / 32; // ±2g量程下每LSB约32mg uint8_t dur_reg duration_ms / 10; // 每LSB约10ms取决于ODR // 使能三轴高阈值检测 write_reg(0x14, 0x38); // 0110 1000: XH1 YH1 ZH1 // 设置活动阈值和持续时间 write_reg(0x17, ths_reg); write_reg(0x18, dur_reg); }阈值换算需要结合量程。±2g 下每 LSB 对应约 32mg一次有效活动通常认为加速度变化超过 250mg~500mg对应的寄存器值大约是 8~15。持续时间用来过滤瞬时冲击比如放在桌上的设备被拍了一下模值会瞬间跳变但马上恢复这个几十毫秒的抖动不能算作活动只有在持续时间内模值始终超阈值才刷新状态。这个延迟判断机制对应了数据手册里的“debounce”概念。2.4 静止检测为什么要单独配置活动检测判断的是“模值超过阈值”静止检测判断的是“模值在阈值区间内保持一段时间”。LIS2DW12 在活动检测之外提供了一个独立的静止检测中断这样在设备由动转静时能及时通知主控而不是等主控主动轮询才发现设备停了。这两者的配合在低功耗设计中非常有用设备活动时以较高频率采样检测到静止后自动切换为较低频率或者直接休眠达到省电的目的。在 RL 模式下配置静止检测需要按加速度量程选择合适的阈值。静止阈值通常设置在 50~100mg这个数值要能够覆盖设备静置时的地平面倾斜变化同时避免因传感器噪声造成的误触发。实际调试时建议用逻辑分析仪捕捉中断引脚的翻转同时打印出模值数据来对照观察阈值和持续时间配合后真实的事件判定情况。3. 在 STM32 上实现活动与静止检测的完整代码3.1 SPI/I2C 接口抽象与驱动初始化LIS2DW12 支持 I2C 和 SPI 两种接口很多工程师在自己的嵌入式开发环境中两种都做了抽象方便后续换料或者调试。以 I2C 为例7 位地址是 0x18SA0 接低电平实际代码里使用 8 位写地址 0x32。初始化流程先通过 WHO_AM_I0x0F寄存器的值 0x44 确认通信正确再配置 CTRL10x20设定工作模式和输出数据速率。typedef struct { void (*write)(uint8_t reg, uint8_t val); uint8_t (*read)(uint8_t reg); } lis2dw12_bus_t; static lis2dw12_bus_t *bus; int lis2dw12_init(lis2dw12_bus_t *bus_ops) { bus bus_ops; uint8_t whoami bus-read(0x0F); if (whoami ! 0x44) return -1; // CTRL1: 50Hz ODR, 低功耗模式2, 14位分辨率 bus-write(0x20, 0x37); // CTRL6: 低通滤波器截止频率约 1/4 ODR可过滤高频振动噪声 bus-write(0x25, 0x10); // 活动/静止检测中断映射到 INT1 引脚 bus-write(0x23, 0x10); return 0; }CTRL1的 0x37 拆开看低 4 位 0110 是 ODR 50Hzbit4~bit5 是 01 表示低功耗模式 2bit6 是 1 使能 14 位分辨率。这个配置组合在电池供电场景是常用的起点功耗和响应速度处于比较合适的均衡点。CTRL6里开启的低通滤波器非常关键尤其是后续要通过模值判断静止状态时轻微的机械抖动会被衰减减小误判概率。3.2 活动检测中断回调与状态机设计配置完成后在中断处理函数中读取 INT_WU_SRC0x27来确认触发原因然后清中断标志。注意 LIS2DW12 的中断是电平还是脉冲模式由 CTRL30x22的 bit1LIR决定。建议配置为锁存模式边沿触发事件后保持中断状态直到主控读取源寄存器后才自动清除这能防止主控来不及响应导致事件丢失。volatile uint8_t activity_event_pending; void EXTI0_IRQHandler(void) { activity_event_pending 1; } void activity_event_handler(void) { if (!activity_event_pending) return; activity_event_pending 0; uint8_t src bus-read(0x27); // 检查是否为高电平触发活动 if (src 0x20) { // 三轴中任一轴超阈值 state STATE_ACTIVE; } // 静止检测中断同理会触发到这里需要读取另一组寄存器区分 }中断处理函数里只做标志位设置实际的状态判断放到主循环里处理这符合嵌入式开发的常见做法中断里不处理耗时操作也不会阻塞其他高优先级中断。状态机方面建议至少有STATE_UNKNOWN、STATE_ACTIVE、STATE_STILL三个状态避免系统刚上电时在一个未初始化状态下输出错误的业务数据。3.3 通过轮询模式实现活动/静止状态判定的备选方案使用中断会使代码结构更高效但并非必须。在某些复用中断引脚的场景或者需要同时兼顾多路传感器时用主控轮询数据来做判断也很常见。此时最大的风险在于 ODR 和轮询频率不匹配导致状态切换滞后甚至漏检测。void poll_lis2dw12_activity(void) { static uint16_t still_count 0; int16_t x read_axis(0x28); int16_t y read_axis(0x2A); int16_t z read_axis(0x2C); uint32_t mag_sq x * x y * y z * z; uint32_t still_thr_sq 0x1000; // 对应约320mg阈值 if (mag_sq still_thr_sq) { still_count; if (still_count 5) state STATE_STILL; } else { still_count 0; state STATE_ACTIVE; } }轮询方案要注意mag_sq和阈值都是平方后的值避免每次判断重新开方。still_thr_sq是在静止基础上叠加了约 200mg 的容差具体数值按设备实际安装后静置时的读数微调。5 次连续计数相当于 100ms 的持续判断这个去抖窗口可以防止按键级瞬间抖动造成状态反复切换。3.4 阈值、持续时间和采样率的配合关系表检测场景ODR (Hz)活动阈值 (mg)活动持续时间 (ms)静止阈值 (mg)静止持续时间 (ms)手环计步505002080200物流冲击记录10015005100100跌倒检测快速动态2520001060500设备防拆监测12.525040401000ODR 决定功耗和延时。活动检测场景下阈值高一些没关系但要避免把阈值设得太高以至于慢走时都检测不到静止检测则需要小的阈值配合长持续时间用来过滤细微的振动干扰。表格只是一个起始参考值真正合不合适需要在目标设备上做实际测试后反向修正。4. 静止状态误判与活动漏检的调参排错4.1 噪声引起的静止误判低通滤波器的正确配置最常见的故障是设备明明放在桌子上静止检测却发现设备在动。此时先假定不是算法问题而是传感器读取到了噪声或电源纹波干扰。LIS2DW12 内部集成了一个低通滤波器带宽由 CTRL6 寄存器配置可以按 ODR 的比例设定截止频率。将滤波器带宽限制在较低档位能够抑制由马达振动或电源波动带来的高频分量。// CTRL6 (0x25) bit0~bit2控制低通带宽 // 000: ODR/2 001: ODR/4 010: ODR/8 011: ODR/10 // 100: ODR/20 101: ODR/40 110: ODR/80 111: ODR/160 static void set_lpf_bw(uint8_t code) { uint8_t v bus-read(0x25); v (v 0xF8) | (code 0x07); bus-write(0x25, v); }如果设备安装在电机附近建议把带宽设为 ODR/20 或更低配合 5 次以上的连续采样确认来过滤偶发噪声尖峰。滤波器的代价是响应延迟带宽越低检测到活动所需的时间越长。这在快速运动比如跌落场景中可能造成漏检要在响应速度和抗干扰之间找一个平衡这个平衡点必须实测确定。4.2 长时间静止后模值漂移与自动校准一些应用里设备会长期静止而温度变化或机械应力释放会导致静止时模值偏离 1g偏移量通常有几十到几百 mg。如果静止阈值设置得很小这种漂移也可能让静止检测失效。常见做法是在系统上电后执行一次校准确认设备处于静止状态时采集 50 至 100 组数据计算平均值把均值作为新的零点之后所有模值都基于这个零点重新计算。typedef struct { int32_t offset_x, offset_y, offset_z; } accel_offset_t; void calibrate_zero(accel_offset_t *off) { int32_t sx 0, sy 0, sz 0; for (int i 0; i 100; i) { sx read_axis(0x28); sy read_axis(0x2A); sz read_axis(0x2C); } off-offset_x sx / 100; off-offset_y sy / 100; off-offset_z sz / 100; }校准逻辑要注意设备必须在真正静止时执行。可以在程序中加入提示信息要求用户在 2 秒内保持设备不动。数据采集完成后算出三轴偏移量后续读取到的原始数值都需要减去这些偏移。如果校准后设备发生了物理位置大幅变化例如从水平变为竖立零点会失真需要重新校准或使用后台的自动校准策略。4.3 用中断源寄存器区分多事件冲突当活动检测和静止检测同时使能且映射到同一个中断引脚时中断处理函数里需要先读 0x27FF_WU_SRC再读静止检测源寄存器并比对两者的内容。很多工程师调试时只配置一个中断使能一旦两个事件先后发生无法区分到底是哪个触发了中断后续状态机就会错乱。void handle_motion_interrupt(void) { uint8_t wu_src bus-read(0x27); uint8_t still_src bus-read(0x2B); if (wu_src 0x20) { state STATE_ACTIVE; } else if (still_src 0x20) { state STATE_STILL; } }0x27的 bit5 表示是否有任一轴超过活动阈值0x2B的 bit5 表示静止条件是否满足。两个寄存器在故障时同时为 0则说明中断来自其他配置源比如 FIFO 满或数据就绪需要重新审查 CTRL4 和 CTRL5 的中断映射。寄存器读取顺序也有讲究必须完整读完所有使能的中断源寄存器后中断线才会拉低/拉回。4.4 低功耗场景下模式切换对检测的影响在电池供电方案中静止后切换传感器到更低功耗模式是常规操作。LIS2DW12 的 CTRL1 寄存器的 MODE 位可以控制低功耗模式切换后采样率和噪声特性都会变化。千万注意切换前要确认当前没有未处理的中断事件否则状态切换会使事件丢失出现“静止了但不报告”的问题。void enter_low_power_still_mode(void) { // 先读回并清除挂起的中断 uint8_t tmp bus-read(0x27); tmp bus-read(0x2B); // 将ODR降为1.6Hz立即进入低功耗模式3 bus-write(0x20, 0x11); }模式切换后活动检测的阈值和持续时间仍然保留原来的配置值但需要重新验证。因为在低功耗模式下传感器的内部采样策略和滤波行为可能会有所不同原来合适的阈值参数可能出现偏差。建议在切换前设置一个“正在进行切换”的全局标志业务逻辑在这个标志置位时忽略状态变化等切换完成后再恢复检测。5. 利用 FIFO 实现活动/静止检测的低功耗进阶方案LIS2DW12 内置了一个 32 级深度的 FIFO 缓冲区在不增加主控唤醒频率的前提下批量读取数据。配合活动/静止检测中断可以让 MCU 进入休眠状态只有检测到活动事件时才唤醒并读取 FIFO 中缓存的完整运动过程数据。这种方法适合事件驱动型的记录设备比如跌倒记录仪、动物行为监测项圈等。void lis2dw12_fifo_stream_config(void) { // CTRL3: FIFO中断使能映射到INT1 bus-write(0x22, 0x08); // FIFO_CTRL (0x2E): 流模式达到阈值触发中断 bus-write(0x2E, 0x00); // FIFO_SAMPLES (0x2F): 16个样本触发中断 bus-write(0x2F, 16); } void read_fifo_batch(int16_t *buf, uint8_t *count) { *count bus-read(0x2F); // 读取当前FIFO中样本数 for (uint8_t i 0; i *count; i) { buf[i * 3 0] read_axis(0x28); buf[i * 3 1] read_axis(0x2A); buf[i * 3 2] read_axis(0x2C); } }FIFO 模式配置需要注意的是 FIFO_CTRL 寄存器低 5 位在流模式下用于设置触发水位而FIFO_SAMPLES寄存器在不同模式下的意义不同。流模式下当 FIFO 内样本数达到设置水位时产生中断主控一次性读取所有样本这样可以将每 50ms 一次的采样扩量到每 800ms 一次批量读取MCU 的休眠时间大大延长同时片上的 FIFO 完整保留了活动发生前后各轴的变化轨迹。配合中断唤醒时可以让主控进入 STOP 模式依靠 EXTI 唤醒。常见做法是硬件上将 LIS2DW12 的 INT1 引脚连接到 MCU 的 PA0/WKUP 引脚开启外部中断活动事件来临后传感器主动拉高 INT1MCU 从 STOP 模式唤醒。唤醒后先读取中断源寄存器再根据需求决定是否读取 FIFO 全部数据。这个方案的关键在于 FIFO 水位不能设太高否则活动事件发生前的数据被新数据覆盖也不能太低否则主控频繁唤醒功耗下不来。实际调参时把水位设在 8~16 之间通常比较合适。验证整个检测链路是否可靠可以用一个简单的回归测试脚本在设备静止时连续记录 20 次状态手动晃动设备 10 次统计检测到活动的成功率和静止误触发率。用已知周期的振动源比如手机振动马达来标定阈值与持续时间的关系记录不同参数组合下的检测延时这种有数据支撑的参数调整比依靠直觉设定可靠性高得多。本文还有配套的精品资源点击获取