You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用SMBus/I2C读取LSM9DS1加速度传感器寄存器返回固定值问题

LSM9DS1加速度计寄存器读值固定问题排查与修复

问题根因

  • 你没有对传感器做任何初始化配置:LSM9DS1上电默认进入掉电休眠模式,加速度计采样电路完全停止工作,三个轴的输出寄存器不会随姿态变化更新,只会返回固定的默认值,这是读值完全不变的核心原因。你能稳定读到固定值,反而说明I2C硬件连接、基础读寄存器操作是正常的,不存在通信故障。
  • 代码存在冗余问题:smbus版本中你把SMBus(1)实例初始化放在了循环内部,每次读值都重新创建I2C连接,会浪费系统资源,应当移到循环外只初始化一次。
  • 字节拼接注意:你定义的OUT_X_XL1(0x28)是X轴加速度低8位寄存器,OUT_X_XL2(0x29)是高8位寄存器,拼接16位原始值时不要搞反高低字节顺序。

修复方案

在开始读输出寄存器之前,先向传感器的两个控制寄存器写入配置值,启动加速度计采样:

  1. 向CTRL_REG5_XL(0x1F)写入0x38:使能X/Y/Z三个轴的加速度输出,使用默认±2g量程。
  2. 向CTRL_REG6_XL(0x20)写入0x60:配置加速度计为正常功耗模式,输出数据率119Hz,退出掉电状态。

配置完成后等待10ms让传感器稳定,再开始读输出寄存器即可拿到随姿态变化的动态值。

原始值转物理加速度的方法

  1. 拼接16位原始值:以X轴为例,raw_x = (acc_x_high << 8) | acc_x_low,Y、Z轴逻辑一致。
  2. 补码转有符号整数:16位二进制补码的取值范围是-32768~32767,如果拼接后的值大于等于32768(即0x8000),减去65536(即0x10000)即可得到对应的有符号整数。
  3. 换算为物理单位:默认±2g量程下,传感器灵敏度为0.061mg/LSB,即每个原始计数对应0.000061g,将有符号原始值乘以该系数,就能得到单位为g的浮点型加速度值。如果后续修改了量程,直接替换为对应量程的灵敏度系数即可。

修正后的smbus版本参考代码

from smbus import SMBus
import time

# 加速度计I2C地址
ACC_ADDR = 0x1c

# 寄存器定义
OUT_X_L_XL = 0x28
OUT_X_H_XL = 0x29
OUT_Y_L_XL = 0x2A
OUT_Y_H_XL = 0x2B
OUT_Z_L_XL = 0x2C
OUT_Z_H_XL = 0x2D
CTRL_REG5_XL = 0x1F
CTRL_REG6_XL = 0x20

def main():
    i2cbus = SMBus(1)
    # 初始化传感器
    i2cbus.write_byte_data(ACC_ADDR, CTRL_REG5_XL, 0x38)  # 使能三轴
    i2cbus.write_byte_data(ACC_ADDR, CTRL_REG6_XL, 0x60)  # 配置ODR、退出掉电
    time.sleep(0.01)  # 等待传感器稳定
    
    while True:
        # 读三轴高低字节
        x_l = i2cbus.read_byte_data(ACC_ADDR, OUT_X_L_XL)
        x_h = i2cbus.read_byte_data(ACC_ADDR, OUT_X_H_XL)
        y_l = i2cbus.read_byte_data(ACC_ADDR, OUT_Y_L_XL)
        y_h = i2cbus.read_byte_data(ACC_ADDR, OUT_Y_H_XL)
        z_l = i2cbus.read_byte_data(ACC_ADDR, OUT_Z_L_XL)
        z_h = i2cbus.read_byte_data(ACC_ADDR, OUT_Z_H_XL)
        
        # 拼接转有符号值
        raw_x = (x_h << 8) | x_l
        raw_y = (y_h << 8) | y_l
        raw_z = (z_h << 8) | z_l
        if raw_x >= 0x8000:
            raw_x -= 0x10000
        if raw_y >= 0x8000:
            raw_y -= 0x10000
        if raw_z >= 0x8000:
            raw_z -= 0x10000
        
        # 转g单位物理值
        acc_x = raw_x * 0.000061
        acc_y = raw_y * 0.000061
        acc_z = raw_z * 0.000061
        
        print(f"Accel X: {acc_x:.3f}g, Y: {acc_y:.3f}g, Z: {acc_z:.3f}g")
        time.sleep(0.5)

if __name__ == "__main__":
    main()

pigpio版本的修复逻辑完全一致,只需要在打开I2C连接后、进入读值循环前,调用pi.i2c_write_byte_data()方法向两个控制寄存器写入相同配置值即可。


内容的提问来源于stack exchange,提问作者Xenoshell

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 22:15:45