这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 活动中心 » 板卡试用 » 镜子里的屏幕——MPU-6050硬件及代码介绍

共1条 1/1 1 跳转至

镜子里的屏幕——MPU-6050硬件及代码介绍

助工
2018-09-18 14:14:54     打赏

Ladies and gentlemen,下面讲一下“镜子里的屏幕”相关MPU-6050的问题。在这个DIY上要用到 MPU-6050 陀螺仪,以前没有接触过它。查了很多资料,在网上很容易就可以找到了需要的代码,但都是STM32F1的相关代码,需要做的就是把代码移植到自己要用的开发板上。

PS:本篇以及下一篇帖子一样拥有视频讲解,且更为详细,欢迎大家观看。视频地址链接:https://v.youku.com/v_show/id_XMzgyMjA5MzA4NA==.html

这个小东西还真是有些复杂,原谅楼主偷了个懒,看到dmp有些懵逼,就直接获得的原始数据,通过对原始数据的分析实现了一部分功能。


一.硬件结构

MPU6050 模块的硬件原理图如图所示。

6.jpg


它的硬件非常简单,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的设计原理和过程。共同学习,共同进步!!!!









共1条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]