Ladies and gentlemen,下面讲一下“镜子里的屏幕”相关MPU-6050的问题。在这个DIY上要用到 MPU-6050 陀螺仪,以前没有接触过它。查了很多资料,在网上很容易就可以找到了需要的代码,但都是STM32F1的相关代码,需要做的就是把代码移植到自己要用的开发板上。
PS:本篇以及下一篇帖子一样拥有视频讲解,且更为详细,欢迎大家观看。视频地址链接:https://v.youku.com/v_show/id_XMzgyMjA5MzA4NA==.html
这个小东西还真是有些复杂,原谅楼主偷了个懒,看到dmp有些懵逼,就直接获得的原始数据,通过对原始数据的分析实现了一部分功能。
一.硬件结构
MPU6050 模块的硬件原理图如图所示。
它的硬件非常简单,SDA与 SCL被引出方便与外部 I2C 主机连接,看图中的右上角,可知该模块的 I2C 通讯引脚 SDA 及 SCL 已经连接了上拉电阻,因此它与外部 I2C 通讯主机通讯时直接使用导线连接起来即可;模块自身的 I2C 设备地址可通过 AD0引脚的电平控制,当 AD0 接地时,设备地址为 0x68(七位地址),当 AD0 接电源时,设备地址为 0x69(七位地址)。另外,当传感器有新数据的时候会通过 INT 引脚通知 STM32。
二.原理介绍
说一下对他的理解。其实也不是特别的复杂,MPU-6050就是一个I2C器件,就像一个微控制器,通过它得到原始的数据信息,经过分析就知道当前的姿态,可以把他想象成一个黑箱,不需要懂他,只需要会使用它就行。首先得了解他的寄存器,知道如何初始化,读取,写入等等。都是套路其实,看着照葫芦画瓢就行。
三.硬件设计
VCC —— 3.3V
GND —— GND
SCL —— PB10
SDA —— PB11
AD0 —— 悬空或接地
四.软件设计
MPU-6050采用I2C通信,在STM32中,有硬件和软件I2C两种方式,大部分情况下,不使用硬件I2C,而是通过软件I2C模拟。因为STM32的硬件I2C非常复杂,更重要的是不稳定,故不推荐使用。所以这里通过软件模拟来实现,有兴趣的同学可以研究一下STM32的硬件I2C。
//开始信号 void i2c_Start(void) { I2C_SDA_1(); I2C_SCL_1(); __nop(); I2C_SDA_0(); __nop(); I2C_SCL_0(); __nop(); } //停止信号 void i2c_Stop(void) { I2C_SDA_0(); I2C_SCL_1(); __nop(); I2C_SDA_1(); } //发送一个字节 void i2c_SendByte(uint8_t _ucByte) { uint8_t i; /* 先发送字节的高位bit7 */ for (i = 0; i < 8; i++) { if (_ucByte & 0x80) { I2C_SDA_1(); } else { I2C_SDA_0(); } __nop(); I2C_SCL_1(); __nop(); I2C_SCL_0(); if (i == 7) { I2C_SDA_1(); } _ucByte <<= 1; // 左移一个bit __nop(); } } //读取一个字节 uint8_t i2c_ReadByte(u8 ack) { uint8_t i; uint8_t value; /* 读到第1个bit为数据的bit7 */ value = 0; for (i = 0; i < 8; i++) { value <<= 1; I2C_SCL_1(); __nop(); if (I2C_SDA_READ()) { value++; } I2C_SCL_0(); __nop(); } if(ack==0) i2c_NAck(); else i2c_Ack(); return value; } //是否产生应答信号ACK uint8_t i2c_WaitAck(void) { uint8_t re; I2C_SDA_1(); __nop(); I2C_SCL_1(); __nop(); if (I2C_SDA_READ()) // CPU读取SDA口线状态 { re = 1; } else { re = 0; } I2C_SCL_0(); __nop(); return re; } //产生一个应答信号ACK void i2c_Ack(void) { I2C_SDA_0(); __nop();__nop(); I2C_SCL_1(); __nop();__nop(); I2C_SCL_0(); __nop();__nop(); I2C_SDA_1(); } //产生1个NACK信号 void i2c_NAck(void) { I2C_SDA_1(); __nop();__nop(); I2C_SCL_1(); __nop();__nop(); I2C_SCL_0(); __nop();__nop(); }
******************************分割线***********************************
下面开始写MPU-6050的代码。
// 写数据到MPU6050寄存器 void MPU6050_WriteReg(u8 reg_add,u8 reg_dat) { i2c_Start(); i2c_SendByte(MPU6050_SLAVE_ADDRESS); i2c_WaitAck(); i2c_SendByte(reg_add); i2c_WaitAck(); i2c_SendByte(reg_dat); i2c_WaitAck(); i2c_Stop(); } //从MPU6050寄存器读取数据 void MPU6050_ReadData(u8 reg_add,unsigned char*Read,u8 num) { unsigned char i; i2c_Start(); i2c_SendByte(MPU6050_SLAVE_ADDRESS); i2c_WaitAck(); i2c_SendByte(reg_add); i2c_WaitAck(); i2c_Start(); i2c_SendByte(MPU6050_SLAVE_ADDRESS+1); i2c_WaitAck(); for(i=0;i<(num-1);i++){ *Read=i2c_ReadByte(1); Read++; } *Read=i2c_ReadByte(0); i2c_Stop(); } //初始化MPU6050芯片 void MPU6050_Init(void) { int i=0,j=0; //在初始化之前要延时一段时间,若没有延时,则断电后再上电数据可能会出错 for(i=0;i<1000;i++) { for(j=0;j<1000;j++) { ; } } MPU6050_WriteReg(MPU6050_RA_PWR_MGMT_1, 0x00); //解除休眠状态 MPU6050_WriteReg(MPU6050_RA_SMPLRT_DIV , 0x07); //陀螺仪采样率,1KHz MPU6050_WriteReg(MPU6050_RA_CONFIG , 0x06); //低通滤波器的设置,截止频率是1K,带宽是5K MPU6050_WriteReg(MPU6050_RA_ACCEL_CONFIG , 0x00); //配置加速度传感器工作在2G模式,不自检 MPU6050_WriteReg(MPU6050_RA_GYRO_CONFIG, 0x18); //陀螺仪自检及测量范围,典型值:0x18(不自检,2000deg/s) } //读取MPU6050的角加速度数据 void MPU6050ReadGyro(short *gyroData) { u8 buf[6]; MPU6050_ReadData(MPU6050_GYRO_OUT,buf,6); gyroData[0] = (buf[0] << 8) | buf[1]; gyroData[1] = (buf[2] << 8) | buf[3]; gyroData[2] = (buf[4] << 8) | buf[5]; } //读取原始温度 void MPU6050ReadTemp(short *tempData) { u8 buf[2]; MPU6050_ReadData(MPU6050_RA_TEMP_OUT_H,buf,2); *tempData = (buf[0] << 8) | buf[1]; } // 读取MPU6050的温度数据,转化成摄氏度 void MPU6050_ReturnTemp(float *Temperature) { short temp3; u8 buf[2]; MPU6050_ReadData(MPU6050_RA_TEMP_OUT_H,buf,2); temp3= (buf[0] << 8) | buf[1]; *Temperature=((double) temp3/340.0)+36.53; }
这里需要注意,所得到的加速度数据是未经过处理的原始数据,在使用过程中需要分析其中规律。还有就是陀螺仪检测的温度会受自身芯片发热的影响,严格来说它测量的是自身芯片的温度,所以用它来测量气温是不太准确的。
再说一个问题,MPU-6050的姿态算法是有专门的算法的,官方已经给出,那就是DMP算法,DMP更加接近于实际应用,大家可以了解了解。
到这里关于MPU-6050的设计就可以了,在下一篇将介绍RTC时钟和OLED的设计原理和过程。共同学习,共同进步!!!!