LIS3DH从入门到精通_三轴加速度计实战指南

LIS3DH 从入门到精通 ------ 一款"老而弥坚"的三轴加速度计

关键词:LIS3DH、三轴加速度计、MEMS、姿态检测、低功耗、I²C、SPI、自由落体检测


一、前言

在众多 MEMS 加速度计中选一颗"万金油"芯片,LIS3DH 一定排在前三。

这颗来自 ST(意法半导体)的三轴加速度计,从 2010 年左右推向市场到现在,已经卖了十几亿颗。你手上的智能手环、TWS 耳机、电子标签、共享单车的智能锁、车辆防盗器、智能水杯......里面大概率都有一颗 LIS3DH 或者它的变种。

它这么能打,三个字:够用、便宜、省心

这篇文章会从应用场景、硬件设计、寄存器配置、驱动代码、低功耗策略、进阶功能到常见调试坑,一条龙讲透彻。无论你是第一次接触 MEMS 传感器的新人,还是想深入研究的老手,都能有所收获。


二、LIS3DH 是谁?------ 一张图看懂

2.1 基本参数

参数 规格 解读
测量轴 3 轴(X, Y, Z) 可独立使能任意轴
量程 ±2g / ±4g / ±8g / ±16g 软件可选,寄存器配置
分辨率 16-bit 数据输出 精度足够绝大多数应用
输出数据率(ODR) 1 Hz ~ 5.376 kHz 从超低功耗到高速采样全覆盖
接口 I²C(最高 400 kHz)+ SPI(最高 10 MHz) 两种任选
工作电压 1.71V ~ 3.6V 一颗纽扣电池就能跑
工作电流 低至 2 μA(低功耗模式,1 Hz ODR) 真正的"钮扣电池吃一年"级别
FIFO 32 级,每级 10-bit 配合 MCU 间歇读取,进一步省电
中断 2 路独立可编程中断引脚(INT1, INT2) 自由落体、唤醒、单击/双击、6D 方向......
封装 LGA-16,3×3×1mm 比一粒芝麻还小
温度范围 -40°C ~ +85°C 工业级,户外随便用

2.2 芯片内部框图

复制代码
         ┌─────────────────────────────────────┐
         │              LIS3DH                  │
         │                                      │
  X ──→  │  ┌─────┐                            │
  Y ──→  │  │MEMS │   ┌──────┐   ┌──────────┐  │
  Z ──→  │  │传感 │→  │电荷放大│→  │16-bit ADC│  │
         │  │单元 │   └──────┘   └────┬─────┘  │
         │  └─────┘                   │         │
         │                            ▼         │
         │                      ┌──────────┐    │
         │                      │ 数字滤波  │    │
         │                      └────┬─────┘    │
         │                           │          │
         │              ┌────────────┼──────┐   │
         │              │     控制逻辑     │   │
         │              │  ┌───┴────┐     │   │
         │              │  │  FIFO  │     │   │
         │              │  │ (32级) │     │   │
         │              │  └────────┘     │   │
         │              │  ┌────────┐     │   │
         │              │  │ 中断   │→ INT1/INT2
         │              │  │ 发生器 │     │   │
         │              │  └────────┘     │   │
         │              └──────┬──────────┘   │
         │                     │               │
         │              ┌──────┴──────┐        │
         │              │ I²C / SPI   │        │
         │              │ 从机接口    │        │
         │              └─────────────┘        │
         └─────────────────────────────────────┘

三、LIS3DH 用在哪些产品上?------ 16 个真实落地场景

这是读者最关心的问题,我把它放前面讲。

3.1 消费电子

产品 LIS3DH 做什么 具体实现
TWS 耳机 佩戴检测、敲击控制 检测放入/取出耳机的加速度特征,双击/三击切歌
智能手环/手表 抬腕亮屏、计步、睡眠监测 加速度变化的持续检测和模式识别
智能手机 屏幕旋转、摇一摇、计步 这是加速度计的"基本盘"应用
平板/电子书 屏幕方向切换 重力方向检测
游戏手柄 姿态感知、体感操控 倾斜角对应游戏角色运动
遥控器 空中飞鼠、语音键抬起唤醒 拿起遥控器自动唤醒语音识别

3.2 物联网 & 工业

产品 LIS3DH 做什么 具体实现
共享单车智能锁 车辆倾倒检测、震动报警 持续监测倾角,异常移动推送告警
电动车/摩托车防盗器 震动触发报警、拖车检测 极低功耗待机,震动唤醒后 GPS 定位上报
智能水杯 喝水动作检测、倾倒检测 杯子倾斜角对应喝水动作;倾倒 90° 防漏水提醒
物流追踪标签 货物倾倒/撞击记录 全程记录加速度异常事件
贵重资产监控 移动检测、防拆告警 任何未经授权的移动都会触发中断通知
桥梁/建筑结构监测 低频振动监测 长期监测结构的微小倾斜和振动频率变化

3.3 汽车 & 安防

产品 LIS3DH 做什么 具体实现
车载 OBD/T-Box 急加速/急刹车/碰撞检测 加速度阈值判断 + 行车数据上传
行车记录仪 碰撞锁定视频、停车监控 检测到碰撞时自动锁定当前视频文件
安防门窗传感器 开/关门检测 门的加速度变化特征判断开关状态
保险箱 移动/倾斜报警 任何异常姿态变化立即触发告警

一句话总结 :只要你需要检测运动、震动、倾斜、自由落体、敲击、休眠唤醒中的任何一个,LIS3DH 就是最优先考虑的那颗料。


四、硬件设计 ------ 原理图到 PCB 一条龙

4.1 典型 I²C 应用电路

复制代码
               VDD (1.71V ~ 3.6V)
                │
                ├──────────────────────────────────┐
                │                                  │
              10μF│                ┌───────────────┼──────────┐
                │  ┌───100nF──┐   │               │          │
                │  │          │   │               │          │
               GND GND       GND  │               │          │
                                  │            LIS3DH        │
                   ┌──────────────┤ 1  (VDD)            12 ├─ GND
                   │     ┌────────┤ 2  (VDD_IO)         11 ├─ GND
                   │     │  ┌─────┤ 3  (NC)     INT1   10 ├─→ MCU GPIO (中断)
                   │     │  │  ┌──┤ 4  (NC / SDO/SA0)   9 ├─→ MCU GPIO (I²C地址选择)
                   │     │  │  │  │                        │
                   │     │  │  │  │  5  (SCL/SPC)  ────────┼─→ MCU SCL (加10kΩ上拉到VDD)
                   │     │  │  │  │  6  (SDA/SDI/SDO) ─────┼─→ MCU SDA (加10kΩ上拉到VDD)
                   │     │  │  │  │  7  (SDO/SA0) ─────────┼─→ MCU GPIO (备用地址)
                   │     │  │  │  │  8  (CS) ──────────────┤─→ GND (I²C模式拉低)
                   └─────┴──┴──┴──┤                         │
                                  └─────────────────────────┘

4.2 关键设计要点

4.2.1 电源去耦 ------ 不能省!
复制代码
VDD ──┬── 10μF (钽电容或大容量MLCC) ── GND
      │
      └── 100nF (靠近芯片1脚,距离<5mm) ── GND

VDD_IO ── 100nF (靠近芯片2脚) ── GND

LIS3DH 内部有电荷泵和 ADC,瞬间电流可达几 mA。 去耦电容没做好,加速度数据会出现周期性噪声(50Hz/60Hz 尖峰),怎么滤波都滤不干净------因为问题出在硬件而不是软件。

4.2.2 I²C 地址选择
SA0 引脚 (Pin 4) 电平 7-bit I²C 地址 8-bit 写地址
接 GND 0x18 0x30
接 VDD 0x19 0x32

注意:如果你买的是 LIS3DH 模块(如 GY-521 那种小板),厂家通常已经帮你拉好了,看模块上的丝印或量一下 SA0 电平。

4.2.3 CS 引脚 ------ I²C vs SPI 模式选择
CS (Pin 8) 模式
GND I²C 模式
VDD SPI 模式
4.2.4 PCB Layout 注意事项
  • 不要放在板边:板边的机械应力最大,MEMS 对这种应力非常敏感,会出现 DC 偏置漂移
  • 远离发热源:远离 LDO、功率电阻、MCU 等发热器件。温度梯度会导致 MEMS 产生热应力,零点偏移可达几十 mg
  • 底部铺铜做 GND:芯片正下方铺大面积 GND,减少 EMI 干扰
  • 不要手动焊接 QFN/LGA 封装:回流焊才能保证焊接平整。手动焊容易导致芯片倾斜,Z 轴会有 1g 的"旋转投影误差"
  • 焊盘设计:严格按数据手册中的推荐焊盘尺寸(0.45mm × 0.35mm),不要自作主张改大改小

五、寄存器地图 ------ 你真正需要关心的就这 10 个

LIS3DH 有 50 多个寄存器,但 90% 的应用只需要掌握以下 10 个:

寄存器名 地址 作用 一句话
WHO_AM_I 0x0F 芯片 ID 读出来永远是 0x33------通信验证第一步
CTRL_REG1 0x20 数据率 + 三轴使能 ODR + XYZ 开关,上电必配
CTRL_REG2 0x21 高通滤波器 一般不用,默认就行
CTRL_REG3 0x22 INT1 中断源配置 哪个事件触发 INT1 引脚
CTRL_REG4 0x23 量程 + 数据格式 + 自检 选 ±2/4/8/16g,选大端还是小端
CTRL_REG5 0x24 INT1 锁存 + 4D 使能 中断引脚的电气行为
CTRL_REG6 0x25 INT2 中断源配置 和 CTRL_REG3 功能一样,控制 INT2
OUT_X_L / OUT_X_H 0x28-0x29 X 轴数据 16-bit,左对齐,需要右移
OUT_Y_L / OUT_Y_H 0x2A-0x2B Y 轴数据 同上
OUT_Z_L / OUT_Z_H 0x2C-0x2D Z 轴数据 同上
INT1_SRC 0x31 中断源状态 读这个就知道是谁触发了中断

5.1 核心寄存器详解

CTRL_REG1 (0x20) ------ 上电第一个要配的寄存器
复制代码
Bit 7   6   5   4    3    2    1    0
    ODR3 ODR2 ODR1 ODR0 LPen Zen Yen Xen
Bits 7:4 数据率 (ODR) 典型功耗
0000 省电模式 < 1 μA
0001 1 Hz 2 μA
0010 10 Hz ---
0011 25 Hz ---
0100 50 Hz ---
0101 100 Hz ---
0110 200 Hz ---
0111 400 Hz ---
1000 1.620 kHz (低功耗 5.376 kHz) ---
Bits 2:0 功能
Xen / Yen / Zen 1 = 使能该轴,0 = 关闭

最常用的几个初始化值

c 复制代码
// 低功耗计步:1 Hz,三轴全开
CTRL_REG1 = 0x17;  // 0001 0111

// 正常模式:100 Hz,三轴全开(最常用)
CTRL_REG1 = 0x57;  // 0101 0111

// 高速采样:400 Hz,三轴全开
CTRL_REG1 = 0x77;  // 0111 0111
CTRL_REG4 (0x23) ------ 量程与数据格式
复制代码
Bit 7   6   5   4    3    2    1    0
    BDU  BLE FS1 FS0 HR   ST1  ST0  SIM
FS1:0 (Bits 5:4) 量程 灵敏度 (mg/LSB)
00 ±2g 1 mg/LSB
01 ±4g 2 mg/LSB
10 ±8g 4 mg/LSB
11 ±16g 12 mg/LSB

经验之谈

  • 计步、姿态检测、抬腕亮屏 → ±2g,精度最高
  • 碰撞检测、自由落体 → ±8g 或 ±16g,不会饱和
  • 不确定用哪个?先上 ±4g,跑一圈看数据峰值,再收窄

BLE (Bit 6) :1 = 先读低字节(Little-Endian),这是大多数 MCU 的默认习惯。建议始终置 1

BDU (Bit 7) :1 = 数据在读取期间锁定,防止高低字节分属两个采样点。建议始终置 1


六、驱动代码实战

6.1 I²C 通信基础(以 STM32 HAL 为例)

c 复制代码
#define LIS3DH_I2C_ADDR  0x18  // SA0 接 GND
#define LIS3DH_WHO_AM_I  0x0F
#define LIS3DH_CTRL_REG1 0x20
#define LIS3DH_CTRL_REG4 0x23
#define LIS3DH_OUT_X_L   0x28
#define LIS3DH_OUT_X_H   0x29
#define LIS3DH_OUT_Y_L   0x2A
#define LIS3DH_OUT_Y_H   0x2B
#define LIS3DH_OUT_Z_L   0x2C
#define LIS3DH_OUT_Z_H   0x2D

// 写单个寄存器
void lis3dh_write_reg(uint8_t reg, uint8_t val) {
    uint8_t buf[2] = {reg, val};
    HAL_I2C_Master_Transmit(&hi2c1, LIS3DH_I2C_ADDR << 1, buf, 2, 100);
}

// 读单个寄存器
uint8_t lis3dh_read_reg(uint8_t reg) {
    uint8_t val;
    HAL_I2C_Master_Transmit(&hi2c1, LIS3DH_I2C_ADDR << 1, &reg, 1, 100);
    HAL_I2C_Master_Receive(&hi2c1, LIS3DH_I2C_ADDR << 1, &val, 1, 100);
    return val;
}

// 读多个连续寄存器(自动递增)
void lis3dh_read_regs(uint8_t reg, uint8_t *buf, uint8_t len) {
    // LIS3DH 支持地址自动递增,设置 bit 7 使能
    reg |= 0x80;  // 使能多字节读取模式
    HAL_I2C_Master_Transmit(&hi2c1, LIS3DH_I2C_ADDR << 1, &reg, 1, 100);
    HAL_I2C_Master_Receive(&hi2c1, LIS3DH_I2C_ADDR << 1, buf, len, 100);
}

6.2 芯片初始化和自检

c 复制代码
int lis3dh_init(void) {
    uint8_t whoami;

    // 第一步:验证通信
    whoami = lis3dh_read_reg(LIS3DH_WHO_AM_I);
    if (whoami != 0x33) {
        printf("LIS3DH not found! WHO_AM_I = 0x%02X\r\n", whoami);
        return -1;
    }
    printf("LIS3DH detected!\r\n");

    // 第二步:配置数据率和使能轴
    // 100 Hz ODR,X/Y/Z 全开
    lis3dh_write_reg(LIS3DH_CTRL_REG1, 0x57);

    // 第三步:配置量程与数据格式
    // BDU=1(锁存), BLE=1(小端), FS=00(±2g), HR=1(高分辨率)
    lis3dh_write_reg(LIS3DH_CTRL_REG4, 0x88);

    // 等待传感器稳定(上电后需要至少 5ms)
    HAL_Delay(10);

    return 0;
}

6.3 读取原始数据并转换

c 复制代码
void lis3dh_read_accel(int16_t *x, int16_t *y, int16_t *z) {
    uint8_t buf[6];

    // 从 OUT_X_L 开始连续读 6 个字节
    lis3dh_read_regs(LIS3DH_OUT_X_L, buf, 6);

    // 组合高低字节(小端格式,BLE=1)
    *x = (int16_t)((buf[1] << 8) | buf[0]);
    *y = (int16_t)((buf[3] << 8) | buf[2]);
    *z = (int16_t)((buf[5] << 8) | buf[4]);

    // LIS3DH 是左对齐的 16-bit,实际有效数据在高 10~12 bits
    // 需要右移以对齐:
    //   ±2g: 12-bit有效 → 右移4位
    //   ±4g: 12-bit有效 → 右移4位
    //   ±8g: 10-bit有效 → 右移6位
    //   ±16g: 10-bit有效 → 右移6位
    // 此处以 ±2g 为例:
    *x >>= 4;
    *y >>= 4;
    *z >>= 4;
}

// 转换为 mg 单位 (以 ±2g, 灵敏度 1mg/LSB 为例)
void lis3dh_read_accel_mg(float *x_mg, float *y_mg, float *z_mg) {
    int16_t x, y, z;
    lis3dh_read_accel(&x, &y, &z);
    *x_mg = (float)x;      // ±2g: 1 LSB = 1 mg
    *y_mg = (float)y;
    *z_mg = (float)z;
}

6.4 计算姿态角(倾斜角)

c 复制代码
// 计算俯仰角 (Pitch) 和翻滚角 (Roll),单位:度
void lis3dh_calc_angles(float x_mg, float y_mg, float z_mg,
                         float *pitch, float *roll) {
    // Pitch: 绕 Y 轴旋转的角度
    *pitch = atan2f(-x_mg, sqrtf(y_mg * y_mg + z_mg * z_mg)) * 180.0f / M_PI;

    // Roll: 绕 X 轴旋转的角度
    *roll  = atan2f(y_mg, z_mg) * 180.0f / M_PI;
}

// 简单倾斜检测(用于水杯倾倒、设备倾斜告警等)
uint8_t lis3dh_is_tilted(float pitch, float roll, float threshold_deg) {
    return (fabsf(pitch) > threshold_deg || fabsf(roll) > threshold_deg);
}

七、中断功能 ------ LIS3DH 的"灵魂"

如果只用 LIS3DH 读加速度数据,你只用了它 30% 的功能。中断才是这颗芯片的精髓------它让 MCU 从"轮询的奴隶"变成"事件的响应者"。

7.1 支持的中断事件

中断类型 功能描述 典型应用
INT_OVERRUN 数据覆盖(FIFO 溢出) 高速连续采样
INT_WTM FIFO 水位线到达 攒够一批数据再通知 MCU 读取
INT_IA1 / IA2 惯性中断(加速度超阈值) 震动检测、敲击检测、碰撞检测
INT_ZYXDA 新数据就绪 最简单的数据通知
INT_Click 单击 / 双击 TWS 耳机敲击、遥控器按键
INT_FreeFall 自由落体 硬盘保护、跌落记录
INT_6D 6D 方向检测 翻转屏幕、倾倒检测
INT_Sleep 静止检测 设备休眠

7.2 实战:震动/敲击检测

c 复制代码
void lis3dh_config_click_interrupt(void) {
    // --- 第一步:配置中断引脚 ---
    // CTRL_REG3: 使能 INT1 上的 CLICK 中断
    lis3dh_write_reg(0x22, 0x80);   // I1_CLICK = 1

    // --- 第二步:配置单击参数 ---
    // CLICK_CFG (0x38): 使能 Z 轴单击检测
    // (实际应用根据需要选择轴,TWS耳机通常用单轴)
    lis3dh_write_reg(0x38, 0x10);   // ZS = 1 (只检测Z轴)

    // CLICK_SRC (0x39): 只读,触发后读这个看结果

    // CLICK_THS (0x3A): 单击阈值
    // 1 LSB = (量程/128)g,±2g 下 1 LSB ≈ 15.6mg
    // 设 16 → 阈值约 250mg
    lis3dh_write_reg(0x3A, 16);

    // TIME_LIMIT (0x3B): 单击最大时间窗口
    // 1 LSB = 1/ODR,100Hz ODR 下 1 LSB = 10ms
    // 设 10 → 时间窗口 100ms(超过这个时间不算"单击")
    lis3dh_write_reg(0x3B, 10);

    // TIME_LATENCY (0x3C): 两次单击之间的延迟(双击用)
    // 不用双击的话设 0 即可
    lis3dh_write_reg(0x3C, 0);

    // TIME_WINDOW (0x3D): 双击检测总时间窗口
    list3dh_write_reg(0x3D, 0);
}
c 复制代码
// 中断引脚 GPIO 的回调函数
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) {
    if (GPIO_Pin == LIS3DH_INT1_PIN) {
        // 读取中断源,确认是谁触发的
        uint8_t int1_src = lis3dh_read_reg(0x31);
        uint8_t click_src = lis3dh_read_reg(0x39);

        if (int1_src & 0x40) {  // IA bit
            // 惯性中断(震动/运动)
        }
        if (click_src & 0x40) {  // IA bit in CLICK_SRC
            printf("Click detected!\r\n");
            // TWS 切换歌曲、水杯点亮屏幕......
        }
    }
}

7.3 实战:自由落体检测

c 复制代码
void lis3dh_config_freefall(void) {
    // INT1 上输出自由落体中断
    lis3dh_write_reg(0x22, 0x10);   // I1_IA1 = 1

    // INT1_THS (0x32): 自由落体阈值
    // 自由落体时三轴合成加速度 ≈ 0g
    // 设 0x10 → 约 250mg 以下触发(越小越灵敏,但容易误触发)
    lis3dh_write_reg(0x32, 0x10);

    // INT1_DURATION (0x33): 持续时间
    // 1 LSB = 1/ODR,100Hz ODR 下 1 LSB = 10ms
    // 设 10 → 持续 100ms 低于阈值才触发(滤除短时抖动)
    lis3dh_write_reg(0x33, 10);

    // INT1_CFG (0x30): 使能中断逻辑和事件
    // 0x95 = AOI(与逻辑) + ZHIE(使能Z高) + YLIE(使能Y低) + XLIE(使能X低) + XHIE(使能X高)
    // 三轴加速度绝对值都低于阈值时触发
    lis3dh_write_reg(0x30, 0x95);
}

八、低功耗设计 ------ 一颗电池撑一年

8.1 三种工作模式对比

模式 功耗 ODR 适用场景
掉电模式 ~0.5 μA 长期不用的存储/运输状态
低功耗模式 (LP) 2 μA @ 1Hz 1 ~ 5.376 kHz 间歇性检测(30s一次够用了)
正常模式 6 μA ~ 300 μA 1 ~ 5.376 kHz 需要高精度、低噪声的场景
高分辨率模式 (HR) 同上 + 额外滤波 1 ~ 1.344 kHz 精度要求极高的场景

8.2 极致省电方案:FIFO + 间歇唤醒

这是我在智能水杯、物流追踪器上的实战方案:

复制代码
┌──────────────────────────────────────────────┐
│           系统工作周期(如 30 秒)               │
│                                               │
│  ┌── 睡眠 (MCU STOP) ──┐  ┌── 唤醒工作 ──┐   │
│  │                     │  │              │   │
│  │ LIS3DH: 低功耗模式   │  │ LIS3DH:      │   │
│  │ ODR = 10 Hz         │  │ 读 FIFO      │   │
│  │ FIFO 持续灌数据      │  │ 处理数据     │   │
│  │                     │  │ 决定是否报警  │   │
│  │ MCU: 深度睡眠        │  │ 上报/存日志  │   │
│  │ (0.5 μA)            │  │ (几十ms)     │   │
│  └─────────────────────┘  └──────────────┘   │
│                                               │
│  29.9 秒                     0.1 秒           │
└──────────────────────────────────────────────┘

关键代码

c 复制代码
void lis3dh_setup_fifo_stream(void) {
    // FIFO_CTRL_REG (0x2E): Stream 模式
    // 写 0x80 = Stream 模式(满了就盖最老的)
    // 写 0x40 = FIFO 模式(满了停止,防覆盖)
    // 写 0x00 = Bypass 模式(FIFO 不用)
    lis3dh_write_reg(0x2E, 0x80);  // Stream 模式

    // 设置 FIFO 水印中断(比如攒到 25 个点通知 MCU)
    lis3dh_write_reg(0x2E, 0x80 | 25);  // Stream + WTM = 25

    // CTRL_REG3: INT1 输出 FIFO 水印中断
    lis3dh_write_reg(0x22, 0x04);   // I1_WTM = 1

    // 设置低功耗模式 + 低 ODR
    // CTRL_REG1: LP mode + 10 Hz + XYZ 全开
    lis3dh_write_reg(0x20, 0x27);  // 0010 0111 (ODR=10Hz, LPen=1)
}

// 唤醒后读 FIFO
void lis3dh_read_fifo(uint8_t *buf, uint8_t len) {
    // FIFO_SRC_REG (0x2F)
    uint8_t fifo_src = lis3dh_read_reg(0x2F);
    uint8_t stored = fifo_src & 0x1F;  // 存了多少个 sample

    // 每个 sample 5 字节:(OUT_X_L, OUT_X_H, OUT_Y_L, OUT_Y_H, OUT_Z_L, OUT_Z_H)
    // 不对......LIS3DH FIFO 中,每轴两个字节,一共 6 字节/sample
    // 实际读取时,读 OUT_X_L ~ OUT_Z_H 这个连续区域
    for (int i = 0; i < stored; i++) {
        lis3dh_read_regs(0x28, &buf[i * 6], 6);
    }
}

功耗计算结果

工作状态 电流 占比
LIS3DH 低功耗模式 (10 Hz) 10 μA 持续
MCU 深度睡眠 0.5 μA 持续
MCU 唤醒工作(30s一次,100ms) 5 mA 0.33% 占空比
总平均 ≈ 27 μA

一颗 200mAh 的 CR2032 纽扣电池,平均 27μA → 约 308 天。实际上加上 BLE 广播还能撑 6 个月。这就是为什么共享单车的智能锁能用 2 年不换电池------方案对,功耗就是低。


九、数字信号处理 ------ 数据不是读出来就能用的

9.1 原始数据的噪声特征

LIS3DH 的噪声密度在正常模式下约为 220 μg/√Hz。这意味着:

  • 100 Hz 带宽下,RMS 噪声约为 ( 220 \times \sqrt{100 \times 1.6} \approx 2.8 \text{ mg} )
  • 实际数据会有 ±10 mg 左右的抖动(再加上 PCB 振动、电源纹波等)

9.2 常用滤波方法

c 复制代码
// 1. 滑动平均(最简单,最常用)
#define AVG_WINDOW 8
static float x_buf[AVG_WINDOW];
static uint8_t buf_idx = 0;

float lis3dh_moving_avg(float new_val) {
    static float sum = 0;
    sum -= x_buf[buf_idx];          // 减去最老的值
    x_buf[buf_idx] = new_val;       // 存入新值
    sum += new_val;
    buf_idx = (buf_idx + 1) % AVG_WINDOW;
    return sum / AVG_WINDOW;
}

// 2. 一阶低通滤波器(IIR)
// y[n] = α * x[n] + (1-α) * y[n-1]
// α 越小,滤波越强,但响应越慢
float lis3dh_low_pass(float input, float *prev_output, float alpha) {
    *prev_output = alpha * input + (1.0f - alpha) * (*prev_output);
    return *prev_output;
}
// 典型 α 值:
//   计步:α = 0.05 (平滑稳定)
//   碰撞检测:α = 0.5 (响应快)
//   姿态检测:α = 0.1 (适中)

// 3. 静止检测(基于方差)
bool lis3dh_is_stationary(float *buf, int len, float threshold_mg) {
    float mean = 0, variance = 0;
    for (int i = 0; i < len; i++) mean += buf[i];
    mean /= len;
    for (int i = 0; i < len; i++) variance += (buf[i] - mean) * (buf[i] - mean);
    variance /= len;
    return (variance < threshold_mg * threshold_mg);
}

十、校准 ------ 让你的数据真正准确

10.1 零偏校准(Offset Calibration)

MEMS 加速度计出厂时就有零偏误差,加上焊接应力,实际零点可能偏几十甚至上百 mg。

6 面校准法(最精确)

复制代码
把芯片依次放置于 6 个面,每个面读 100 次取平均:

  面 1 (Z 向上):理论值 [0, 0, +1g]
  面 2 (Z 向下):理论值 [0, 0, -1g]
  面 3 (X 向上):理论值 [+1g, 0, 0]
  面 4 (X 向下):理论值 [-1g, 0, 0]
  面 5 (Y 向上):理论值 [0, +1g, 0]
  面 6 (Y 向下):理论值 [0, -1g, 0]

对 X 轴:
  实际+1g 读数 = X_plus
  实际-1g 读数 = X_minus
  → offset_X = (X_plus + X_minus) / 2
  → scale_X  = (X_plus - X_minus) / 2 / 1000  (mg/LSB, 理论值=1)
c 复制代码
typedef struct {
    float offset_x, offset_y, offset_z;
    float scale_x, scale_y, scale_z;
} lis3dh_calib_t;

void lis3dh_apply_calibration(int16_t *x, int16_t *y, int16_t *z,
                               lis3dh_calib_t *cal) {
    *x = (int16_t)((*x - cal->offset_x) / cal->scale_x);
    *y = (int16_t)((*y - cal->offset_y) / cal->scale_y);
    *z = (int16_t)((*z - cal->offset_z) / cal->scale_z);
}

10.2 生产线上怎么快速校准?

  • 工装夹具:做一个六面翻转工装,自动走位
  • 省流版:只做 2 面(Z 轴向上和向下),因为大多数设备主要用 Z 轴的姿态检测
  • 自校准:如果设备可以旋转(如手机),用户日常翻转就是天然的校准数据

十一、常见坑和调试大全

坑1:WHO_AM_I 读到 0xFF 或 0x00

原因

  • I²C 地址不对(0x18 vs 0x19?用万用表量 SA0 电平)
  • I²C 上拉电阻太弱(4.7kΩ 是最佳值,10kΩ 勉强,不要用 100kΩ)
  • 芯片没供电(量 VDD 和 VDD_IO)
  • CS 引脚浮空(必须接 GND 才能进 I²C 模式!)

坑2:数据正常但总是有 ±100mg 的固定偏移

原因

  • PCB 倾斜或弯曲(板子翘了 1°,Z 轴就多 cos(1°)×1g ≈ 略小于 1g,但可能出现 X/Y 轴有几十 mg 的分量)
  • 焊接应力(回流焊时不均匀的降温)
  • 芯片附近有磁铁(扬声器、马达磁铁、耳机磁钢)

对策:必须做零偏校准(见第十章)。

坑3:Z 轴数据开立方根式抖动

原因:电源去耦不够。LIS3DH 内部有电荷泵,电感的瞬间电流会通过 GND 反弹回来。

对策

  • 100nF + 10μF 去耦必须靠近芯片
  • I²C 走线远离 DC-DC 电感和 PWM 走线
  • 必要时给 LIS3DH 独立供电(一个小的 LDO 单独给它)

坑4:低功耗模式数据完全不更新

原因:LP 模式(CTRL_REG1 bit3)必须和对应的 ODR 配合使用,某些 ODR 值在 LP 模式下不支持,数据会"卡住"。

对策:严格按数据手册的 ODR 表选择参数。不确定的话,先在正常模式下跑通,再切低功耗。

坑5:中断引脚反复触发,MCU 被"淹死"

原因

  • 中断没有及时清除(读相关状态寄存器才会清除)
  • 中断触发条件设得太宽(震动阈值太低,环境噪声就能触发)
  • 中断配置了"锁存"模式,需要读 INT1_SRC 清除

对策

c 复制代码
// 中断服务函数中务必读取状态寄存器
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) {
    if (GPIO_Pin == LIS3DH_INT1_PIN) {
        // 读 INT1_SRC 会清除锁存器
        uint8_t src = lis3dh_read_reg(0x31);

        // 根据 src 的 bit 判断是什么事件
        if (src & 0x40) { /* IA 中断 */ }
        if (src & 0x08) { /* 数据就绪 */ }

        // 如果还配了双击中断,也要读 CLICK_SRC
        // uint8_t click = lis3dh_read_reg(0x39);
    }
}

坑6:加速度值在量程边界"饱和"------数据不增长

现象:用手摇设备,读数卡在 +2g 不往上涨了。

原因:量程设得太小(±2g)。摇晃时加速度可能达到 3~4g。

对策

  • 碰撞/震动类应用 → 至少 ±8g
  • 如果 ±16g 还不够用 → LIS3DH 不适合你,去看 LIS2DW12(±16g)或 IIS3DWB(±128g 超大量程)

坑7:批量生产时一致性差

现象:同一条产线,A 台读数 ±10mg 以内,B 台偏了 80mg。

原因

  • 焊接应力每片板子不一样(回流焊的升降温曲线、PCB 板材批号差异)
  • 不同批次的 LIS3DH 零偏初始值不一样

对策

  • 产线上每台都做 1 点校准(至少 Z 轴向上校准一次,读出 offset_z 存入 Flash)
  • PCB 拼板时在芯片下方加"应力释放槽"(一条窄槽沿芯片轮廓边缘)

十二、替代选型速查

型号 厂家 vs LIS3DH 适用
LIS2DW12 ST 功耗更低(0.38μA@1Hz)、噪声更低、FIFO更大(512级) 新一代低功耗设计
LIS2DH12 ST 与 LIS3DH 软件兼容,封装兼容,功耗略低 LIS3DH 的"顺位替代"
ADXL345 ADI 功耗高但精度更高、量程±16g 工业/高精度场景
MMA8451Q NXP 类似规格,寄存器更简单 北美供应链首选
KXTJ3-1057 Kionix 超小封装 2×2mm,极低功耗 真无线耳机、极致空间
BMI160 Bosch 6 轴(Accel+Gyro),惯性导航 需要角速度的场景
QMA6100P 矽睿科技 国产替代,性价比极高 成本敏感、国产化要求

十三、总结与心法

LIS3DH 是一颗"老派"的芯片------它没有追最新最先进的指标,也没有动不动 μA 以下的神仙功耗。但它的稳定性、可靠性、供货能力、生态成熟度,是市面上大多数新品比不了的。

给年轻工程师的三条心法:

  1. 先读 WHO_AM_I,再谈其他。通信不通,后面全是白费劲。0x33 读到的那一刻,项目就成功了一半。

  2. 善用中断,别死轮询。LIS3DH 的精华就是那两颗中断脚------新数据、震动、自由落体、敲击、翻转......全部可以用中断通知 MCU。MCU 安心睡觉,有事才唤醒。这才是低功耗系统的正确打开方式。

  3. 功耗大头永远不在传感器。LIS3DH 最低能跑到 2μA,你的 MCU、你的蓝牙、你的显示屏才是耗电大户。先优化系统架构(谁该睡、谁该醒、多久醒一次),再抠传感器的细节。

核心要点回顾:

  1. 应用场景:TWS耳机、手环手表、共享单车锁、车载T-Box、智能水杯、安防防盗、跌倒检测------凡是需要"感知运动和姿势"的地方,都能见到它的身影
  2. 接口:I²C(地址 0x18/0x19)+ SPI
  3. 量程:±2/4/8/16g 可选,根据应用场景定
  4. 功耗:最低 2μA @ 1Hz,纽扣电池能撑一年
  5. 中断:INT1 + INT2,支持新数据就绪、震动/敲击、自由落体、6D方向、FIFO水印等多种事件
  6. FIFO:32级,配合低功耗间歇采样,进一步省电
  7. 校准:批量生产时必须做零偏校准,焊接应力不可忽视
  8. 滤波:滑动平均 + 低通滤波组合,消除噪声同时保持响应速度


参考与延伸阅读

  • ST LIS3DH 官方数据手册(Doc ID: CD00274266)
  • ST AN3308:LIS3DH 应用笔记(中断配置、6D 检测)
  • ST AN4508:LIS3DH FIFO 使用指南
  • ST MEMS 校准指南(6 面校准详细步骤)
  • ST GitHub:STMems_Standard_C_drivers(官方驱动库,直接拿来用)
相关推荐
zcmodeltech2 小时前
化工装置沙盘模型多设备协同控制系统设计:基于STM32与Modbus RTU的装置-流程-安全联动方案
大数据·stm32·嵌入式硬件·安全·unity·制造
coward912 小时前
千兆以太网卡(Ethernet)驱动初始化完成,但是无法udhcpc获取ip
服务器·网络·嵌入式硬件·tcp/ip
Tyfrank2 小时前
Linux内核收包路径及中断
linux·运维·单片机
csdn杰哥3 小时前
瑞萨单片机开发教程[二十六] DMAC 存储器数据传输实验
单片机·嵌入式硬件·mongodb·瑞萨·ra6m5
求知喻3 小时前
串口中断模式
单片机·嵌入式硬件
ACP广源盛139246256733 小时前
GSV6155@ACP# Type-C 视频信号转换芯片:技术架构、工程痛点适配与落地场景分析
大数据·c语言·开发语言·人工智能·分布式·嵌入式硬件·架构
光子物联单片机3 小时前
STM32传感器模块编程实践(二十一)DIY语音控制小车套件模型
c语言·stm32·单片机·嵌入式硬件·mcu
csdn杰哥3 小时前
瑞萨单片机开发教程[二十八] DTC 串口传输实验
单片机·嵌入式硬件·瑞萨·ra6m5
义嘉泰3 小时前
【硬核拆解】540×540时代的显示核心:集创北方 CO6300 AMOLED驱动芯片深度解析
嵌入式硬件·芯片