MPU6050/MPU9150传感器的DMP数据读取中遇到的问题总结

MPU6050/MPU9150传感器的DMP数据读取中遇到的问题总结

源代码的问题,本文就不啰嗦了,大家参考正点原子的MPU6050例程即可。MPU9150和MPU6050用一模一样的代码就可以。
本文只罗列在DMP使用过程中遇到的坑和解法。

问题1:MPU6050的AD0引脚接了3.3V,器件地址在程序中设置了是0X69,但是初始化不成功?

首先,一般的初始化代码大致如下:

//初始化MPU6050
//返回值:0,成功
//    其他,错误代码
u8 MPU_Init(void)
{ 
	u8 res;
	IIC_Init();//初始化IIC总线
    MPU_Write_Byte(MPU_PWR_MGMT1_REG,0X80);	//复位MPU6050
    delay_ms(100);
	MPU_Write_Byte(MPU_PWR_MGMT1_REG,0X00);	//唤醒MPU6050 
	
	MPU_Set_Gyro_Fsr(3);					//陀螺仪传感器,±2000dps
	MPU_Set_Accel_Fsr(0);					//加速度传感器,±2g
	MPU_Set_Rate(50);						//设置采样率50Hz
	MPU_Write_Byte(MPU_INT_EN_REG,0X00);	//关闭所有中断
	MPU_Write_Byte(MPU_USER_CTRL_REG,0X00);	//I2C主模式关闭
	MPU_Write_Byte(MPU_FIFO_EN_REG,0X00);	//关闭FIFO
	MPU_Write_Byte(MPU_INTBP_CFG_REG,0X80);	//INT引脚低电平有效
	res=MPU_Read_Byte(MPU_DEVICE_ID_REG);

	if(res==MPU_ADDR) //器件ID正确 // 注意这里MPU_ADDR=0X69
	{
		MPU_Write_Byte(MPU_PWR_MGMT1_REG,0X01);	//设置CLKSEL,PLL X轴为参考
		MPU_Write_Byte(MPU_PWR_MGMT2_REG,0X00);	//加速度与陀螺仪都工作
		MPU_Set_Rate(50);						//设置采样率为50Hz
 	}else return 1; // 返回1,代表初始化失败

	return 0; // 返回0,代表初始化成功
}

大家可以在这段初始化代码里设置断点,看看问题发生在哪个位置!

解法1:

  • 若是在"if(res==MPU_ADDR) "这句话以前就发生问题了,那么应该是I2C的设置有问题,连线出错了,或者是电源电压,总之硬件和软件I2C的配置应该有问题。
  • 若是问题发生在"if(res==MPU_ADDR) ",那么大家可以打印出"res"这个变量,这个变量的值应该是0X68。因此,肯定和我们设置好的"MPU_ADDR=0X69"不符了,自然初始化就运行不下去了。这时候解决方法很简单:
if(res==MPU_ADDR)  》》改成》》 if(res==0x68)

至于为什么AD0接了3.3V,器件返回的地址还是0X68?
这个其实是我们自己弄混了。器件地址就是0X68,这是内置的。至于我们通过AD0接了3.3V,改变的只是器件的操作地址,我们必须通过0X69来操作器件了。而器件自己认为自己的地址还是0X68。

问题2:AD0引脚接了3.3V,MPU6050初始化成功,但是DMP的初始化(mpu_dmp_init)失败,导致欧拉角数据全为0?

mpu_dmp_init函数的代码如下:

//mpu6050,dmp初始化
//返回值:0,正常
//    其他,失败
u8 mpu_dmp_init(void)
{
	u8 res=0;
	IIC_Init(); 		//初始化IIC总线
	
	if(mpu_init()==0)	//初始化MPU6050
	{	
		res=mpu_set_sensors(INV_XYZ_GYRO|INV_XYZ_ACCEL);//设置所需要的传感器
		if(res)return 1; 
		res=mpu_configure_fifo(INV_XYZ_GYRO | INV_XYZ_ACCEL);//设置FIFO
		if(res)return 2; 
		res=mpu_set_sample_rate(DEFAULT_MPU_HZ);	//设置采样率
		if(res)return 3; 
		res=dmp_load_motion_driver_firmware();		//加载dmp固件
		if(res)return 4; 
		res=dmp_set_orientation(inv_orientation_matrix_to_scalar(gyro_orientation));//设置陀螺仪方向
		if(res)return 5; 
		res=dmp_enable_feature(DMP_FEATURE_6X_LP_QUAT|DMP_FEATURE_TAP|	//设置dmp功能
		    DMP_FEATURE_ANDROID_ORIENT|DMP_FEATURE_SEND_RAW_ACCEL|DMP_FEATURE_SEND_CAL_GYRO|
		    DMP_FEATURE_GYRO_CAL);
		if(res)return 6; 
		res=dmp_set_fifo_rate(DEFAULT_MPU_HZ);	//设置DMP输出速率(最大不超过200Hz)
		if(res)return 7;   
		res=run_self_test();		//自检
		if(res)return 8;    
		res=mpu_set_dmp_state(1);	//使能DMP
		if(res)return 9;
	}
	return 0;
}

老实说,这段代码写得很瞎。没想到这还是官方提供的。我们先分析一下这段代码:

if(mpu_init()==0)
{
	***
}

这句话说明,mpu_init()返回值是0时,才执行if语句内部的DMP初始化命令,也就是说mpu_init()返回值必须是0啊,要是不是0,连DMP初始化命令都不执行,那DMP初始化肯定失败呀。

但是,往下看你会发现,要是mpu_init()返回值不是0的话,不执行if语句,那么就直接跳到return 0这句话上了。而返回值为0,代表的是初始化正常。。。

看到这,我真是无语了。。。我之前一直认为DMP初始化成功了,只是数据读不出来。结果发现这里有问题,我也是费了好大一番劲呢。

解法2:

我遇到的问题是mpu_init()返回值不是0,然后直接没有运行DMP的初始化命令。
首先,MPU初始化成功了,另外原始数据也可以读到,可以说明I2C应该没有问题。应该问题就是出在DMP初始化上了。
一步步的追溯发现了问题的根源:

mpu_dmp_init()
  |-- mpu_init()
    |-- if (i2c_write(st.hw->addr, st.reg->pwr_mgmt_1, 1, data))  return -1; // 这句话中出错了,返回了-1

我发现在上面这句if语句中出错了,返回了-1。于是,我进一步查看了st.hw->addr这个变量的数值,发现这个变量被设置成了0X68。。。
我的AD0引脚接了3.3V了啊,这里必须得是0X69呀,于是我改成了0X69。一切都恢复正常了,可以读到欧拉角数据了。

这里我不得不再吐槽吐槽,这个地方的地址要改,怎么从来没有人说过呢???
改的位置,我告诉大家:

// 这可以在inv_mpu.c文件的开头部分找到
const struct hw_s hw={
  0x69,	 //addr // 就是这里
  1024,	 //max_fifo
  118,	 //num_reg
  340,	 //temp_sens
  -521,	 //temp_offset
  256	 //bank_size
};

问题3:MPU6050初始化成功,DMP的初始化成功,但读出来的欧拉角数据全为0?

解法3:

这个问题很常见,就是FIFO溢出导致的。大家可以缩短读取数据的间隔时间,避免数据溢出。

while(mpu_dmp_get_data(&pitch,&roll,&yaw)!=0){}

试试看这句话,如果是因为FIFO溢出的话,写上这句话,肯定就能读出来了。

总结

MPU6050/MPU9150的数据读取阶段可以分成:

  • I2C配置
  • MPU6050/MPU9150的初始化
  • DMP功能初始化
  • 读取原始数据和欧拉角

问题可能出现的位置:

  • MPU6050/MPU9150的初始化就不成功,那么需要检查I2C的问题了,或者是地址的配置问题,硬件层面的问题可能性很大。
  • 读取原始数据可以,但欧拉角不行。那说明 MPU6050/MPU9150的初始化成功了,I2C应该也没什么问题,那就是DMP配置的问题了,这就是软件层面的问题了。
  • 如果DMP配置也没有问题,那么就是FIFO读取时候的问题了。这个容易解决。

最后给大家一点小贴士,一点要用仿真器单步调试程序,定位出问题的位置,这样才能最快的解决问题。一味在网上搜索类似的问题,很可能现象相同,但是根本的原因又完全不同!

你可能感兴趣的:(编程基础知识)