资讯详情

资讯详情

LIS2DH12TR与LIS3DH加速度计:低功耗运动检测与驱动避坑指南

简介ST官方应用笔记AN4509面向使用LIS2DH12TR、LIS3DH等低g三轴加速度计的嵌入式开发与传感器应用工程师系统讲解倾斜检测原理与倾斜角测量方法覆盖屏幕旋转、汽车安全报警、电子罗盘倾斜补偿等典型场景。压缩包内为单个PDF文件大小约619KB无冗余内容便于快速下载与查阅。该笔记已有1758人学习下载适合消费电子、工业传感及便携导航等领域的硬件与固件开发人员参考。内容从重力加速度在各轴上的映射原理入手详细推导单轴、双轴、三轴倾斜检测的数学计算并给出不同角度的灵敏度对比例如接近垂直时灵敏度约0.15 mg/°、水平附近约17.45 mg/°帮助设计者避开低灵敏区同时针对传感器噪声、温度漂移和非线性响应介绍了校准与滤波等非理想因素补偿策略。应用笔记还包含版本历史与图表目录工程实践指导价值较强。1. LIS2DH12TR 与 LIS3DH这两颗加速度计低功耗运动检测怎么选怎么做做电池供电的便携设备时我习惯在选型阶段先把加速度计的空闲电流拉出来比一遍。LIS2DH12TR 和 LIS3DH 这两颗三轴加速度计经常被拿来做低功耗运动检测、倾斜唤醒和计步但它们的寄存器几乎相同实际用起来却有不少差异。这颗 LIS2DH12TR 后缀里的 TR 只是卷带包装标识芯片本身比 LIS3DH 更小、低功耗档位更细LIS3DH 则是被验证过多年的经典款周边资料多寄存器行为大家更熟悉。这篇笔记不是数据手册的翻译而是把我在某可穿戴项目上从初始化、中断唤醒、FIFO 到倾角计算这一路踩过的坑整理出来。新手可以照代码跑通第一版驱动熟手可以直接跳到避坑章节看参数边界。2. 寄存器模型与选型LIS3DH 和 LIS2DH12TR 谁适合你的板子2.1 量程、分辨率与 BDU输出数据如何换算成 g这两颗芯片的寄存器地址几乎一一对应核心寄存器从 0x20 的 CTRL1 开始到 0x28 起的 OUT_X_L 三轴输出。读取加速度时芯片以 2 的补码形式输出 6 个字节X、Y、Z 各占 2 个字节。分辨率取决于 CTRL4 里的 HR 位和 CTRL1 里的 LPen 位组合normal 模式是 10 位有效数据high-resolution 模式是 12 位有效数据low-power 模式是 8 位有效数据。输出数据统一左对齐放在 16 位寄存器的高位低位补 0所以读出来以后要按你实际用的模式右移对应的位数。量程由 CTRL4 的 FS1、FS0 两位决定四档分别是 ±2g、±4g、±8g、±16g。量程直接影响换算系数同一份原始数据在不同量程下代表的物理加速度完全不同这是新手最容易写错的地方。以 ±2g 高分辨率模式为例典型灵敏度接近 1 mg/LSB也就是原始值 1000 附近对应 1g转换起来非常方便。如果切到 ±16g同一份读数代表的重力值就小了好几倍所以代码里必须把量程做成可配置项不能写死。BDU 位在 CTRL4 的 bit7名字叫 block data update作用是冻结输出寄存器更新。没有它你在读低字节和高字节的间隙芯片可能刚好更新了数据导致拼出来的 16 位值来自两个不同时刻的采样。虽然这个窗口很小但运动检测里偶尔跳一个毛刺就很难查所以我习惯一上来就把 BDU 置 1。下面是读取三轴原始值并右移对齐的最小实现#define LIS_I2C_ADDR 0x18 // SDO 接地时的地址SDO 拉高则为 0x19 #define LIS_OUT_X_L 0x28 // 三轴输出起始寄存器 static int8_t lis_read_raw(int16_t out[3]) { uint8_t buf[6]; // 从 0x28 连续读 6 字节芯片支持自动递增寻址 if (i2c_read_regs(LIS_I2C_ADDR, LIS_OUT_X_L, buf, 6) ! 0) return -1; for (int i 0; i 3; i) { int16_t v (int16_t)((buf[i * 2 1] 8) | buf[i * 2]); v 4; // 12bit 有效数据左对齐右移舍弃低 4 位 out[i] v; } return 0; }这段代码假设你已经有了一个多字节读函数i2c_read_regs第一个参数是 7 位设备地址第二个参数是起始寄存器第三个是接收缓冲区第四个是长度。LIS2DH12TR 和 LIS3DH 的 I2C 地址都支持 SDO 引脚选择接地为 0x18拉高为 0x19。多字节读的自动递增是默认行为不需要额外配置但前提是你的 I2C 控制器在 repeated START 之后还能保持寄存器地址不变有些 MCU 的 I2C 外设读多字节时会自动把地址加 1这时候就要改成逐个字节读再自己拼。右移 4 位只适用于高分辨率模式如果你在 normal 模式有效位是 10 位应该右移 6 位low-power 模式 8 位右移 8 位。把模式做成宏定义避免三处代码各写各的。2.2 ODR 与功耗low-power 模式下的配置差异ODR 全称是 output data rate也就是输出数据速率配置在 CTRL1 的高 4 位。LIS3DH 和 LIS2DH12TR 都支持从 1 Hz 到 5 kHz 左右的多个档位常用的是 10 Hz、25 Hz、50 Hz、100 Hz、200 Hz。ODR 决定的是数据更新频率不是中断响应速度这两个概念经常被混在一起。运动检测唤醒场景里ODR 越低功耗越小但你要接受检测延迟ODR 越高越灵敏代价是电流直线上升。我一般会把常态 ODR 设在 25 Hz 到 50 Hz等中断触发后再切换到 100 Hz 以上做精细采集。LIS2DH12TR 相比 LIS3DH 的一个重要变化是低功耗模式做得更细。LIS3DH 的低功耗模式主要靠 CTRL1 的 LPen 位拉低内部功耗LIS2DH12TR 在同样 ODR 下多了几档可选的省电配置对电池供电的设备来说多省下来的那几微安可能就是待机时间差一个星期的来源。实际选型时我不只看数据手册首页的电流数值而是看同 ODR、同量程、同分辨率条件下的电流对比因为这三者都会影响功耗表现。高分辨率模式比普通模式费电这是正常的不能拿不同配置下的数据放在一起比较。LIS2DH12TR 比 LIS3DH 晚出同样功能下封装更小这对面积紧张的 TWS 耳机、手环主板很有吸引力。但小封装也带来两个实际问题一是 PCB 上走线和器件距离更近电源噪声更容易耦合进模拟前端二是焊接后底部填充和助焊剂残留更难清理返修时热风枪吹久了容易把内部悬臂烤变形。相比之下 LIS3DH 的封装大一点手工焊接和飞线调试都更友好做原型验证阶段我会优先选 LIS3DH等方案定型要压面积了再换 LIS2DH12TR。2.3 引脚与中断映射LGA16 与 LGA12 的板级差别LIS3DH 和 LIS2DH12TR 虽然寄存器高度兼容引脚定义却不是一一对应的。LIS3DH 的封装外形明显大一圈引脚数量更多LIS2DH12TR 把电源、地、I2C 和中断脚压缩在更小的尺寸上。硬件移植时不能只对着原理图说“寄存器一样就硬接”要逐个引脚核对功能。比如中断输出脚 INT1 和 INT2两个型号都有但中断源映射到哪个脚由 CTRL3 和 CTRL6 决定配置前先看原理图确认 INT1 接在 MCU 的哪个 GPIO别把中断使能写到了没接线的那个脚上。I2C 上拉电阻也是板级设计里容易翻车的地方。这两颗芯片是开漏输出SDA 和 SCL 必须有外部上拉上拉电阻的大小取决于总线上的器件数量和走线长度。我常用 4.7 kΩ如果总线上挂了多个器件、走线超过 10 cm就降到 2.2 kΩ 再量一下上升沿时间。上拉电阻太小会让低电平拉不下去太大则导致上升沿太缓在 400 kHz 快速模式下尤其明显。还有一个细节是 SDO 脚它在 I2C 模式下只用来选地址不能悬空悬空时电平不确定地址可能在 0x18 和 0x19 之间随机这是读不到传感器的一个隐藏原因。芯片工作电压在 1.71 V 到 3.6 V 之间如果你的 MCU 是 5 V 供电I2C 上拉必须接到传感器的 VDD 而不是 MCU 的 5 V不然会超过引脚耐压。// BDU ±2g HR 模式的典型配置 static void lis_init(void) { i2c_write_reg(LIS_I2C_ADDR, 0x20, 0x57); // CTRL1: 100Hz, 三轴使能 i2c_write_reg(LIS_I2C_ADDR, 0x23, 0x88); // CTRL4: BDU1, ±2g, HR1 }0x23 写成 0x88 的位展开是 BDU1、FS00、HR1。LSB 的 bit0 SIM 保持 0走 I2C如果用 SPI 四线模式这里才需要改。CTRL1 的 0x57 是 ODR100 Hz、LPen0、三轴全部使能。如果你要更低功耗把 ODR 档位降下来比如 25 Hz 对应 0x3710 Hz 对应 0x27。这两个寄存器写完之后最好读回来确认一次防止 I2C 总线上的毛刺把配置字节吃掉。3. 初始化与数据读取最小驱动代码的每一步3.1 先写 I2C 读写封装地址、寄存器与多字节读无论 LIS2DH12TR 还是 LIS3DH驱动代码的地基都是两个函数写寄存器和读寄存器。芯片的 I2C 协议很直接写的时候先发设备地址加写位再发寄存器地址最后发数据字节。读的时候要先发送寄存器地址然后重新产生 START 条件再发设备地址加读位连续读多个字节。寄存器地址不会自动递增到下一个字节以外的范围所以一次最多读六字节输出数据就够了。下面是我常用的封装注释里写清了时序顺序static int8_t i2c_write_reg(uint8_t addr, uint8_t reg, uint8_t val) { uint8_t buf[2] { reg, val }; return i2c_write(addr, buf, 2); // 你的 HAL 层写函数 } static int8_t i2c_read_regs(uint8_t addr, uint8_t reg, uint8_t *buf, uint8_t len) { i2c_write(addr, reg, 1); // 先写寄存器地址 return i2c_read(addr, buf, len); // 再读数据 }注意这里的i2c_write和i2c_read是理想要素实际项目中你要替换成自己工程里的 HAL 函数。芯片地址是 7 位地址不包含读写位0x18 已经是去掉最低位的值如果你用的是带了读写的 8 位地址形式I2C 写地址是 0x30读地址是 0x31别搞混。MCU 的 I2C 外设有的会自动处理 repeated START有的需要手动设置一个控制位如果你的平台在连续读时读出来的第一个字节是上一个操作的残留数据多半是 repeated START 没生效。我建议调试时先把 WHO_AM_I 读出来这一步通了再继续往下走。3.2 初始化序列CTRL1 与 CTRL4 的位级解释初始化配置的核心就两个寄存器但它们的位含义牵一发动全身。CTRL1 的 bit7 到 bit4 是 ODRbit3 是 LPenbit2 到 bit0 分别是 Z、Y、X 轴的使能位。三轴使能位看起来是常识但如果只开了 X 轴Y 和 Z 输出会被读成 0而且这个 0 是真实输出不是错误你很难察觉。我见过有人排查了半天数据跳变最后发现是使能位写错导致某根轴悬浮。CTRL4 的 bit7 BDU、bit6 BLE、bit5 和 bit4 是量程、bit3 是 HR、bit2 和 bit1 是自检位、bit0 是 SPI 模式选择。自检位平时必须保持 00如果不小心写成了 01 或 10输出数据会叠加上一个固定偏移静止读数也会偏出去一大截。初始化顺序也有讲究。先把传感器从掉电模式唤醒也就是写好 CTRL1 让芯片开始采样再配置量程和 BDU最后去读数据。反过来先配 CTRL4 再写 CTRL1 也能工作但第一次上电时 WHO_AM_I 能读、输出却全 0 的情况多半是 CTRL1 还没把轴使能起来。如果你用的是别人的初始化代码片段务必看一下有没有把 CTRL1 的使能位漏掉。下面是完整初始化包含状态寄存器清零static void lis_init(void) { // 复位 FIFO 和相关状态防止上电残留数据 i2c_write_reg(LIS_I2C_ADDR, 0x0E, 0x00); // CTRL0? 实际复位用软复位或读 STATUS i2c_read_regs(LIS_I2C_ADDR, 0x27, st, 1); // 读 STATUS 清状态位 i2c_write_reg(LIS_I2C_ADDR, 0x20, 0x57); // CTRL1: 100Hz, 三轴使能 i2c_write_reg(LIS_I2C_ADDR, 0x23, 0x88); // CTRL4: BDU1, ±2g, HR1 i2c_write_reg(LIS_I2C_ADDR, 0x24, 0x00); // CTRL5: 关闭 FIFO 相关中断 }初始化里最后清一次 STATUS 寄存器是很多人不会注意的细节。STATUS 位包括 ZYXOR 溢出标志和 ZYXDA 数据可用标志上电后可能残留旧的置位不清掉的话第一次读输出会和第二次读输出混在一起。CTRL5 我习惯显式写 0防止上电随机值把 FIFO 中断或 INT1 引脚映射到意外状态。这里没有软复位寄存器是因为这两颗芯片的软复位行为因型号略有差异最简单可靠的做法是掉电重启如果条件不允许就把所有用到的寄存器都显式写一遍初值。3.3 读取 X/Y/Z 并转成 mgBDU 与右移对齐数据读取我在 2.1 已经给了核心代码这里补上完整的物理量换算。读数转 mg 的公式很简单原始值除以该配置下的灵敏度再乘 1000。±2g 高分辨率模式下灵敏度约 1 mg/digit所以原始值就是毫 g 数1g 对应读数 1000。换到 ±4g 高分辨率模式灵敏度变成约 2 mg/digit±8g 是约 4 mg/digit±16g 是约 12 mg/digit。这些值在数据手册里都有表格我不建议背但建议把灵敏度做成一张表放在代码里按量程自动选择免得每次手动换算。typedef struct { int16_t x; int16_t y; int16_t z; } lis_axis_t; // 量程对应的灵敏度单位 mg/digit static const uint16_t lis_sensitivity_mg[4] { 1, 2, 4, 12 }; static float lis_read_x_mg(uint8_t fs_index) { int16_t raw[3]; if (lis_read_raw(raw) ! 0) return 0.0f; return (float)raw[0] * lis_sensitivity_mg[fs_index]; }这只是一个示意实际工程里建议一次读回三轴再换算不要调三次读取函数因为三次读取之间数据已经更新了组合出来的向量没有意义。BDU 开了以后单轴读取虽然不会读错但三轴之间的时间一致性还是要靠一次多字节读保证。换算结果如果要用于倾角计算保留 float 精度如果只是为了看运动强度用整型计算平方和就够了浮点运算在低功耗 MCU 上会拉高中断处理时间。4. 低功耗唤醒、运动检测与 FIFO把中断用起来4.1 运动检测唤醒配置INT1_CFG、INT1_THS 与持续时间设备休眠时加速度计可以保持运行检测到运动后通过中断脚唤醒 MCU这是这两颗芯片最常用的场景。中断路径分两层第一层是 INT1_CFG 配置触发条件第二层是 INT1_THS 和 INT1_DURATION 配置阈值和持续时间。INT1_CFG 的 AOI 位决定条件是 AND 还是 ORbit5 到 bit0 分别对应 Y 轴高阈值、Y 轴低阈值、X 轴高阈值、X 轴低阈值等。做运动唤醒时我一般用 OR 组合即三轴任意一轴超过阈值就算运动配置值常见为 0x2F。// 开启 INT1 运动唤醒阈值约 30~40mg 量级具体看寄存器分辨率 i2c_write_reg(LIS_I2C_ADDR, 0x22, 0x40); // CTRL3: 使能 AOI1 到 INT1 i2c_write_reg(LIS_I2C_ADDR, 0x30, 0x2F); // INT1_CFG: 三轴 OR 高/低阈值 i2c_write_reg(LIS_I2C_ADDR, 0x32, 0x0A); // INT1_THS: 阈值码值 i2c_write_reg(LIS_I2C_ADDR, 0x33, 0x02); // INT1_DURATION: 持续 2 个采样周期INT1_THS 的码值和实际阈值的换算跟量程以及分辨率模式有关最简单的办法是先写一个中间值然后用示波器量 INT1 引脚晃动板子看中断持续时间再反向调整码值。阈值写太大会导致只有剧烈晃动才触发写太小则会被电源噪声和振动台干扰误触发。INT1_DURATION 的作用是防抖它要求加速度连续超过阈值规定的采样周期数才真正触发中断对拿在手里轻微抖动的人来说这个值设 1 到 3 比较合适。中断触发后 INT1_SRC 会锁存中断状态读一次这个寄存器就能清除锁存否则中断脚一直保持有效电平MCU 会陷入中断风暴。这一点在手册里写得很清楚但实际调试时十有八九会忘。4.2 FIFO 批量搬运Stream 模式与水位中断FIFO 是这两颗芯片给低功耗系统准备的数据缓冲深度 32 级每一级完整保存一组三轴数据。它的价值在于减少 MCU 唤醒频次如果按 25 Hz 采集每 40 ms 读一次CPU 频繁醒来如果开 FIFO 并设满 16 级再中断MCU 每 640 ms 才醒一次其他时间睡大觉。FIFO 模式在 FIFO_CTRL 寄存器里配置bits7-6 选模式bit5-0 是水位阈值。Stream 模式适合持续采集满了覆盖最老的数据FIFO 模式适合触发采集存满就停。配置 FIFO 还有一个前提要把 FIFO 中断使能打开映射到 INT1 或 INT2 引脚// Stream 模式水位 16 组数据 i2c_write_reg(LIS_I2C_ADDR, 0x2E, 0x90); // FIFO_CTRL: Stream, FTH16 // CTRL5 bit6 置 1 使能 FIFOCTRL3 映射到 INT1 i2c_write_reg(LIS_I2C_ADDR, 0x24, 0x44); // CTRL5: FIFO 中断使能 i2c_write_reg(LIS_I2C_ADDR, 0x22, 0x02); // CTRL3: INT1 上输出 FIFO 中断FIFO_CTRL 的 0x90 是 10 对应当前模式选择 Stream0x10 是水位 16。注意 0x90 的低五位是水位0x10 是 16所以 0x90 不能写成 0x40那是 FIFO 模式加水位 0。FIFO 满了之后状态可以从 FIFO_SRC 读出来FIFO_SRC 的 bit5 是水位状态标志bit4 是满标志读 FIFO_SRC 同时会把复位 FIFO 的指针方便下一轮重新填。实际调试时如果发现读到的数据是历史数据先确认 FIFO 是不是没在 Bypass 模式下被上一次运行残留填满了。4.3 点击检测低成本交互的另一条路点击检测是这两颗芯片的隐藏功能单双击识别可以省掉一颗触摸 IC。配置位于 CLICK_CFG 等一组寄存器核心思路是芯片内部检测加速度的短时脉冲超过阈值且时间窗内不再触发第二次就算一次单击。双击则是第一次点击后的规定时间窗口内再出现一次合法点击。它对手持设备的误触发比较敏感需要仔细调 CLICK_THS、TIME_LIMIT、TIME_LATENCY 和 TIME_WINDOW 四个参数我建议用正弦摆动台或手指敲击录制波形来标定。// 单击检测X/Y/Z 各自独立使能 i2c_write_reg(LIS_I2C_ADDR, 0x38, 0x77); // CLICK_CFG: 三轴单击使能 i2c_write_reg(LIS_I2C_ADDR, 0x39, 0x08); // CLICK_THS: 点击阈值 i2c_write_reg(LIS_I2C_ADDR, 0x3A, 0x10); // TIME_LIMIT: 点击最大时长 i2c_write_reg(LIS_I2C_ADDR, 0x3B, 0x20); // TIME_LATENCY: 双击间隔下限点击检测中断同样通过 INT1 或 INT2 输出需要读 CLICK_SRC 确认是单击还是双击并清除状态。这个功能的坑在阈值标定不同的人握持习惯会产生完全不同的加速度波形生产时要留出足够的余量否则用户轻轻一碰就触发或者在桌面上放手机也会因为振动误触发。我一般会先把加速度原始数据用串口打出来看看一次真实点击的峰值是多少再设阈值到峰值的一半。5. LIS2DH12TR/LIS3DH 常见问题排查五个现场踩坑记录5.1 现象读 WHO_AM_I 失败I2C 无 ACK读 0x0F 寄存器返回 0xFF 或者 I2C 直接报错这是所有驱动联调的第一道坎。原因集中在三个方向一是设备地址配错0x18 和 0x19 取决于 SDO 脚电平原理图上看一眼就能确认二是 SDA 或 SCL 没有上拉示波器看波形是一条被拉低到地的直线三是 MCU 的 I2C 引脚被复用成了其他外设功能初始化时机冲突导致引脚电平不对。解决方法是先量 SDO 电平再查上拉最后用逻辑分析仪看地址帧的第一个字节是不是 0x30 和 0x31。这个排查顺序能覆盖九成无 ACK 场景。5.2 现象三轴输出全部是 0STATUS 却显示数据可用数据可用标志正常读出来的三轴原始值却恒为 0这个问题最隐蔽的原因是 CTRL1 里的三轴使能位没写对。芯片工作在掉电模式时轴使能为 0输出寄存器保持在 0 值STATUS 的 ZYXDA 会显示没有新数据或保持旧状态。还有一类原因是 FIFO 开启后没有正确读完数据FIFO 水位的状态没清上层读到的是空数据。解决方法是回读 CTRL1 确认 bit2 到 bit0 是不是 0x07再检查 FIFO_CTRL 的 mode 是不是在 Bypass如果之前配了 FIFO 模式先写回 0x00。5.3 现象运动唤醒中断只触发一次之后再也不动中断脚第一次有效服务函数里处理完业务后第二次晃动板子中断不再来。这是典型的中断锁存未清除。INT1_SRC 寄存器在触发后会锁存事件直到主机读取它才会复位不清除锁存INT1 引脚电平会一直被拉低或保持高MCU 对应 GPIO 的中断触发沿检测就失效了。解决方法是每次进入中断服务函数时无条件读一次 INT1_SRC并把读到的值保存用于判断是哪一类事件然后置一个标志位给主循环处理。如果用了脉冲模式而不是锁存模式这个现象不会出现但我建议保持锁存模式方便排查。5.4 现象静止时 Z 轴读数不是 1gX/Y 轴有明显偏置把板子水平放在桌面上Z 轴读数应该在 1g 附近X 和 Y 接近 0。如果偏差很大先确认是不是焊接应力导致封装内部悬臂变形这种机械应力贴片后很难消除只能通过软件校准吸收。软件方法很简单静止状态下采集 100 次取平均得到 X、Y、Z 的偏移量再把每次读数减去偏移量。校准完成后Z 轴的偏移量还包含重力分量需要再减去当地重力加速度对应的读数才能得到真正的传感器零偏。这个零偏会随温度漂移要求高的场景要配合温度补偿不过对大多数消费类场景来说常温校准一次已经够用。5.5 现象数据毛刺多静止读数偶尔跳一个大值毛刺在时域上表现为一个孤立的大幅跳变在频谱上表现为宽频噪声。现象背后通常是三种情况电源退耦不充分I2C 总线上的开关噪声耦合进电源SPI 模式下 CS 脚悬空导致芯片误进入 SPI 状态或者 MCU 在读数据时刚好碰到内部采样更新。解决方法第一优先是加 0.1 μF 和 1 μF 陶瓷电容紧贴传感器的 VDD 引脚第二检查 CS 脚有没有被拉死没有用 SPI 就把它接固定电平第三确认 BDU 是否打开。高频毛刺还可能来自 PCB 走线的天线效应特别是 LIS2DH12TR 这种小封装走线过长的区域需要包地处理。6. 进阶验证技巧倾角计算与自检怎么确认你的驱动没写错倾角计算是把加速度计的静态输出变成设备姿态的最直接方法。当设备没有线性加速度时加速度计测到的是重力向量在三个轴上的分量通过反三角函数就能还原俯仰角和横滚角。下面这个实现用了atan2f它对四个象限的处理比atan更稳避免在 90 度位置出现符号错误#include math.h static void lis_angle(float ax, float ay, float az, float *pitch, float *roll) { // 俯仰角绕 Y 轴旋转用 X 轴和 YZ 平面的合成量计算 *pitch atan2f(-ax, sqrtf(ay * ay az * az)) * 180.0f / 3.14159f; // 横滚角绕 X 轴旋转用 Y 轴分量计算 *roll atan2f(ay, sqrtf(ax * ax az * az)) * 180.0f / 3.14159f; }这个公式在设备基本水平时精度不错但在大角度俯仰下横滚角会失真因为重力在 X 轴上的分量影响了横滚的几何关系。如果你要全姿态解算就要引入四元数或者更复杂的旋转矩阵加速度计只负责提供重力参考陀螺仪负责短时积分。倾角输出对器件噪声很敏感我会先对原始数据做 3 到 5 点的滑动平均再算角度否则屏幕上的角度值会一直抖。验证时把设备放在已知角度的斜面上对比角度读数误差在正负 1 度以内算合格。自检位是产线上验证传感器有没有损坏的重要手段。把 CTRL4 的 ST 位临时设为 01传感器内部会施加一个已知方向的静电力让输出产生正向偏移设为 10 则产生负向偏移。这个偏移量在数据手册里有范围实际做法是先正常模式读 10 次取均值再开自检读 10 次取均值两者相减看差值是否落在手册范围。如果差值明显偏小或接近零说明内部悬臂可能断裂或粘连直接判为不良。测完一定把 ST 位恢复为 00否则出货前每颗设备的读数都带偏置后台会收到一堆“校准不过”的返修单这个教训我不希望你重演。整个驱动的置信度我习惯用三步确认WHO_AM_I 通、静止 Z 轴读数接近 1g、自检差值在范围里。三步都过了代码才会交到产线手上。希望帮到你。本文还有配套的精品资源点击获取
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →