一、MPU9250传感器模块概述
MPU9250是一款高集成度的九轴惯性测量单元(IMU),它集成了三轴陀螺仪、三轴加速度计和三轴磁力计(通常集成的磁力计为AK8963)。由于其体积小、功耗低、性能稳定,MPU9250广泛应用于无人机、机器人、智能穿戴设备、虚拟现实以及运动追踪等领域。MPU9250采用MEMS(微机电系统)技术制造,能够同时采集角速度、线性加速度和地磁场数据,从而实现九自由度测量。模块内部还集成了数字运动处理器(DMP),用于执行复杂的传感器融合算法,从而降低了主控芯片的运算负担。
二、功能与特点
MPU9250整合了3轴加速度计、3轴陀螺仪和3轴磁力计,能够提供九轴数据。这使得系统可以实时计算出姿态、航向和运动状态,为高精度定位和运动控制提供数据支持。
- 低功耗设计
采用先进的低功耗设计,适合于便携式设备和电池供电的应用场景。其工作模式可根据应用需求进行灵活配置,如休眠、低功耗待机以及全速工作模式。 - 高动态范围和分辨率
陀螺仪:支持±250、±500、±1000和±2000°/s等不同的量程选择,可适应从微小角速度到大幅度旋转的测量。
加速度计:支持±2g、±4g、±8g和±16g的量程,适用于多种运动状态检测。
磁力计:内置AK8963磁力计,具有高分辨率,可以进行精确的地磁测量,用于航向计算和磁场干扰补偿。 - 数字运动处理器(DMP)
内置DMP可以实现基本的姿态计算和传感器融合,降低主控MCU的计算负担,并实现实时的运动检测与姿态估计。 - 多种通信接口
MPU9250支持I2C和SPI两种通信方式,便于在不同系统中灵活应用。标准库或HAL库均可对其进行驱动开发。 - 内置温度传感器
除了三轴数据,MPU9250还内置温度传感器,用于监控芯片内部温度。虽然该温度数据主要反映芯片工作时的温度状况,但在某些应用中也可作为温度补偿参考。
三、数据校准与转换
传感器输出的原始数据通常为16位有符号数。为了获得物理意义上的数值,需要根据所选的量程进行转换。例如:
- 加速度计:如果选择±2g量程,则转换系数为16384 LSB/g,即原始数据除以16384后得到加速度值(单位g)。
- 陀螺仪:如果选择±250°/s量程,则转换系数为131 LSB/°/s,即原始数据除以131后得到角速度值(单位°/s)。
- 温度传感器:MPU9250的文档中未明确给出温度转换参数,温度转换公式一般参考MPU6050的公式:
温度 ( ℃ ) = T E M P − O U T 340 + 36.53 温度(℃)=\frac{TEMP-OUT}{340}+36.53 温度(℃)=340TEMP−OUT+36.53
四、常用寄存器说明
1、WHO_AM_I:读取设备ID寄存器(只读不能写),MPU9250的ID默认为0x71。
其中AK8963的设备ID固定为0x48。
2、PWR_MGMT_1:电源管理1, 此寄存器用于设置用户配置电源模式和时钟源。
H_RESET:重置内部寄存器,并恢复默认设置。写一个1来设置重置位,该位将自动清除。即复位MPU9250。
SLEEP:设置MPU9250工作模式为休眠模式。
CYCLE:周期模式。当你在 PWR_MGMT_1 寄存器中设置了 CYCLE 位,同时确保 SLEEP 和 STANDBY 位没有被设置时,MPU9250 会进入一种低功耗工作模式。在这种模式下,芯片会不断地在“休眠”与“短暂唤醒采样”之间交替工作。每次唤醒时,它只会采集一个加速度计样本,而不是连续采集数据。采样的频率由 LP_ACCEL_ODR 寄存器来控制。注意:如果你通过 PWR_MGMT_2 寄存器禁用了所有加速度计的轴(也就是关闭了加速度计),那么即使启用了周期模式,芯片仍然会按照 LP_ACCEL_ODR 寄存器设定的时间间隔定时唤醒,但由于加速度计被禁用了,所以它不会采集任何数据。简单来说,就是启用周期模式时芯片周期性地从低功耗休眠状态中唤醒,采集一次数据,然后再回到休眠状态。如果禁用加速度计:芯片仍会周期性唤醒,但不会采集数据。
GYRO_STANDBY:陀螺仪待机。设置后,陀螺仪驱动器和锁相环电路将启用,但感测路径将被禁用。这是一种低功耗模式,可快速启用陀螺仪。
PD_PTAT:关闭内部 PTAT 电压发生器和 PTAT ADC
CLKSEL[2:0]:时钟选择。可选择内部8M晶振、外部晶振或陀螺仪时钟作为时钟源。设备上电默认使用内部8M晶振作为时钟,但其精度不高。官方推荐使用陀螺仪时钟或外部晶振作为时钟源,以提高稳定性,一般设置CLKSEL=001,即选择陀螺仪X轴时钟作为时钟源即可。下表为时钟源选择。
3、PWR_MGMT_2:电源管理2,使能3轴加速度和3轴陀螺仪。
4、SMPLRT_DIV:采样率分频器,用于设置传感器数据采样的速率。将设置采样速率时钟通过这个寄存器进行分频,从而得到最终的数据采样率
分频计算公式如下
5、CONFIG:配置寄存器。
FIFO_MODE:控制 FIFO(数据缓冲区)在装满后如何处理新的数据。当FIFO_MODE = 0时,一旦FIFO装满,则新数据覆盖旧数据。FIFO_MODE = 1时,一旦FIFO满,则停止存储数据。
EXT_SYNC_SET[2:0]:配置外部同步,让芯片与外部触发信号同步采集数据。以下表为选择哪个传感器数据同步,其中000为禁用同步,001为温度数据同步,010-111分别为3轴陀螺仪、3轴加速度数据同步。
DLPF_CFG[2:0]:设置数字低通滤波器,用于滤除传感器信号中的高频噪声。当 FCHOICE_B [1:0] = 00 时,DLPF 由 DLPF_CFG 配置。陀螺仪和温度传感器根据 DLPF_CFG 和 FCHOICE_B 的值进行过滤,如下表所示。
6、GYRO_CONFIG:配置陀螺仪自检和满量程
7、ACCEL_CONFIG:配置加速度自检和满量程
8、INT_PIN_CFG:中断配置寄存器,用于设置INT中断引脚的电平标准和驱动方式(推挽、开漏)等;
BYPASS_EN:配置旁路模式。读取磁力计数据可以通过两种方式读取,一种是通过配置内部I2C主控模式读取,一种是直接通过旁路模式读取,一般是开启旁路模式来访问磁力计,比较简单方便。
9、CNTL1:配置磁力计工作模式。
以下为配置模式
五、接线说明
STM32F103C8T6 | MPU9250 / USB转TTL |
---|---|
3V3 | MPU9250_VCC |
GND | MPU9250和TTL的GND |
GPIOB10 | MPU9250_SCL |
GPIOB11 | MPU9250_SDA |
GPIOA9 | TTL_RX |
GPIOA10 | TTL_TX |
六、读取MPU9250九轴数据
代码示例:
main.c
#include "stm32f10x.h" // Device header
#include "mpu9250.h"
#include "delay.h"
#include "usart.h"
int16_t ax, ay, az, gx, gy, gz, mx, my, mz;
float temperature;
char mpu9250ID[30], ak8963ID[30], buf[100];
int main(void)
{
SystemInit();
MPU9250_Init();
USART1_Init(); // USART初始化函数
sprintf(mpu9250ID, "mpu9250_id = 0x%02X\r\n", MPU9250_GetID());
USART_SendString(USART1, mpu9250ID);
sprintf(ak8963ID, "ak8963_id = 0x%02X\r\n\r\n", AK8963_GetID());
USART_SendString(USART1, ak8963ID);
while(1)
{
//读取加速度和陀螺仪
MPU9250_GetData(&ax, &ay, &az, &gx, &gy, &gz, &mx, &my, &mz);
//读取温度
temperature = MPU6050_GetTemperature();
sprintf(buf, "ax:%d ay:%d az:%d gx:%d gy:%d gz:%d\r\nmx:%d my:%d mz:%d\r\nTemp: %.2f℃\r\n\r\n",
ax, ay, az, gx, gy, gz, mx, my, mz, temperature);
USART_SendString(USART1, buf);
Delay_ms(500);
}
}
MPU9250.c
#include "MyI2C.h"
#include "MPU9250_Reg.h"
#include "delay.h"
void MPU9250_WriteReg(uint8_t DeviceAddr, uint8_t RegAddress, uint8_t Data)
{
MyI2C_Start();
MyI2C_SendByte(DeviceAddr);
MyI2C_ReceiveAck();
MyI2C_SendByte(RegAddress);
MyI2C_ReceiveAck();
MyI2C_SendByte(Data);
MyI2C_ReceiveAck();
MyI2C_Stop();
}
uint8_t MPU9250_ReadReg(uint8_t DeviceAddr, uint8_t RegAddress)
{
uint8_t Data;
MyI2C_Start();
MyI2C_SendByte(DeviceAddr);
MyI2C_ReceiveAck();
MyI2C_SendByte(RegAddress);
MyI2C_ReceiveAck();
MyI2C_Start();
MyI2C_SendByte(DeviceAddr | 0x01); //指定地址读
MyI2C_ReceiveAck();
Data = MyI2C_ReceiveByte();
MyI2C_SendAck(1);
MyI2C_Stop();
return Data;
}
uint8_t MPU9250_GetID(void)
{
return MPU9250_ReadReg(MPU9250_ADDR_WRITE, MPU9250_WHO_AM_I);
}
uint8_t AK8963_GetID(void)
{
return MPU9250_ReadReg(AK8963_ADDR_WRITE, AK8963_WHO_AM_I);
}
void MPU9250_GetData(int16_t *ax, int16_t *ay, int16_t *az,
int16_t *gx, int16_t *gy, int16_t *gz,
int16_t *mx, int16_t *my, int16_t *mz)
{
uint8_t AccData[7], GyroData[7], MagData[7]; // 包括6字节数据及1字节状态(ST2)
uint8_t i;
//3轴加速度
for(i = 0; i < 7; i++){
AccData[i] = MPU9250_ReadReg(MPU9250_ADDR_WRITE, MPU9250_ACCEL_XOUT_H + i);
}
*ax = (int16_t)(((int16_t)AccData[0] << 8) | AccData[1]);
*ay = (int16_t)(((int16_t)AccData[2] << 8) | AccData[3]);
*az = (int16_t)(((int16_t)AccData[4] << 8) | AccData[5]);
//3轴陀螺仪
for(i = 0; i < 7; i++){
GyroData[i] = MPU9250_ReadReg(MPU9250_ADDR_WRITE, MPU9250_GYRO_XOUT_H + i);
}
*gx = (int16_t)(((int16_t)GyroData[0] << 8) | GyroData[1]);
*gy = (int16_t)(((int16_t)GyroData[2] << 8) | GyroData[3]);
*gz = (int16_t)(((int16_t)GyroData[4] << 8) | GyroData[5]);
//3轴磁力计
for(i = 0; i < 7; i++){
MagData[i] = MPU9250_ReadReg(AK8963_ADDR_WRITE, AK8963_HXL + i);
}
/* 注意:AK8963数据寄存器采用低字节在前的格式 */
*mx = (int16_t)(((int16_t)MagData[1] << 8) | MagData[0]);
*my = (int16_t)(((int16_t)MagData[3] << 8) | MagData[2]);
*mz = (int16_t)(((int16_t)MagData[5] << 8) | MagData[4]);
/* 可以在此检查ST2寄存器(Data[6])中的溢出标志 */
}
float MPU6050_GetTemperature(void)
{
int16_t TempData;
uint8_t tempH, tempL;
tempH = MPU9250_ReadReg(MPU9250_ADDR_WRITE, MPU9250_TEMP_OUT_H);
tempL = MPU9250_ReadReg(MPU9250_ADDR_WRITE, MPU9250_TEMP_OUT_L);
TempData = (int16_t)(tempH << 8) | tempL;
return((float)TempData) / 340.0f + 36.53f;
}
void MPU9250_Init()
{
MyI2C_Init();
MPU9250_WriteReg(MPU9250_ADDR_WRITE, MPU9250_PWR_MGMT_1, 0x01);
MPU9250_WriteReg(MPU9250_ADDR_WRITE, MPU9250_PWR_MGMT_2, 0x00);
MPU9250_WriteReg(MPU9250_ADDR_WRITE, MPU9250_SMPLRT_DIV, 0x09); //采样分频器
MPU9250_WriteReg(MPU9250_ADDR_WRITE, MPU9250_CONFIG, 0x06); //配置寄存器,配置同步时钟和低通滤波
MPU9250_WriteReg(MPU9250_ADDR_WRITE, MPU9250_GYRO_CONFIG, 0x18); //配置陀螺仪自测和满量程
MPU9250_WriteReg(MPU9250_ADDR_WRITE, MPU9250_ACCEL_CONFIG, 0x18);
MPU9250_WriteReg(MPU9250_ADDR_WRITE, MPU9250_INT_PIN_CFG, 0x02); //开启旁路模式
MPU9250_WriteReg(AK8963_ADDR_WRITE, AK8963_CNTL1, 0x16); //设置连续测量模式
Delay_ms(10);
}
效果展示:
七、读取不到磁力计数据的可能原因及解决方法
获取磁力计是根据AK8963来测量,在读取磁力计数据前,先读取下AK8963设备的ID值是否返回正常。如果不正常,可能的原因有以下几点:
- 旁路模式未开启
MPU9250内部连接了AK8963,只有在设置旁路模式后,外部I2C才能直接访问AK8963。如果旁路模式没有正确配置,I2C总线上可能读不到AK8963的数据。
如果旁路模式已开启,常见原因是MPU9250内部I2C主控功能没有被关闭,导致旁路模式虽然设置了但仍然屏蔽了对AK8963的直接访问。通常在启用旁路模式之前,需要先清除MPU9250的I2C_MST_EN,以确保外部I2C能直接访问AK8963。否则,即便旁路模式配置正确,也可能读不到AK8963的寄存器,返回0x00。
建议检查初始化流程,确保在设置INT_PIN_CFG寄存器为0x02以启用旁路模式之前,先在USER_CTRL寄存器中清除I2C主控使能位,然后再进行后续的AK8963初始化流程。 - I2C通信问题
检查下I2C初始化和通讯时序是否正确。
值得注意的是I2C地址的位宽上,AK8963的7位从地址是0x0C,如果你的I2C位操作中,传递的是8位地址。对于8位地址,写操作应使用(0x0C<<1)=0x18,而读操作应使用0x18|0x01=0x19。如果直接使用0x0C,就相当于地址错误,I2C总线读取时由于找不到设备,返回的自然就是上拉电平(0xFF)。 - 供电或复位问题
如果AK8963没有正确上电或者处于复位状态,也可能返回0x00。确保传感器的电源电压和启动顺序符合要求。
总结
MPU9250作为一款集成了九轴传感器的高性能IMU,凭借其小巧的体积、低功耗和多种通信接口,成为了广泛应用于无人机、机器人、可穿戴设备和VR等领域的首选传感器模块。其内部集成的DMP不仅简化了外部数据处理,也为实现高精度姿态估计提供了强有力的支持。然而,在实际应用中,校准、磁干扰和信号完整性等问题依然需要开发者认真对待,通过软硬件设计优化实现更稳定可靠的系统。
需要源代码可收藏加关注在评论留下邮箱获取!!!