您现在的位置是:首页 > 科技前沿
阿波罗 STM32F767 开发板资料连载第四十章 MPU9250 九轴传感器
智慧创新站
2025-04-30【科技前沿】77人已围观
简介1)实验平台:alientek阿波罗STM32F767开发板第四十章MPU9250九轴传感器实验本章,我们介绍一款主流的九轴(三轴加速度+三轴角速度(陀螺仪)+三轴磁力计)传感器:MPU9250,该传感器广泛用于四轴、平衡车和空中鼠标等设计,具有非常广泛的应用范围。ALIENTEK阿波罗STM32F...
1)实验平台:alientek阿波罗STM32F767开发板

第四十章MPU9250九轴传感器实验
本章,我们介绍一款主流的九轴(三轴加速度+三轴角速度(陀螺仪)+三轴磁力计)传感器:
MPU9250,该传感器广泛用于四轴、平衡车和空中鼠标等设计,具有非常广泛的应用范围。
ALIENTEK阿波罗STM32F767开发板自带了MPU9250传感器。本章我们将使用STM32F767
来驱动MPU9250,读取其原始数据,并利用其自带的DMP结合MPL库实现姿态解算,结合
匿名四轴上位机软件和LCD显示,教大家如何使用这款功能强大的九轴传感器。本章分为如下
几个部分:
40.1MPU9250简介
40.2硬件设计
40.3软件设计
40.4下载验证
40.1MPU9250简介
本节,我们将分2个部分介绍:1,MPU9250基础介绍。2,DMP使用简介。另外,所有
MPU9250的相关资料,都在光盘:A盘7,硬件资料MPU9250资料文件夹里面。
40.1.1MPU9250基础介绍
MPU9250是InvenSense公司推出的全球首款整合性9轴运动处理组件,相较于多组件方
案,免除了组合陀螺仪与加速器时之轴间差的问题,减少了体积和功耗。
MPU9250内部集成有3轴陀螺仪、
3轴加速度计和3轴磁力计,输出都是16位的数字量;可
以通过集成电路总线(IIC)接口和单片机进行数据交互,传输速率可达400kHz/s。陀螺仪的角
速度测量范围最高达±2000(°/s),具有良好的动态响应特性。加速度计的测量范围最大为±
16g(g为重力加速度),静态测量精度高。磁力计采用高灵度霍尔型传感器进行数据采集,磁感
应强度测量范围为±4800μT,可用于对偏航角的辅助测量。
MPU9250自带的数字运动处理器(DMP:DigitalMotionProcessor)硬件加速引擎,可以整
合九轴传感器数据,向应用端输出完整的9轴融合演算数据。有了DMP,我们可以使用
InvenSense公司提供的运动处理库(MPL:MotionProcessLibrary),非常方便的实现姿态解算,
降低了运动处理运算对操作系统的负荷,同时大大降低了开发难度。
MPU9250的特点包括:
①以数字形式输出9轴旋转矩阵、四元数(quaternion)、欧拉角格式(EulerAngleforma)的
融合演算数据(需DMP支持)
②集成16位分辨率,量程为:±250、±500、±1000°与±2000°/sec的3轴角速度
传感器(陀螺仪)
③集成16位分辨率,量程为:±2g、±4g、±8g和±16g的3轴加速度传感器
④集成16位分辨率,量程为:±4800uT的磁场传感器(磁力计)
⑤自带数字运动处理(DMP:DigitalMotionProcessing)引擎可减少MCU复杂的融合演算
数据、感测器同步化、姿势感应等的负荷
⑥自带一个数字温度传感器
⑦可编程数字滤波器
⑧支持SPI接口,通信速度高达20Mhz
⑨自带512字节FIFO缓冲区
⑩高达400Khz的IIC通信接口
⑪超小封装尺寸:3x3x1mm(QFN)
MPU9250传感器的检测轴如图40.1.1.1所示:
图40.1.1.1MPU9250检测轴及其方向
MPU9250的内部框图如图40.1.1.2所示:
图40.1.1.2MPU9250框图
其中,SCL和SDA可以连接MCU的IIC接口,MCU通过这个IIC接口来控制MPU9250,
另外还有一个IIC接口:AUX_CL和AUX_DA,这个接口可用来连接外部从设备,比气压传感
器。VDDIO是IO口电压,该引脚最低可以到1.8V,我们一般直接接VDD即可。AD0是从IIC
接口(接MCU)的地址控制引脚,该引脚控制IIC地址的最低位。如果接GND,则MPU9250
的IIC地址是:0X68,如果接VDD,则是0X69,注意:这里的地址是不包含数据传输的最低
位的(最低位用来表示读写)!!注意:当使用SPI接口的时候,使用:SCLK、SDO、SDI和
nCS脚来传输数据。
这里需要和大家说明一下的是:MPU9250,实际上是内部集成了一个MPU6500六轴传感
器和一个AK8963三轴磁力计,他们共用一个IIC接口,这样组合成一个九轴传感器。前面说
了我们开发板上MPU9250的IIC地址是0X68,实际上是指MPU6500的地址是0X68,而AK8963
磁力计的IIC地址,则是:0X0C(不包含最低位)。
在阿波罗STM32开发板上,AD0是接GND的,所以MPU9250的IIC地址是0X68(不含
最低位),IIC通信的时序我们在之前已经介绍过(第二十九章,IIC实验),这里就不再细说了。
接下来,我们介绍一下利用STM32F767读取MPU9250的加速度和角度传感器数据(非
中断方式),需要哪些初始化步骤:
1)初始化IIC接口
MPU9250采用IIC与STM32F767通信,所以我们需要先初始化与MPU9250连接的SDA
和SCL数据线。这个在前面的IIC实验章节已经介绍过了,这里MPU9250与24C02共用一个
IIC,所以初始化IIC完全一模一样。
2)复位MPU9250
这一步让MPU9250内部所有寄存器恢复默认值,通过对电源管理寄存器1(0X6B)的bit7
写1实现。复位后,电源管理寄存器1恢复默认值(0X40),然后必须设置该寄存器为0X00,
以唤醒MPU9250,进入正常工作状态。
3)设置角速度传感器(陀螺仪)和加速度传感器的满量程范围
这一步,我们设置两个传感器的满量程范围(FSR),分别通过陀螺仪配置寄存器(0X1B)
和加速度传感器配置寄存器(0X1C)设置。我们一般设置陀螺仪的满量程范围为±2000dps,
加速度传感器的满量程范围为±2g。
4)设置其他参数
这里,我们还需要配置的参数有:关闭中断、关闭AUXIIC接口、禁止FIFO、设置陀螺
仪采样率和设置数字低通滤波器(DLPF)等。本章我们不用中断方式读取数据,所以关闭中断,
然后也没用到AUXIIC接口外接其他传感器,所以也关闭这个接口。分别通过中断使能寄存器
(0X38)和用户控制寄存器(0X6A)控制。MPU9250可以使用FIFO存储传感器数据,不过
本章我们没有用到,所以关闭所有FIFO通道,这个通过FIFO使能寄存器(0X23)控制,默
认都是0(即禁止FIFO),所以用默认值就可以了。陀螺仪采样率通过采样率分频寄存器(0X19)
控制,这个采样率我们一般设置为50即可。数字低通滤波器(DLPF)则通过配置寄存器(0X1A)
设置,一般设置DLPF为带宽的1/2即可。
5)配置系统时钟源并使能角速度传感器和加速度传感器
系统时钟源同样是通过电源管理寄存器1(0X6B)来设置,该寄存器的最低三位用于设置
系统时钟源选择,默认值是0(内部8MRC震荡),不过我们一般设置为1,选择x轴陀螺PLL
作为时钟源,以获得更高精度的时钟。同时,使能角速度传感器和加速度传感器,这两个操作
通过电源管理寄存器2(0X6C)来设置,设置对应位为0即可开启。
6)配置AK8963磁场传感器(磁力计)
经过前面5步配置,我们完成了对MPU6500的配置,此步需要对AK8963进行配置。首
先设置控制寄存器2(0X0B)的最低位为1,对AK8963进行软复位。随后设置控制寄存器1
(0X0A)为0X11,选择16位输出,单次测量模式。随后就可以读取磁力计数据了。
至此,MPU9250的初始化就完成了,可以正常工作了(其他未设置的寄存器全部采用默认值即可),接下来,我们就可以读取相关寄存器,得到加速度传感器、角速度传感器和温度传感
器的数据了。不过,我们先简单介绍几个重要的寄存器。
首先,我们介绍电源管理寄存器1,该寄存器地址为0X6B,各位描述如表40.1.1.1所示:
图40.1.1.1电源管理寄存器1各位描述
其中,H_RESET位用来控制复位,设置为1,复位MPU9250,复位结束后,MPU硬件自
动清零该位。SLEEEP位用于控制MPU9250的工作模式,复位后,该位为1,即进入了睡眠模
式(低功耗),所以我们要清零该位,以进入正常工作模式。最后CLKSEL[2:0]用于选择系统时
钟源,选择关系如表40.1.1.2所示:
图40.1.1.2CLKSEL选择列表
默认是使用内部20MRC晶振的,精度不高,我们一般设置其自动选择最有效的时钟源,
一般设置CLKSEL=001即可。
接着,我们看陀螺仪配置寄存器,该寄存器地址为:0X1B,各位描述如表40.1.3所示:
表40.1.1.3陀螺仪配置寄存器各位描述
该寄存器我们只关心GYRO_FS_SEL[1:0]和FCHOICE[1:0]这四个位,GYRO_FS_SEL[1:0]用于
设置陀螺仪的满量程范围:0,±250°/S;1,±500°/S;2,±1000°/S;3,±2000°/S;我
们一般设置为3,即±2000°/S,因为陀螺仪的ADC为16位分辨率,所以得到灵敏度为:
65536/4000=16.4LSB/(°/S)。FCHOICE[1:0]用于控制DLPF旁路,我们一般设置为3,不旁路
DLPF。
接下来,我们看加速度传感器配置寄存器,寄存器地址为:0X1C,各位描述如表40.1.1.4
所示:
表40.1.1.4加速度传感器配置寄存器各位描述
该寄存器我们只关心ACCEL_FS_SEL[1:0]这两个位,用于设置加速度传感器的满量程范围:
0,±2g;1,±4g;2,±8g;3,±16g;我们一般设置为0,即±2g,因为加速度传感器的
ADC也是16位,所以得到灵敏度为:65536/4=16384LSB/g。
接下来,我看看FIFO使能寄存器,寄存器地址为:0X23,各位描述如表40.1.1.5所示:
表40.1.1.5FIFO使能寄存器各位描述
该寄存器用于控制FIFO使能,在简单读取传感器数据的时候,可以不用FIFO,设置对应
位为0即可禁止FIFO,设置为1,则使能FIFO。注意加速度传感器的3个轴,全由1个位(ACCEL)
控制,只要该位置1,则加速度传感器的三个通道都开启FIFO了。
接下来,我们看陀螺仪采样率分频寄存器,寄存器地址为:0X19,各位描述如表40.1.1.6
所示:
表40.1.1.6陀螺仪采样率分频寄存器各位描述
该寄存器用于设置MPU9250的陀螺仪采样频率,计算公式为:
采样频率=陀螺仪输出频率/(1+SMPLRT_DIV)
这里陀螺仪的输出频率,是1Khz、8Khz或32Khz,与数字低通滤波器(DLPF)的设置有
关,当FCHOICE[1:0]不为11的时候,频率为32Khz,其他情况:当DLPF_CFG=0/7的时候,
频率为8Khz,否则是1Khz。而且DLPF滤波频率一般设置为采样率的一半。采样率,我们假
定设置为50Hz,那么SMPLRT_DIV=1000/50-1=19。
接下来,我们看配置寄存器,寄存器地址为:0X1A,各位描述如表40.1.1.7所示:
表40.1.1.7配置寄存器各位描述
这里,我们主要关心数字低通滤波器(DLPF)的设置位,即:DLPF_CFG[2:0],陀螺仪根
据这三个位的配置进行过滤。DLPF_CFG不同配置对应的过滤情况如表40.1.1.8所示:
表40.1.1.8DLPF_CFG配置表
一般我们设置角速度传感器的带宽为其采样率的一半,如前面所说的,如果设置采样率为
50Hz,那么带宽就应该设置为25Hz,取近似值20Hz,就应该设置DLPF_CFG=100。需要注意:
FCHOICE[1:0](通过0X1B寄存器配置)必须设置为11,否则固定32K频率,且DLPF_CFG
的配置无效!
接下来,我们看电源管理寄存器2,寄存器地址为:0X6C,各位描述如表40.1.1.9所示:
表40.1.1.9电源管理寄存器2各位描述
该寄存器低六位有效,分别控制加速度和陀螺仪的x/y/z轴是否开启,这里我们设置全部都
开启,所以全部设置为0即可。
接下来,我们看看陀螺仪数据输出寄存器,总共由6个寄存器组成,地址为:0X43~0X48,
通过读取这6个寄存器,就可以读到陀螺仪x/y/z轴的值,比如x轴的数据,可以通过读取0X43
(高8位)和0X44(低8位)寄存器得到,其他轴以此类推。
同样,加速度传感器数据输出寄存器,也有6个,地址为:0X3B~0X40,通过读取这6个
寄存器,就可以读到加速度传感器x/y/z轴的值,比如读x轴的数据,可以通过读取0X3B(高
8位)和0X3C(低8位)寄存器得到,其他轴以此类推。
另外,温度传感器的值,可以通过读取0X41(高8位)和0X42(低8位)寄存器得到,
温度换算公式为:
Temperature=21+regval/338.87
其中,Temperature为计算得到的温度值,单位为℃,regval为从0X41和0X42读到的温度
传感器值。
接下来,我们看AK8963的控制寄存器1,寄存器地址为:0X0A,各位描述如表40.1.1.10
所示:
表40.1.1.10AK8963控制寄存器1
其中,BIT位控制AK8963输出位数,0,表示14位;1,表示16位;我们一般设置为1。
MODE[3:0]用于控制AK8963的工作模式:0000,掉电模式;0001,单次测量模式;0010,
连续测量模式1;0110,连续测量模式2;0100,外部触发测量模式;1000,自测试模式;
1111,FuseROM访问模式;我们一般设置MODE[3:0]=0001,即单次测量模式。
接下来,我们看AK8963的控制寄存器2,寄存器地址为:0X0B,各位描述如表40.1.1.11
所示:
表40.1.1.11AK8963控制寄存器2
该寄存器仅最低位有效,用于控制AK8963的软复位,我们在初始化的时候,设置SRST=1
即可让AK8963进行一次软复位,复位结束后,自动设置为0。
最后,我们看看磁力计数据输出寄存器,总共由6个寄存器组成,地址为:0X03~0X08,
通过读取这6个寄存器,就可以读到磁力计x/y/z轴的值,比如x轴的数据,可以通过读取0X03
(低8位)和0X04(高8位)寄存器得到,其他轴以此类推。
关于MPU9250的基础介绍,我们就介绍到这。MPU9250的详细资料和相关寄存器介绍,
请参考光盘:7,硬件资料MPU9250资料和
这两个文档,另外该目录还提供了部分MPU9250的中文资料,供大家参考学习。
40.1.2DMP使用简介
经过40.1.1节的介绍,我们可以读出MPU9250的加速度传感器和角速度传感器的原始数
据。不过这些原始数据,对想搞四轴之类的初学者来说,用处不大,我们期望得到的是姿态数
据,也就是欧拉角:航向角(yaw)、横滚角(roll)和俯仰角(pitch)。有了这三个角,我们就
可以得到当前四轴的姿态,这才是我们想要的结果。
要得到欧拉角数据,就得利用我们的原始数据,进行姿态融合解算,这个比较复杂,知识
点比较多,初学者不易掌握。而MPU9250自带了数字运动处理器,即DMP,并且,InvenSense
提供了一个MPU9250的嵌入式运动处理库(MPL),结合MPU9250的DMP,可以将我们的传
感器原始数据,直接转换成四元数输出,而得到四元数之后,就可以很方便的计算出欧拉角,
从而得到yaw、roll和pitch。
使用内置的DMP,大大简化了四轴的代码设计,且MCU不用进行姿态解算过程,大大降
低了MCU的负担,从而有更多的时间去处理其他事件,提高系统实时性。
InvenSense提供的最新MPL库版本为:6.12版本,它提供了基于STM32F4Discovery板的
参考例程(IAR工程),我们只需要将它移植到我们的开发板上即可。官方原版驱动在光盘:7,
硬件资料MPU9250资料motion_driver_6.12.zip。解压之后,里面有MPL的参考例程
(arm/msp430)、LIB库(mpllibraries)和说明文档(documentation)等资料,大家可以参考
documentation文件夹下的几个PDF教程来学习MPL的使用。
官方MPL库移植起来,还是比较简单的,主要是实现这4个函数:i2c_write,i2c_read,
delay_ms和get_ms,具体细节,我们就不详细介绍了,移植后的驱动代码,我们放在本例程
HARDWAREMPU9250MPL文件夹内,包含4个文件夹,如图40.1.2.1所示:
图40.1.2.1移植后的驱动库代码
为了方便大家使用该驱动库(MPL),我们在inv_里面添加了两个函数:
mpu_dmp_init
和mpu_mpl_get_data这两个函数,这里我们简单介绍下这两个函数。
mpu_dmp_init,是MPU9250DMP初始化函数,该函数代码如下:
//MPU9250,dmp初始化
//返回值:0,正常
//其他,失败
u8mpu_dmp_init(void)
{
u8res=0;
structint_param_sint_param;
unsignedcharaccel_fsr;
unsignedshortgyro_rate,gyro_fsr;
unsignedshortcompass_fsr;
IIC_Init();
//初始化IIC总线
if(mpu_init(int_param)==0)
//初始化MPU9250
{
res=inv_init_mpl();
//初始化MPL
if(res)return1;
inv_enable_quaternion();
inv_enable_9x_sensor_fusion();
inv_enable_fast_nomot();
inv_enable_gyro_tc();
inv_enable_vector_compass_cal();
inv_enable_magnetic_disturbance();
inv_enable_eMPL_outputs();
res=inv_start_mpl();//开启MPL
if(res)return1;
res=mpu_set_sensors(INV_XYZ_GYRO|INV_XYZ_ACCEL|
INV_XYZ_COMPASS);//设置所需要的传感器
if(res)return2;
res=mpu_configure_fifo(INV_XYZ_GYRO|INV_XYZ_ACCEL);//设置FIFO
if(res)return3;
res=mpu_set_sample_rate(DEFAULT_MPU_HZ);
//设置采样率
if(res)return4;
res=mpu_set_compass_sample_rate(1000/COMPASS_READ_MS);//磁力计采样率
if(res)return5;
mpu_get_sample_rate(gyro_rate);
mpu_get_gyro_fsr(gyro_fsr);
mpu_get_accel_fsr(accel_fsr);
mpu_get_compass_fsr(compass_fsr);
inv_set_gyro_sample_rate(1000000L/gyro_rate);
inv_set_accel_sample_rate(1000000L/gyro_rate);
inv_set_compass_sample_rate(COMPASS_READ_MS*1000L);
inv_set_gyro_orientation_and_scale(
inv_orientation_matrix_to_scalar(gyro_orientation),(long)gyro_fsr15);
inv_set_accel_orientation_and_scale(
inv_orientation_matrix_to_scalar(gyro_orientation),(long)accel_fsr15);
inv_set_compass_orientation_and_scale(
inv_orientation_matrix_to_scalar(comp_orientation),(long)compass_fsr15);
res=dmp_load_motion_driver_firmware();//加载dmp固件
if(res)return6;
res=dmp_set_orientation(inv_orientation_matrix_to_scalar(gyro_orientation));
//设置陀螺仪方向
if(res)return7;
res=dmp_enable_feature(DMP_FEATURE_6X_LP_QUAT|DMP_FEATURE_TAP|
DMP_FEATURE_ANDROID_ORIENT|DMP_FEATURE_SEND_RAW_ACCEL|
DMP_FEATURE_SEND_CAL_GYRO|DMP_FEATURE_GYRO_CAL);
//设置dmp功能
if(res)return8;
res=dmp_set_fifo_rate(DEFAULT_MPU_HZ);//设置DMP输出速率(不超过200Hz)
if(res)return9;
res=run_self_test();
//自检
if(res)return10;
res=mpu_set_dmp_state(1);//使能DMP
if(res)return11;
}
return0;
}
此函数首先通过IIC_Init(需外部提供)初始化与MPU9250连接的IIC接口,然后调用
mpu_init函数,初始化MPU9250,之后就是设置DMP所用传感器、FIFO、采样率和加载固件
等一系列操作,在所有操作都正常之后,最后通过mpu_set_dmp_state(1)使能DMP功能,在使
能成功以后,我们便可以通过mpu_mpl_get_data来读取姿态解算后的数据了。
mpu_mpl_get_data函数代码如下:
//得到mpl处理后的数据(注意,本函数需要比较多堆栈,局部变量有点多)
//pitch:俯仰角精度:0.1°范围:-90.0°---+90.0°
//roll:横滚角精度:0.1°范围:-180.0°---+180.0°
//yaw:航向角精度:0.1°范围:-180.0°---+180.0°
//返回值:0,正常
//其他,失败
u8mpu_mpl_get_data(float*pitch,float*roll,float*yaw)
{
unsignedlongsensor_timestamp,timestamp;
shortgyro[3],accel_short[3],compass_short[3],sensors;
unsignedcharmore;
longcompass[3],accel[3],quat[4],temperature;
longdata[9];
int8_taccuracy;
if(dmp_read_fifo(gyro,accel_short,quat,sensor_timestamp,sensors,more))return1;
if(sensorsINV_XYZ_GYRO)
{
inv_build_gyro(gyro,sensor_timestamp);
//把新数据发送给MPL
mpu_get_temperature(temperature,sensor_timestamp);
inv_build_temp(temperature,sensor_timestamp);//发温度值给MPL,仅陀螺仪需要
}
if(sensorsINV_XYZ_ACCEL)
{
accel[0]=(long)accel_short[0];
accel[1]=(long)accel_short[1];
accel[2]=(long)accel_short[2];
inv_build_accel(accel,0,sensor_timestamp);
//把加速度值发给MPL
}
if(!mpu_get_compass_reg(compass_short,sensor_timestamp))
{
compass[0]=(long)compass_short[0];
compass[1]=(long)compass_short[1];
compass[2]=(long)compass_short[2];
inv_build_compass(compass,0,sensor_timestamp);//把磁力计值发给MPL
}
inv_execute_on_data();
inv_get_sensor_type_euler(data,accuracy,×tamp);
*roll=(data[0]/q16);
*pitch=-(data[1]/q16);
*yaw=-data[2]/q16;
return0;
}
此函数用于得到DMP姿态解算后的俯仰角、横滚角和航向角。不过本函数局部变量有点
多,大家在使用的时候,如果死机,那么请设置堆栈大一点(在startup_里面设置,
默认是800)。
利用这两个函数,我们就可以读取到姿态解算后的欧拉角,使用非常方便。DMP部分,我
们就介绍到这。
40.2硬件设计
本实验采用STM32F767的2个普通IO连接MPU9250(IIC),本章实验功能简介:程序先
初始化MPU9250等外设,然后利用MPL库,初始化MPU9250及使能DMP,最后,在死循
环里面不停读取:温度传感器、加速度传感器、陀螺仪、磁力计、MPL姿态解算后的欧拉角等
数据,通过串口上报给上位机(温度不上报),利用上位机软件(ANO_TC匿名科创地面站
),可以实时显示MPU9250的传感器状态曲线,并显示3D姿态,可以通过KEY0按
键开启/关闭数据上传功能。同时,在LCD模块上面显示温度和欧拉角等信息。DS0来指示程
序正在运行。
所要用到的硬件资源如下:
1)指示灯DS0
2)KEY0按键
3)LCD模块
4)串口
5)MPU9250
前4个,在之前的实例已经介绍过了,这里我们仅介绍MPU9250与阿波罗STM32F767开
发板的连接。该接口与MCU的连接原理图如40.2.1所示:
图40.2.1MPU9250与STM32F767的连接电路图
从上图可以看出,MPU9250的SCL和SDA与STM32F767开发板的PH4和PH5连接,与
24C02等共用IIC总线。图中,AD0接的GND,所以MPU9250的器件地址是:0X68。
注意:9D_INT信号,是连接在PCF8574T的P5脚上的,并没有直接连接到MCU,所以,
在需要读取9D_INT的时候,需要先初始化PCF8574T。不过,本例程用不到9D_INT,所以,
可以不初始化PCF8574T,直接通过IIC总线读取数据即可。
40.3软件设计
打开本章实验工程可以看到,我们在HARDWARE分组之下添加了MPU9250驱动源文件
,并且包含了其对应的头文件。同时,将MPL驱动库代码(见光盘例程
源码:实验35MPU9250九轴传感器实验\HARDWARE\MPU9250\MPL目录)添加到新建的
MPL分组之下,工程结构如图39.3.1所示:
图39.3.1MPU9250工程结构图
注意:MPL代码,要求在MDKOptionsforTarget的C/C++选项卡里面,要勾选C99模
式,否则编译出错。
由于篇幅所限,MPL部分的代码,我们就不详细介绍了,请大家参考motion_driver_6.12.zip
里面的相关教程进行学习。我们仅介绍里面的部分函数,首先是:MPU_Init,该函
数代码如下:
//初始化MPU9250
//返回值:0,成功
//其他,错误代码
u8MPU9250_Init(void)
{
u8res=0;
IIC_Init();//初始化IIC总线
MPU_Write_Byte(MPU9250_ADDR,MPU_PWR_MGMT1_REG,0X80);//复位MPU9250
delay_ms(100);//延时100ms
MPU_Write_Byte(MPU9250_ADDR,MPU_PWR_MGMT1_REG,0X00);//唤醒MPU9250
MPU_Set_Gyro_Fsr(3);
//陀螺仪传感器,±2000dps
MPU_Set_Accel_Fsr(0);
//加速度传感器,±2g
MPU_Set_Rate(50);
//设置采样率50Hz
MPU_Write_Byte(MPU9250_ADDR,MPU_INT_EN_REG,0X00);//关闭所有中断
MPU_Write_Byte(MPU9250_ADDR,MPU_USER_CTRL_REG,0X00);//主模式关闭
MPU_Write_Byte(MPU9250_ADDR,MPU_FIFO_EN_REG,0X00);//关闭FIFO
MPU_Write_Byte(MPU9250_ADDR,MPU_INTBP_CFG_REG,0X82);
//INT引脚低电平有效,开启bypass模式,可以直接读取磁力计
res=MPU_Read_Byte(MPU9250_ADDR,MPU_DEVICE_ID_REG);
//读取MPU6500的ID
if(res==MPU6500_ID)//器件ID正确
{
MPU_Write_Byte(MPU9250_ADDR,MPU_PWR_MGMT1_REG,0X01);
//设置CLKSEL,PLLX轴为参考
MPU_Write_Byte(MPU9250_ADDR,MPU_PWR_MGMT2_REG,0X00);
//加速度与陀螺仪都工作
MPU_Set_Rate(50);
//设置采样率为50Hz
}elsereturn1;
res=MPU_Read_Byte(AK8963_ADDR,MAG_WIA);//读取AK8963ID
if(res==AK8963_ID)
{
MPU_Write_Byte(AK8963_ADDR,MAG_CNTL1,0X11);//设置AK8963为单次测量模式
}elsereturn1;
return0;
}
该函数就是按我们在39.1.1节介绍的方法,对MPU9250进行初始化,该函数执行成功后,
便可以读取传感器数据了。
然后,我们再看MPU_Get_Temperature、MPU_Get_Gyroscope、MPU_Get_Accelerometer
和MPU_Get_Magnetometer等四个函数,源码如下:
//得到温度值
//返回值:温度值(扩大了100倍)
shortMPU_Get_Temperature(void)
{
u8buf[2];
shortraw;
floattemp;
MPU_Read_Len(MPU9250_ADDR,MPU_TEMP_OUTH_REG,2,buf);
raw=((u16)buf[0]8)|buf[1];
temp=21+((double)raw)/333.87;
returntemp*100;;
}
//得到陀螺仪值(原始值)
//gx,gy,gz:陀螺仪x,y,z轴的原始读数(带符号)
//返回值:0,成功
//其他,错误代码
u8MPU_Get_Gyroscope(short*gx,short*gy,short*gz)
{
u8buf[6],res;
res=MPU_Read_Len(MPU9250_ADDR,MPU_GYRO_XOUTH_REG,6,buf);
if(res==0)
{
*gx=((u16)buf[0]8)|buf[1];
*gy=((u16)buf[2]8)|buf[3];
*gz=((u16)buf[4]8)|buf[5];
}
returnres;;
}
//得到加速度值(原始值)
//gx,gy,gz:陀螺仪x,y,z轴的原始读数(带符号)
//返回值:0,成功
//其他,错误代码
u8MPU_Get_Accelerometer(short*ax,short*ay,short*az)
{
u8buf[6],res;
res=MPU_Read_Len(MPU9250_ADDR,MPU_ACCEL_XOUTH_REG,6,buf);
if(res==0)
{
*ax=((u16)buf[0]8)|buf[1];
*ay=((u16)buf[2]8)|buf[3];
*az=((u16)buf[4]8)|buf[5];
}
returnres;;
}
//得到磁力计值(原始值)
//mx,my,mz:磁力计x,y,z轴的原始读数(带符号)
//返回值:0,成功
//其他,错误代码
u8MPU_Get_Magnetometer(short*mx,short*my,short*mz)
{
u8buf[6],res;
res=MPU_Read_Len(AK8963_ADDR,MAG_XOUT_L,6,buf);
if(res==0)
{
*mx=((u16)buf[1]8)|buf[0];
*my=((u16)buf[3]8)|buf[2];
*mz=((u16)buf[5]8)|buf[4];
}
MPU_Write_Byte(AK8963_ADDR,MAG_CNTL1,0X11);
//AK8963每次读完以后都需要重新设置为单次测量模式
returnres;;
}
其中MPU_Get_Temperature用于获取MPU9250自带温度传感器的温度值,然后
MPU_Get_Gyroscope、MPU_Get_Accelerometer和MPU_Get_Magnetometer分别用于读取
陀螺仪、加速度传感器和磁力计的原始数据。
最后看MPU_Write_Len和MPU_Read_Len这两个函数,代码如下:
//IIC连续写
//addr:器件地址
//reg:寄存器地址
//len:写入长度
//buf:数据区
//返回值:0,正常
//其他,错误代码
u8MPU_Write_Len(u8addr,u8reg,u8len,u8*buf)
{
u8i;
IIC_Start();
IIC_S_Byte((addr1)|0);
//发送器件地址+写命令
if(IIC_Wait_Ack()){IIC_Stop();return1;}
//等待应答
IIC_S_Byte(reg);
//写寄存器地址
IIC_Wait_Ack();
//等待应答
for(i=0;ilen;i++)
{
IIC_S_Byte(buf[i]);
//发送数据
if(IIC_Wait_Ack()){IIC_Stop();return1;}//等待应答
}
IIC_Stop();
return0;
}
//IIC连续读
//addr:器件地址
//reg:要读取的寄存器地址
//len:要读取的长度
//buf:读取到的数据存储区
//返回值:0,正常
//其他,错误代码
u8MPU_Read_Len(u8addr,u8reg,u8len,u8*buf)
{
IIC_Start();
IIC_S_Byte((addr1)|0);
//发送器件地址+写命令
if(IIC_Wait_Ack()){IIC_Stop();return1;}
//等待应答
IIC_S_Byte(reg);
//写寄存器地址
IIC_Wait_Ack();
//等待应答
IIC_Start();
IIC_S_Byte((addr1)|1);
//发送器件地址+读命令
IIC_Wait_Ack();
//等待应答
while(len)
{
if(len==1)*buf=IIC_Read_Byte(0);
//读数据,发送nACK
else*buf=IIC_Read_Byte(1);
//读数据,发送ACK
len--;
buf++;
}
IIC_Stop();
//产生一个停止条件
return0;
}
MPU_Write_Len用于指定器件和地址,连续写数据,可用于实现MPL部分的:i2c_write
函数。而MPU_Read_Len用于指定器件和地址,连续读数据,可用于实现MPL部分的:i2c_read
函数。MPL移植部分的4个函数,这里就实现了2个,剩下的delay_ms就直接采用我们
里面的delay_ms实现,get_ms则直接提供一个空函数即可。
关于我们就介绍到这,的代码,我们这里就不再贴出了,大家看光
盘源码即可。
最后看看内容,代码如下:
//串口1发送1个字符
//c:要发送的字符
voidusart1_s_char(u8c)
{
while(__HAL_UART_GET_FLAG(UART1_Handler,UART_FLAG_TC)==RESET){};
USART1-TDR=c;
}
//传送数据给匿名四轴地面站(V4版本)
//fun:功能字.0X01~0X1C
//data:数据缓存区,最多28字节!!
//len:data区有效数据个数
voidusart1_niming_report(u8fun,u8*data,u8len)
{
u8s_buf[32];
u8i;
if(len28)return;
//最多28字节数据
s_buf[len+3]=0;
//校验数置零
s_buf[0]=0XAA;
//帧头
s_buf[1]=0XAA;
//帧头
s_buf[2]=fun;
//功能字
s_buf[3]=len;
//数据长度
for(i=0;ilen;i++)s_buf[4+i]=data[i];
//复制数据
for(i=0;ilen+4;i++)s_buf[len+4]+=s_buf[i];//计算校验和
for(i=0;ilen+5;i++)usart1_s_char(s_buf[i]);//发送数据到串口1
}
//发送加速度传感器数据+陀螺仪数据(传感器帧)
//aacx,aacy,aacz:x,y,z三个方向上面的加速度值
//gyrox,gyroy,gyroz:x,y,z三个方向上面的陀螺仪值
voidmpu9250_s_data(shortaacx,shortaacy,shortaacz,shortgyrox,shortgyroy,shortgyroz)
{
u8tbuf[18];
tbuf[0]=(aacx8)0XFF;
tbuf[1]=aacx0XFF;
tbuf[2]=(aacy8)0XFF;
tbuf[3]=aacy0XFF;
tbuf[4]=(aacz8)0XFF;
tbuf[5]=aacz0XFF;
tbuf[6]=(gyrox8)0XFF;
tbuf[7]=gyrox0XFF;
tbuf[8]=(gyroy8)0XFF;
tbuf[9]=gyroy0XFF;
tbuf[10]=(gyroz8)0XFF;
tbuf[11]=gyroz0XFF;
tbuf[12]=0;//开启MPL后,无法直接读取磁力计数据,所以这里直接屏蔽掉.用0替代.
tbuf[13]=0;
tbuf[14]=0;
tbuf[15]=0;
tbuf[16]=0;
tbuf[17]=0;
usart1_niming_report(0X02,tbuf,18);//传感器帧,0X02
}
//通过串口1上报结算后的姿态数据给电脑(状态帧)
//roll:横滚角.单位0.01度。-18000-18000对应-180.00-180.00度
//pitch:俯仰角.单位0.01度。-9000-9000对应-90.00-90.00度
//yaw:航向角.单位为0.1度0-3600对应0-360.0度
//csb:超声波高度,单位:cm
//prs:气压计高度,单位:mm
voidusart1_report_imu(shortroll,shortpitch,shortyaw,shortcsb,intprs)
{
u8tbuf[12];
tbuf[0]=(roll8)0XFF;
tbuf[1]=roll0XFF;
tbuf[2]=(pitch8)0XFF;
tbuf[3]=pitch0XFF;
tbuf[4]=(yaw8)0XFF;
tbuf[5]=yaw0XFF;
tbuf[6]=(csb8)0XFF;
tbuf[7]=csb0XFF;
tbuf[8]=(prs24)0XFF;
tbuf[9]=(prs16)0XFF;
tbuf[10]=(prs8)0XFF;
tbuf[11]=prs0XFF;
usart1_niming_report(0X01,tbuf,12);//状态帧,0X01
}
intmain(void)
{
u8t=0,report=1;
//默认开启上报
u8key;
floatpitch,roll,yaw;
//欧拉角
shortaacx,aacy,aacz;
//加速度传感器原始数据
shortgyrox,gyroy,gyroz;
//陀螺仪原始数据
shorttemp;
//温度
Cache_Enable();//打开L1-Cache
MPU_Memory_Protection();//保护相关存储区域
HAL_Init();
//初始化HAL库
Stm32_Clock_Init(432,25,2,9);//设置时钟,216Mhz
delay_init(180);
//初始化延时函数
…//此处省略部分初始化代码
while(mpu_dmp_init())
{
LCD_ShowString(30,130,200,16,16,"MPU9250Error");delay_ms(200);
LCD_Fill(30,130,239,130+16,WHITE);delay_ms(200);
LED0_Toggle;//DS0闪烁
}
LCD_ShowString(30,130,200,16,16,"MPU9250OK");
LCD_ShowString(30,150,200,16,16,"KEY0:UPLOADON/OFF");
POINT_COLOR=BLUE;//设置字体为蓝色
LCD_ShowString(30,170,200,16,16,"UPLOADON");
LCD_ShowString(30,200,200,16,16,"Temp:.C");
LCD_ShowString(30,220,200,16,16,"Pitch:.C");
LCD_ShowString(30,240,200,16,16,"Roll:.C");
LCD_ShowString(30,260,200,16,16,"Yaw:.C");
while(1)
{
key=KEY_Scan(0);
if(key==KEY0_PRES)
{
report=!report;
if(report)LCD_ShowString(30,170,200,16,16,"UPLOADON");
elseLCD_ShowString(30,170,200,16,16,"UPLOADOFF");
}
if(mpu_mpl_get_data(pitch,roll,yaw)==0)
{
temp=MPU_Get_Temperature();//得到温度值
MPU_Get_Accelerometer(aacx,aacy,aacz);//得到加速度传感器数据
MPU_Get_Gyroscope(gyrox,gyroy,gyroz);//得到陀螺仪数据
if(report)mpu9250_s_data(aacx,aacy,aacz,gyrox,gyroy,gyroz);
//发送加速度+陀螺仪原始数据
if(report)usart1_report_imu((int)(roll*100),(int)(pitch*100),(int)(yaw*100),0,0);
if((t%10)==0)
{
if(temp0)
{
LCD_ShowChar(30+48,200,'-',16,0);
//显示负号
temp=-temp;
//转为正数
}elseLCD_ShowChar(30+48,200,'',16,0);
//去掉负号
LCD_ShowNum(30+48+8,200,temp/100,3,16);
//显示整数部分
LCD_ShowNum(30+48+40,200,temp%10,1,16);
//显示小数部分
temp=pitch*10;
if(temp0)
{
LCD_ShowChar(30+48,220,'-',16,0);
//显示负号
temp=-temp;
//转为正数
}elseLCD_ShowChar(30+48,220,'',16,0);
//去掉负号
LCD_ShowNum(30+48+8,220,temp/10,3,16);
//显示整数部分
LCD_ShowNum(30+48+40,220,temp%10,1,16);
//显示小数部分
temp=roll*10;
if(temp0)
{
LCD_ShowChar(30+48,240,'-',16,0);
//显示负号
temp=-temp;
//转为正数
}elseLCD_ShowChar(30+48,240,'',16,0);
//去掉负号
LCD_ShowNum(30+48+8,240,temp/10,3,16);
//显示整数部分
LCD_ShowNum(30+48+40,240,temp%10,1,16);
//显示小数部分
temp=yaw*10;
if(temp0)
{
LCD_ShowChar(30+48,260,'-',16,0);
//显示负号
temp=-temp;
//转为正数
}elseLCD_ShowChar(30+48,260,'',16,0);
//去掉负号
LCD_ShowNum(30+48+8,260,temp/10,3,16);
//显示整数部分
LCD_ShowNum(30+48+40,260,temp%10,1,16);
//显示小数部分
t=0;
LED0_Toggle;//DS0闪烁
}
}
t++;
}
}
此部分代码除了main函数,还有几个函数,用于上报数据给上位机软件,利用上位机软件
显示传感器波形,以及3D姿态显示,有助于更好的调试MPU9250。上位机软件使用:ANO_TC
匿名科创地面站,该软件在:开发板光盘6,软件资料软件匿名地面站文件夹里
面可以找到,该软件的使用方法,见该文件夹下的:飞控通信协议,这里我们
不做介绍。其中,usart1_niming_report函数用于将数据打包、计算校验和,然后上报给匿名地
面站软件。MPU9250_s_data函数用于上报加速度和陀螺仪的原始数据,可用于波形显示传
感器数据,通过传感器帧(02H)发送。而usart1_report_imu函数,则用于上报飞控显示帧,
可以实时3D显示MPU9250的姿态,传感器数据等,通过状态帧(01H)发送。
这里,main函数是比较简单的,大家看代码即可,不过需要注意的是,为了高速上传数据,
这里我们将串口1的波特率设置为500Kbps了,测试的时候要注意下。
至此,我们的软件设计部分就结束了。
40.4下载验证
在代码编译成功之后,我们通过下载代码到ALIENTEK阿波罗STM32开发板上,可以看
到LCD显示如图40.4.1所示的内容:
图40.4.1程序运行时LCD显示内容
屏幕显示了MPU9250的温度、俯仰角(pitch)、横滚角(roll)和航向角(yaw)的数值。
然后,我们可以晃动开发板,看看各角度的变化。
另外,通过按KEY0可以开启或关闭数据上报,开启状态下,我们可以打开:ANO_TC匿
名科创地面站,这个软件,接收STM32F767上传的数据,从而图形化显示传感器数据以
及飞行姿态,如图40.4.2和图40.4.3所示:
图40.4.2传感器数据波形显示
图40.4.3飞控状态显示
图40.4.2就是波形化显示我们通过MPU9250_s_data函数发送的数据,采用传感器帧(02)
发送,总共6条线(ACC_X、ACC_Y、ACC_Z、GYRO_X、GYRO_Y和GYRO_Z)显示波形,
全部来自传感器帧,分别代表:加速度传感器x/y/z和角速度传感器(陀螺仪)x/y/z方向的原
始数据(请注意把选项“程序设置-上位机设置-数据校验”设置为Off,否则可能看不到数
据和飞控状态变化)。
图图40.4.3则3D显示了我们开发板的姿态,通过usart1_report_imu函数发送的数据显示,
采用状态帧(01)上传,同时还显示了加速度陀螺仪等传感器的原始数据。
很赞哦!(60)