本人大二,这两年才刚接触单片机,这个暑假用MPU6050练习一下I2C通讯,结果I2C还好说,但在使用MPU6050时遇到很多问题,上网查有些问题也没有具体的原因和解决方案。于是有了一个在这里汇总记录一下我遇到的问题和解决办法的主意。要是能顺便帮到也被这些问题所困惑的各位就更好了。由于本文性质更偏向于总结、日记,文中含有一些个人吐槽。
那么接下来就直接进入主题。
I2C
在这里我不多提关于I2C的部分,只说一点。I2C的通讯以我目前了解有两种。一种是全程利用延迟,对SDA和SCL的输出和接收高低电平的时间进行控制以起到通讯作用。二是利用中断接收ACK信号以起到通讯作用。在实际操作中,发现第二种通讯会对DMP的初始化产生影响。
我不打算不多说6050的初始化。无论是哪种I2C,只要能通讯,MPU6050的初始化是肯定没问题的。建议各位如果不确定I2C写的是否正确,可以先读取MPU6050的器件地址,这只和AD0这个引脚的接法有关,接地就是0X68,接电源就是0X69,要是可以正常读取,那就ok。
这里说一下我觉得DMP的一下麻烦的地方。
一. mpu_set_sensors(INV_XYZ_GYRO|INV_XYZ_ACCEL);
//设置所需要的传感器
这一步基本不会出错,只要I2C没问题,肯定是直接过的。
二.mpu_configure_fifo(INV_XYZ_GYRO | INV_XYZ_ACCEL);
//设置FIFO
在实际中发现,上一步设置完传感器后需要延迟一会以便使芯片确认传感器以正常工作。若不予以一定延迟则会使st.chip_cfg.sensors
这条代码的值不正常。
三.mpu_set_sample_rate(DEFAULT_MPU_HZ);
//设置采样率
这一步我在查别的资料时发现也有人会出错,好像是错在st.chip_cfg.dmp_on
这条语句里。这条语句是用来检测DMP是否正常开启,要出错可能会是电源问题。
四.dmp_load_motion_driver_firmware();
//加载dmp固件
就在这一步里我卡了一个星期之多,对这个我简直是万分的痛恨。。。。
这个函数最开始st.chip_cfg.dmp_loaded
是检测DMP是否被加载过,如果是第一次调用就肯定会过。这一步要是出错建议去前面检查一下是否在哪里已经加载过DMP。
接下来是对DMP进行读写测试,这一步问题就来了。很多人(包括我),在memcmp(firmware+ii, cur, this_write)
这一步都过不去。
最后发现是I2C的问题,就是我一开始提到的中断。MEMCMP这个比较函数本身是没问题的,所以问题出在写入和读取的值不相等。然而在实际中,即使我的I2C可以正常通讯(因为MPU6050的初始化是正常的,我可以读出温度值),在这里依然会出现读写错误。上网查资料,网上很多人提到中断问题,有中断的程序在这里很容易被打断I2C读写,导致读写的结果不一致。我一开始以为是什么定时器中断,但是我没用到定时器,所以一直困惑于找不到原因。
后来发现,这里的中断可能指的是I2C通讯里的中断。因为我重写了I2C通讯,全程使用延迟,这个问题就解决了。
五._run_self_test();
//自检
这里也出过问题,我那时候把MPU拿起来晃来晃去在初始化,然后这里没过去,在桌子上放平初始化就好了。
(哇写到这里已经觉得累了,网上写长篇讲解的大佬我感觉已经了解到你们的痛苦了。。。)
主要说一下mpu_dmp_get_data(&pitch,&roll,&yaw);
这个函数的一些常见问题。
if (mpu_read_fifo_stream(dmp.packet_length, fifo_data, more)) return -1;
这条函数返回值要是-1,原因一般有俩。
一是if (!st.chip_cfg.dmp_on)
,检查DMP是否正常。有人会被这个卡住。老样子可能是电源问题。建议检查下电源或者接线。(这个问题也是我在网上看到的,我就奇怪了,你要是这步挂了,那你前面的DMP初始化是怎么过去的0.0,难不成初始化DMP但没有检查DMP是否正常启动?这也太秀了吧。。。。)
二是下面这条FIFO读取
if (fifo_count > (st.hw->max_fifo >> 1)) { /* FIFO is 50% full, better check overflow bit. */ if (i2c_read(st.hw->addr, st.reg->int_status, 1, tmp)) return -5; if (tmp[0] & BIT_FIFO_OVERFLOW) { mpu_reset_fifo(); return -6; } }
-6那个点很多人会有返回值,原因是读取速度太慢。如果是这个地方出现问题,建议用WHILE语句重复调用mpu_dmp_get_data(&pitch,&roll,&yaw);
这条函数,大概率解决问题。
`
if ((quat_mag_sq < QUAT_MAG_SQ_MIN) ||
(quat_mag_sq > QUAT_MAG_SQ_MAX)) {
/* Quaternion is outside of the acceptable threshold. */
mpu_reset_fifo();
sensors[0] = 0;
return -2;
}
要是这句出问题,这句上面的注释已经说明是取得的值超出范围,是DMP初始化中的某一些地方出现了问题,建议仔细排查。
至此我想说的对于MPU6050的使用注意事项就说完了。由于我没有使用到杜邦线等连接线,所以对于一些由于接线导致的问题不了解,就不对此进行分析了。本人才疏学浅,文章中有出错处请多多包涵。
PS:这里的提到的问题都是我在做的时候遇到的,感觉已经把可以遇到的问题全部遇到了个遍。。。18/7/29