用STM32实现MPU6050原始数据的读取

用STM32实现MPU6050原始数据的读取

最近项目组在做自主导航的小车,需要读取底盘的姿态,所以准备往上面加mpu6050,于是整理了这样的文档供以后学习,程序是在正点原子的库上更改的。

了解MPU6050

MPU-60x0 是全球首例 9 轴运动处理传感器。它集成了 3 轴MEMS陀螺仪,3 轴MEMS加速度计,以及一个可扩展的数字运动处理器 DMP(Digital Motion Processor)。 MPU-60x0 对陀螺仪和加速度计分别用了三个 16 位的 ADC,将其测量的模拟量转化为可输出的数字量。为了精确跟踪快速和慢速的运动,传感器的测量范围都是用户可控的,陀螺仪可测范围为 ±250,±500,±1000,±2000°/秒(dps),加速度计可测范围为 ±2,±4,±8,±16g。

简单总结的话,mpu6050使用陀螺仪传感器测角度,使用加速度传感器测加速度。

同时,mpu6050有自带的I2C接口连接非惯性的数字传感器,比如压力传感器。其内部也集成了温度传感器,以及一个dmp数字运动处理器,可以解算mpu6050获取的原始数据,进行片内处理。

接线

我们测试时使用的是战舰V3开发板,其中

  • VCC→3.3V
  • GND→GND
  • SCL→PB10
  • SDA→ PB11
    注:PB10,PB11,是模拟I2C协议的引脚,可以随软件设置而更改。

IIC协议

MPU6050是一个 I2C 器件,里面有很多寄存器(但是我们用到的只有几个),我们通过读写寄存器来操作这个芯片。所以首要问题就是STM32 和 MPU6050 的 I2C 通信。

软件模拟IIC

首先初始化IIC

void MPU_IIC_Init(void)
{          
  GPIO_InitTypeDef  GPIO_InitStructure;
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10|GPIO_Pin_11; 
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;   
  GPIO_Init(GPIOB, &GPIO_InitStructure);  
  GPIO_SetBits(GPIOB,GPIO_Pin_10|GPIO_Pin_11);  
 }

其次要用软件模拟吃IIC的起始信号、停止信号、应答信号。这三个信号是IIC通信所要用到的信号,具体底层的原理就不在本文中仔细讲解,软件模拟时主要时要模拟出IIC通信信号的时许与对应电平

void MPU_IIC_Start(void);//产生IIC起始信号
void MPU_IIC_Stop(void);//产生IIC停止型号
u8 MPU_IIC_Wait_Ack(void);//等待响应
void MPU_IIC_Ack(void);//产生IIC响应信号
void MPU_IIC_NAck(void);//不响应
void MPU_IIC_Send_Byte(u8 txd);//发送数据
u8 MPU_IIC_Read_Byte(unsigned char ack);//读取数据

IIC模块都有其地址,MPU6050的地址时通过模块上AD0引脚设置的,AD0接地或者悬空,芯片地址为0x68,接3.3V时,芯片地址为0x69。

通过IIC读取MPU6050寄存器

读寄存器
1.发送起始信号
2.发送设备地址(写模式)
3.发送内部寄存器地址
4.写入寄存器数据(8 位数据宽度)
5.发送结束信号
写寄存器
1.发送起始信号
2.发送设备地址(写模式)
3.发送内部寄存器地址
4.发送重复起始信号
5.发送设备地址(读模式)
6.读取寄存器数据(8 位数据宽度)
7.发送结束信号

内部传感器的地址可以通过手册查询。

实现传感器功能

传感器初始化

u8 MPU_Init(void)//采用带返回值的函数,是因为采用杜邦线连接,干扰比较大,容易初始化失败,所以根据返回值判断是否初始化成功
{ 
  u8 res;
  GPIO_InitTypeDef  GPIO_InitStructure;
  
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE); 
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
  
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15; 
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_Init(GPIOA, &GPIO_InitStructure);

  GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE);
  
  MPU_AD0_CTRL=0;//AD0为低电平,地址为0x68
  
  MPU_IIC_Init();
  MPU_Write_Byte(MPU_PWR_MGMT1_REG,0X80); 
  delay_ms(100);
  MPU_Write_Byte(MPU_PWR_MGMT1_REG,0X00);  
  MPU_Set_Gyro_Fsr(3); //设置陀螺仪量程
  MPU_Set_Accel_Fsr(0); //设置加速度计量程
  MPU_Set_Rate(50); 
  MPU_Write_Byte(MPU_INT_EN_REG,0X00); //关中断
  MPU_Write_Byte(MPU_USER_CTRL_REG,0X00); //IIC主模式关闭
  MPU_Write_Byte(MPU_FIFO_EN_REG,0X00)/; //清空FIFO
  MPU_Write_Byte(MPU_INTBP_CFG_REG,0X80); //INT低有效
  MPU_Write_Byte(MPU_PWR_MGMT1_REG,0X01);
  res=MPU_Read_Byte(MPU_DEVICE_ID_REG);//都工作加速度计与陀螺仪都工作
  MPU_Write_Byte(MPU_PWR_MGMT2_REG,0X00);
  MPU_Set_Rate(50); 
  MPU_Write_Byte(MPU_PWR_MGMT1_REG,0X01);
  MPU_Write_Byte(MPU_PWR_MGMT2_REG,0X00);
  MPU_Set_Rate(50); 
  if(res==MPU_ADDR)//判断模块地址正确(0x68)
 {
  MPU_Write_Byte(MPU_PWR_MGMT1_REG,0X01); 
  MPU_Write_Byte(MPU_PWR_MGMT2_REG,0X00); //再次使能加速度计与陀螺仪
  MPU_Set_Rate(50); 
  }else return 1;
 return 0;

传感器初始化之后就可以读取数据了。

u8 MPU_Read_Len(u8 addr,u8 reg,u8 len,u8 *buf)
{ 
  MPU_IIC_Start(); 
 MPU_IIC_Send_Byte((addr<<1)|0);//发送地址+写命令
 if(MPU_IIC_Wait_Ack()) //等待应答
 {
  MPU_IIC_Stop();   
  return 1;  
 }
    MPU_IIC_Send_Byte(reg); //写寄存器地址
    MPU_IIC_Wait_Ack();  //等待应答
    MPU_IIC_Start();
 MPU_IIC_Send_Byte((addr<<1)|1);//发送器件地址+读命令
    MPU_IIC_Wait_Ack();  //等待应答
 while(len)
 {
  if(len==1)*buf=MPU_IIC_Read_Byte(0);//读数据 
  else *buf=MPU_IIC_Read_Byte(1);  //发送应答信号
  len--;
  buf++; 
 }    
    MPU_IIC_Stop(); //发送停止信号
 return 0; 
}

通过读不同的地址,可以获取到加速度计和陀螺仪的原始数据。

u8 MPU_Get_Gyroscope(short *gx,short *gy,short *gz)//读陀螺仪
{
 u8 buf[6],res;  
 res=MPU_Read_Len(MPU_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];
 }  
 return res;;
}

u8 MPU_Get_Accelerometer(short *ax,short *ay,short *az)//读加速度计
{
 u8 buf[6],res;  
 res=MPU_Read_Len(MPU_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];
 }  
 return res;;
}

到此我们就读出了MPU6050的加速度计和陀螺仪的原始数据,可以对他做解算了,这个留到下一篇文章讲。

一些问题以及解决

DMP

我们没有用MPU6050内置的dmp功能。它内置的dmp功能非常强大,但是由于少了一个z轴的观测,所以不是特别好用,在后面的文章中将介绍如何用四元数融合算法,结合hmc5883,来解算出欧拉角。

零偏问题

每块芯片都有一定的零点漂移,要在放平时对芯片进行校准。在放平时,gx,gy,gz都是0;ax,ay为0,az应该为32768/2=16384。

初始化失败问题

用杜邦线连接的MPU6050很容易初始化失败,所以要编写一个while函数来判断,如果没有初始化成功,就继续初始化。如果模块直接插入焊好的IIC接口中,情况会好很多。

相关推荐
©️2020 CSDN 皮肤主题: 数字20 设计师:CSDN官方博客 返回首页