一、BMI160简介

  BMI160 是 一颗低功耗 6-轴惯性测量单元(3 轴加速度 + 3 轴陀螺),面向移动设备、可穿戴、AR/VR、相机OIS、步数/手势检测等场景。体积小(2.5×3.0×0.83 mm LGA),电源范围宽(VDD 1.71–3.6 V,VDDIO 1.2–3.6 V),并内建 FIFO、时间戳与中断引擎,可实现低功耗的运动检测与自主事件触发。当加速度计和陀螺仪处于完全工作模式时,典型工作电流约 925 µA。
主要特性

  • 供电电源:3.3V / 5V
  • 高性能加速度计和陀螺仪(硬件同步)
  • 超低功耗:典型值925 uA(加速度计和陀螺仪全速运行)
  • 兼容Android Lollipop:支持大幅度运动和步数检测器/计步器(每个5 μA)
  • 内置电源管理单元 (PMU),可实现高级电源管理
  • 陀螺仪快速启动模式,节省功耗
  • 1024 字节可分配 FIFO 缓冲区(可处理外部传感器数据)
  • 硬件传感器时间戳,用于精确的传感器数据融合
  • 集成中断,用于增强自主运动检测
  • 灵活的数字主接口,可通过 I2C 或 SPI 连接到主机
  • 扩展 I2C 模式,时钟频率高达 1 MHz
  • 额外的二级高速接口,用于 OIS 应用

应用场景

  • 室内导航
  • 3D扫描/室内地图绘制
  • 高级手势识别
  • 沉浸式游戏
  • 9轴运动检测
  • 空中鼠标应用和指针
  • 计步器/步数计数
  • 移动应用的高级系统电源管理

二、引脚说明

VIN 5V供电
3V3 VIN接了5V,该引脚输出3.3V;如果3.3V供电,接该引脚,则VIN不需要接
GND
SCL 12C串行时钟线/SPI串行时钟端口
SDA 12C串行数据线/4线SPI串行数据输入/3线SPI串行数据输入/输出
CS SPI模式选择引脚
SA0 SPI串行数据输出/12C地址选择引脚
OCS OIS接口
INT1 中断引脚1
INT2 中断引脚2
SCX 磁力计接口
SDX 磁力计接口

三、数据流框图和I2C读写访问


  从上面的框图中,可以看到,BMI160与外部进行双向数据传输的方式有两种:SPI和I2C。以I2C与外部进行通信的方式说明。当BMI160通过I2C与外部进行通信时,BMI160将作为I2C从设备挂到主控芯片(主设备)的I2C总线上,所以,主控芯片在配置其对应的I2C驱动时就需要知道BMI160的从设备地址。
  对于不同的硬件设计,BMI160的从设备地址是不同的。从数据手册可知,从设备地址可根据SDO进行选择,SDO接低电平,从设备地址为0x68,SDO接高电平,从设备地址为0x69。店铺的BMI160模块的从设备地址默认为0x69。

I2C读写访问

四、主要寄存器说明

CHIPID(0x00):设备ID寄存器,BMI160的ID号为0xD1。

ERR_REG(0x02):错误寄存器,用于调试配置。

PMU_STATUS(0x03):状态寄存器,用于读取当前模式。其中Normal为正常工作模式。

DATA(0x04~0x17):数据寄存器,加速度,陀螺仪,若连接了磁力计,也可以读取磁力计数据。读取数据时尽量一次读取完,以保证 accel/gyro 的时间同步,即连续读。

ACC_CONF(0x40):设置加速度计采样频率与带宽。

ACC_RANGE(0x41):选择加速度量程,Bit3-0:选择量程(±2g / ±4g / ±8g / ±16g),其他位没有用到,置0即可。

GYR_CONF(0x42):设置陀螺仪采样频率和带宽。

GYR_RANGE(0x43):选择陀螺仪量程,Bit2-0:选择量程(±125°/s / ±250°/s / ±500°/s / ±1000°/s / ±2000°/s),其他位没有用到,置0即可。

CMD(0x7E):控制寄存器,用该地址写入不同值控制加速度或陀螺仪的工作模式。其中,通过该地址写入0x11,设置加速度为正常工作模式,写入0x15,设置陀螺仪为正常工作模式。写入0xB6,为软复位。

注意:CMD只能接受一个命令一次,写入一次后,必须等待命令执行完毕后再写入,缺少等待会导致后续配置/读取异常。

五、原始数据到物理量的换算

 从寄存器读到的是有符号 16-bit 原始值,需要按所选量程除以灵敏度得到物理量。
 加速度(以 g 或 m/s²单位 表示),常见灵敏度(LSB / g):
    ±2 g :16384 LSB/g
    ±4 g :8192 LSB/g
    ±8 g :4096 LSB/g
    ±16 g:2048 LSB/g
 转为g单位:accel_g = raw_accel_signed / S_accel,如:raw=16384,FS=±2g → accel_g = 16384/16384 = 1 g
 转为m/s²单位:accel_m_s2 = accel_g * 9.80665

 陀螺仪(以 °/s 或 rad/s单位 表示),常见灵敏度(LSB / (°/s)):
    ±2000 °/s → 16.4 LSB/(°/s)
    ±1000 °/s → 32.8 LSB/(°/s)
    ±500 °/s → 65.6 LSB/(°/s)
    ±250 °/s → 131.2 LSB/(°/s)
    ±125 °/s → 262.4 LSB/(°/s)
 转为°/s单位:gyro_dps = raw_gyro_signed / S_gyro
 转为rad/s单位:gyro_rad_s = gyro_dps * (π / 180)

六、STM32F103驱动BMI160读取六轴数据

准备工作

  STM32F103C8T6开发板,OLED屏,BMI160模块

接线说明

STM32F103C8T6 BMI160
PB10 SCL
PB11 SDA
PB8 OLED->SCL
PB9 OLED->SDA
5V VIN
GND GND

代码示例

BMI160.c

#include "bmi160.h" 

void BMI160_WriteReg(uint8_t RegAddress, uint8_t Data)
{
	MyI2C_Start();
	MyI2C_SendByte(BMI160_ADDR_WRITE);
	MyI2C_ReceiveAck();
	MyI2C_SendByte(RegAddress);
	MyI2C_ReceiveAck();
	MyI2C_SendByte(Data);
	MyI2C_ReceiveAck();
	MyI2C_Stop();
}

uint8_t BMI160_ReadReg(uint8_t RegAddress)
{
	uint8_t Data;
	
	MyI2C_Start();
	MyI2C_SendByte(BMI160_ADDR_WRITE);
	MyI2C_ReceiveAck();
	MyI2C_SendByte(RegAddress);
	MyI2C_ReceiveAck();
	
	MyI2C_Start();
	MyI2C_SendByte(BMI160_ADDR_READ); //指定地址读
	MyI2C_ReceiveAck();
	Data = MyI2C_ReceiveByte();
	MyI2C_SendAck(1);
	MyI2C_Stop();
	
	return Data;
}

void BMI160_ReadMulti(uint8_t RegAddress, uint8_t *buf, uint8_t len)
{
    uint8_t i;
    MyI2C_Start();
    MyI2C_SendByte(BMI160_ADDR_WRITE);        
    MyI2C_ReceiveAck();
    MyI2C_SendByte(RegAddress);
    MyI2C_ReceiveAck();

    MyI2C_Start();                     
    MyI2C_SendByte(BMI160_ADDR_READ); 
    MyI2C_ReceiveAck();
    for (i = 0; i < len; i++)
    {
        buf[i] = MyI2C_ReceiveByte();
        if (i == (len - 1)) MyI2C_SendAck(1); 
        else MyI2C_SendAck(0);               
    }
    MyI2C_Stop();
}

void BMI160_Get6AxisRaw(int16_t *ax, int16_t *ay, int16_t *az, int16_t *gx, int16_t *gy, int16_t *gz)
{
	uint8_t buf[12];
    int16_t raw;

    BMI160_ReadMulti(BMI160_REG_GYR_LSB, buf, 12);

    *gx = (int16_t)((buf[1]<<8) | buf[0]);
    *gy = (int16_t)((buf[3]<<8) | buf[2]);
    *gz = (int16_t)((buf[5]<<8) | buf[4]);

    *ax = (int16_t)((buf[7]<<8) | buf[6]);
    *ay = (int16_t)((buf[9]<<8) | buf[8]);
    *az = (int16_t)((buf[11]<<8) | buf[10]);
}

void BMI160_ConvAcc(int16_t ax_raw, int16_t ay_raw, int16_t az_raw, float *ax_g, float *ay_g, float *az_g)
{
    *ax_g = (float)ax_raw / BMI160_ACCEL_SENS_16G * 9.80665f;  // 输出单位 m/s^2
    *ay_g = (float)ay_raw / BMI160_ACCEL_SENS_16G * 9.80665f;
    *az_g = (float)az_raw / BMI160_ACCEL_SENS_16G * 9.80665f;
}

void BMI160_ConvGyro(int16_t gx_raw, int16_t gy_raw, int16_t gz_raw, float *gx_dps, float *gy_dps, float *gz_dps)
{
    *gx_dps = (float)gx_raw / BMI160_GYRO_SENS_2000;  // 输出单位 °/s
    *gy_dps = (float)gy_raw / BMI160_GYRO_SENS_2000;
    *gz_dps = (float)gz_raw / BMI160_GYRO_SENS_2000;
}

void BMI160_Init(void)
{
	MyI2C_Init();
	
	BMI160_WriteReg(BMI160_REG_CMD, 0xB6);  
    Delay_ms(100); 
	
	BMI160_WriteReg(BMI160_REG_CMD, 0x15);  // gyro normal
    Delay_ms(100);
    BMI160_WriteReg(BMI160_REG_CMD, 0x11);  // acc normal
    Delay_ms(100);
	
	// 设置 ODR
    BMI160_WriteReg(BMI160_ACC_CONF, 0x28);  // acc 100Hz
    BMI160_WriteReg(BMI160_GYR_CONF, 0x28);  // gyro 100Hz

    // 设置量程
    BMI160_WriteReg(BMI160_REG_ACC_RANGE, 0x0C);  // ±16g
    BMI160_WriteReg(BMI160_REG_GYR_RANGE, 0x00);  // ±2000°/s
	
	Delay_ms(100);
}

main.c

#include "stm32f10x.h"                  // Device header
#include "bmi160.h" 
#include "oled.h"
#include "KEY.h"

uint8_t ID, key;
int16_t ax, ay, az, gx, gy, gz;
float ax_g, ay_g, az_g, gx_dps, gy_dps, gz_dps;

int main(void)
{
	OLED_Init();
	BMI160_Init();
	Key_Init();
	
	OLED_ShowString(1,1,"ID:");
	
	ID = BMI160_ReadReg(0x00);
	OLED_ShowHexNum(1,4,ID,2);

	
	while (1)
	{
		BMI160_Get6AxisRaw(&ax, &ay, &az, &gx, &gy, &gz);
		
		key = Key_Scan();
		if(key)
		{
			OLED_ShowString(1,7,"m/s^2    o/s");
			BMI160_ConvAcc(ax, ay, az, &ax_g, &ay_g, &az_g);
			BMI160_ConvGyro(gx, gy, gz, &gx_dps, &gy_dps, &gz_dps);
			OLED_ShowFloat(2, 1, ax_g, 2, 2);
			OLED_ShowFloat(3, 1, ay_g, 2, 2);
			OLED_ShowFloat(4, 1, az_g, 2, 2);
			OLED_ShowFloat(2, 9, gx_dps, 2, 2);
			OLED_ShowFloat(3, 9, gy_dps, 2, 2);
			OLED_ShowFloat(4, 9, gz_dps, 2, 2);
		}else{
			OLED_ShowString(1,7,"        ");
			OLED_ShowSignedNum(2, 1, ax, 5);
			OLED_ShowSignedNum(3, 1, ay, 5);
			OLED_ShowSignedNum(4, 1, az, 5);
			OLED_ShowSignedNum(2, 9, gx, 5);
			OLED_ShowSignedNum(3, 9, gy, 5);
			OLED_ShowSignedNum(4, 9, gz, 5);
		}
	}
}

效果展示

请添加图片描述

总结

  BMI160 是一颗体积小、功耗低、功能丰富的 6-DoF IMU,适合大多数需要加速度与角速度数据的移动/穿戴/相机稳定场景;使用时优先保证硬件与通信可靠、理解 FIFO 与 CMD 时序、并在系统层面做好校准与滤波。

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐