使用SMBus/I2C读取LSM9DS1加速度传感器寄存器返回固定值问题
LSM9DS1加速度计寄存器读值固定问题排查与修复
问题根因
- 你没有对传感器做任何初始化配置:LSM9DS1上电默认进入掉电休眠模式,加速度计采样电路完全停止工作,三个轴的输出寄存器不会随姿态变化更新,只会返回固定的默认值,这是读值完全不变的核心原因。你能稳定读到固定值,反而说明I2C硬件连接、基础读寄存器操作是正常的,不存在通信故障。
- 代码存在冗余问题:smbus版本中你把
SMBus(1)实例初始化放在了循环内部,每次读值都重新创建I2C连接,会浪费系统资源,应当移到循环外只初始化一次。 - 字节拼接注意:你定义的
OUT_X_XL1(0x28)是X轴加速度低8位寄存器,OUT_X_XL2(0x29)是高8位寄存器,拼接16位原始值时不要搞反高低字节顺序。
修复方案
在开始读输出寄存器之前,先向传感器的两个控制寄存器写入配置值,启动加速度计采样:
- 向
CTRL_REG5_XL(0x1F)写入0x38:使能X/Y/Z三个轴的加速度输出,使用默认±2g量程。 - 向
CTRL_REG6_XL(0x20)写入0x60:配置加速度计为正常功耗模式,输出数据率119Hz,退出掉电状态。
配置完成后等待10ms让传感器稳定,再开始读输出寄存器即可拿到随姿态变化的动态值。
原始值转物理加速度的方法
- 拼接16位原始值:以X轴为例,
raw_x = (acc_x_high << 8) | acc_x_low,Y、Z轴逻辑一致。 - 补码转有符号整数:16位二进制补码的取值范围是-32768~32767,如果拼接后的值大于等于32768(即0x8000),减去65536(即0x10000)即可得到对应的有符号整数。
- 换算为物理单位:默认±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
相关产品推荐
相关产品推荐

