一、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的公式:
溫度(℃)={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 |
六、讀取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%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內部連接了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不僅簡化了外部數據處理,也為實現高精度姿態估計提供了強有力的支持。然而,在實際應用中,校準、磁干擾和信號完整性等問題依然需要開發者認真對待,通過軟硬件設計優化實現更穩定可靠的系統。
需要源代碼可收藏加關注在評論留下郵箱獲取!!!
審核編輯 黃宇
-
傳感器
+關注
關注
2576文章
55041瀏覽量
791336 -
STM32F
+關注
關注
1文章
42瀏覽量
18783
發布評論請先 登錄
【瑞薩RA6E2】硬件IIC驅動九軸傳感器與OLED顯示
零知開源——STM32F103RBT6驅動 ICM20948 九軸傳感器及 vofa + 上位機可視化教程
零知開源——STM32F103RBT6驅動 ICM20948 九軸傳感器及 vofa + 上位機可視化教程
基于STM32F103C8T6驅動MPU9250傳感器讀取九軸數據
評論