电子说
MPU9250是一款高集成度的九轴惯性测量单元(IMU),它集成了三轴陀螺仪、三轴加速度计和三轴磁力计(通常集成的磁力计为AK8963)。由于其体积小、功耗低、性能稳定,MPU9250广泛应用于无人机、机器人、智能穿戴设备、虚拟现实以及运动追踪等领域。MPU9250采用MEMS(微机电系统)技术制造,能够同时采集角速度、线性加速度和地磁场数据,从而实现九自由度测量。模块内部还集成了数字运动处理器(DMP),用于执行复杂的传感器融合算法,从而降低了主控芯片的运算负担。
MPU9250整合了3轴加速度计、3轴陀螺仪和3轴磁力计,能够提供九轴数据。这使得系统可以实时计算出姿态、航向和运动状态,为高精度定位和运动控制提供数据支持。
传感器输出的原始数据通常为16位有符号数。为了获得物理意义上的数值,需要根据所选的量程进行转换。例如:
温度(℃)={TEMP-OUT}/{340}+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 |
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%02Xrn", MPU9250_GetID());
USART_SendString(USART1, mpu9250ID);
sprintf(ak8963ID, "ak8963_id = 0x%02Xrnrn", 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:%drnmx:%d my:%d mz:%drnTemp: %.2f℃rnrn",
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作为一款集成了九轴传感器的高性能IMU,凭借其小巧的体积、低功耗和多种通信接口,成为了广泛应用于无人机、机器人、可穿戴设备和VR等领域的首选传感器模块。其内部集成的DMP不仅简化了外部数据处理,也为实现高精度姿态估计提供了强有力的支持。然而,在实际应用中,校准、磁干扰和信号完整性等问题依然需要开发者认真对待,通过软硬件设计优化实现更稳定可靠的系统。
需要源代码可收藏加关注在评论留下邮箱获取!!!
审核编辑 黄宇
全部0条评论
快来发表一下你的评论吧 !