本文用到的资料手册,详见: data-manual/ 常见IC
MPU6050是InvenSense公司推出的全球首款整合性6轴运动处理组件,内带3轴陀螺仪和3轴加速度传感器,并且含有一个第二IIC接口,可用于连接外部磁力传感器,利用自带数字运动处理器(DMP: Digital Motion Processor)硬件加速引擎,通过主IIC接口,可以向应用端输出完整的9轴姿态融合演算数据。有了DMP,我们可以使用InvenSense公司提供的运动处理资料库,非常方便的实现姿态解算,降低了运动处理运算对操作系统的负荷,同时大大降低了开发难度 ,我们常用的模块如下所示。
目前市面上的加速度计从输出上区分为两种,一种是数字的,另一种是模拟的。miniAHRS 使用的是MPU6050三轴加速度计,是I2C接口的数字传感器。通过特定的命令可以配置加速度的量程,并将内部ADC的转换结果读出来。
MPU6050的读数,以LSB为单位的,不是我们的最常用的g(9.8米/秒^ 2),需要最后的转换,我们要知道加速度计灵敏度,通常表示为LSB /g。比方说当我们选择2g的量程时,对应的灵敏度= 16384 LSB/ G 。为了得到最终的力值,单位为g,我们用下面的公式:RX = ADCRx /灵敏度就可以进行计算了,也就是说当x轴的计数为ADCRx 时,那么对应的加速度值就是 (ADCRx/16384)g.
自带数字运动处理(DMP: Digital Motion Processing)引擎可减少MCU复杂的融合演算数据、感测器同步化、姿势感应等的负荷。
自带一个数字温度传感器。
加速度计的工作原理
如果我们把盒子形状的立方体 放在一个没引力场的地方,球会保持在盒子的中间。可以想象,这个盒子是在外太空,远离任何天体,一切都是在失重状态下。那么六个壁面感受到的压力都是0,这样就是没有加速度的,所以我们要测加速度就是测六个壁面的压力,可以理解为六个壁面的都是压敏电阻,然后我们就是测ADC,其实实际情况也是测量ADC数据!
突然将立方体向左侧移动(我们加快加速,1G =9.8米/ S ^ 2),皮球打在了墙上X-。然后,我们测量球作用在X轴上的壁和输出-1g值的压力,这里要注意就是力的作用是相互的,说白了我们测量的其实是参考面的压力,不是真实的压力情况,所以我们这里真实值是实际值的相反数。
同样的我们也可以根据这个原理测量到多轴的数据情况
那么通过矢量合成的方法就可以获取到我们当前的一个角度情况了,下面图中展示了我们的一个新的坐标系,向量R是我们测量得到的矢量,他在XYZ三个轴上就会有对应的分量RX,RY,RZ。
他们的关系如下,这样我们就可以通过反推的方式获取到各个轴的加速度。
陀螺仪的工作原理
MPU6050 集成了三轴的陀螺仪,角速度全格感测范围为±250、±500、±1000与±2000°/sec (dps)。当选择量程为±250dps的时候,将会得到分辩率为131LSB/(º/s)。也就是当载体在X+轴转动1dps时,ADC将输出131。
陀螺仪就不再是检测加速度这样的对壁面的压力了,而是检测绕相应轴的转动速度,MPU6050带有三个陀螺仪,每个陀螺仪各自负责检测相应轴的转动速度,也就是检测围绕各个轴转动的速度。像三轴的陀螺仪将同时检测 X Y Z轴的旋转。
MPU6050的内部框图如下所示:
其中,SCL 和 SDA 是连接 MCU 的 IIC 接口,MCU 通过这个 IIC 接口来控制 MPU6050,另外还有一个 IIC 接口:AUX_CL 和 AUX_DA,这个接口可用来连接外部从设备,比如磁传感器,这样就可以组成一个九轴传感器。VLOGIC 是 IO 口电压,该引脚最低可以到 1.8V,我们一般直接接 VDD 即可。AD0 是从 IIC 接口(接 MCU)的地址控制引脚,该引脚控制IIC 地址的最低位。如果接 GND,则 MPU6050 的 IIC 地址是:0X68,如果接 VDD,则是0X69,注意:这里的地址是不包含数据传输的最低位的(最低位用来表示读写),例 0x68:1101000 + 最低位表示读写,构成8位的IIC地址。
常见的MPU6050的原理图如下所示
基本上就是一个LDO,然后就是芯片电路加上一排引脚了,比较好移植,主要是注意屏蔽还有隔离上的设计
下面来介绍下MPU6050中一些重要的寄存器
数据 | 时钟源 |
---|---|
000 | 内部8MRC晶振 |
001 | PLL,使用X轴陀螺作为参考 |
010 | PLL,使用Y轴陀螺作为参考 |
011 | PLL,使用Z轴陀螺作为参考 |
100 | PLL,使用外部32.768Khz作为参考 |
101 | PLL,使用外部19.2Mhz作为参考 |
110 | 保留 |
111 | 关闭时钟,保持时序产生电路复位伏态 |
一般我们选001,这样精度高点
这里附上数据手册里面的完整寄存器列表:
#define MPU_SELF_TESTX_REG 0X0D //自检寄存器X
#define MPU_SELF_TESTY_REG 0X0E //自检寄存器Y
#define MPU_SELF_TESTZ_REG 0X0F //自检寄存器Z
#define MPU_SELF_TESTA_REG 0X10 //自检寄存器A
#define MPU_SAMPLE_RATE_REG 0X19 //采样频率分频器
#define MPU_CFG_REG 0X1A //配置寄存器
#define MPU_GYRO_CFG_REG 0X1B //陀螺仪配置寄存器
#define MPU_ACCEL_CFG_REG 0X1C //加速度计配置寄存器
#define MPU_MOTION_DET_REG 0X1F //运动检测阀值设置寄存器
#define MPU_FIFO_EN_REG 0X23 //FIFO使能寄存器
#define MPU_I2CMST_CTRL_REG 0X24 //IIC主机控制寄存器
#define MPU_I2CSLV0_ADDR_REG 0X25 //IIC从机0器件地址寄存器
#define MPU_I2CSLV0_REG 0X26 //IIC从机0数据地址寄存器
#define MPU_I2CSLV0_CTRL_REG 0X27 //IIC从机0控制寄存器
#define MPU_I2CSLV1_ADDR_REG 0X28 //IIC从机1器件地址寄存器
#define MPU_I2CSLV1_REG 0X29 //IIC从机1数据地址寄存器
#define MPU_I2CSLV1_CTRL_REG 0X2A //IIC从机1控制寄存器
#define MPU_I2CSLV2_ADDR_REG 0X2B //IIC从机2器件地址寄存器
#define MPU_I2CSLV2_REG 0X2C //IIC从机2数据地址寄存器
#define MPU_I2CSLV2_CTRL_REG 0X2D //IIC从机2控制寄存器
#define MPU_I2CSLV3_ADDR_REG 0X2E //IIC从机3器件地址寄存器
#define MPU_I2CSLV3_REG 0X2F //IIC从机3数据地址寄存器
#define MPU_I2CSLV3_CTRL_REG 0X30 //IIC从机3控制寄存器
#define MPU_I2CSLV4_ADDR_REG 0X31 //IIC从机4器件地址寄存器
#define MPU_I2CSLV4_REG 0X32 //IIC从机4数据地址寄存器
#define MPU_I2CSLV4_DO_REG 0X33 //IIC从机4写数据寄存器
#define MPU_I2CSLV4_CTRL_REG 0X34 //IIC从机4控制寄存器
#define MPU_I2CSLV4_DI_REG 0X35 //IIC从机4读数据寄存器
#define MPU_I2CMST_STA_REG 0X36 //IIC主机状态寄存器
#define MPU_INTBP_CFG_REG 0X37 //中断/旁路设置寄存器
#define MPU_INT_EN_REG 0X38 //中断使能寄存器
#define MPU_INT_STA_REG 0X3A //中断状态寄存器
#define MPU_ACCEL_XOUTH_REG 0X3B //加速度值,X轴高8位寄存器
#define MPU_ACCEL_XOUTL_REG 0X3C //加速度值,X轴低8位寄存器
#define MPU_ACCEL_YOUTH_REG 0X3D //加速度值,Y轴高8位寄存器
#define MPU_ACCEL_YOUTL_REG 0X3E //加速度值,Y轴低8位寄存器
#define MPU_ACCEL_ZOUTH_REG 0X3F //加速度值,Z轴高8位寄存器
#define MPU_ACCEL_ZOUTL_REG 0X40 //加速度值,Z轴低8位寄存器
#define MPU_TEMP_OUTH_REG 0X41 //温度值高八位寄存器
#define MPU_TEMP_OUTL_REG 0X42 //温度值低8位寄存器
#define MPU_GYRO_XOUTH_REG 0X43 //陀螺仪值,X轴高8位寄存器
#define MPU_GYRO_XOUTL_REG 0X44 //陀螺仪值,X轴低8位寄存器
#define MPU_GYRO_YOUTH_REG 0X45 //陀螺仪值,Y轴高8位寄存器
#define MPU_GYRO_YOUTL_REG 0X46 //陀螺仪值,Y轴低8位寄存器
#define MPU_GYRO_ZOUTH_REG 0X47 //陀螺仪值,Z轴高8位寄存器
#define MPU_GYRO_ZOUTL_REG 0X48 //陀螺仪值,Z轴低8位寄存器
#define MPU_I2CSLV0_DO_REG 0X63 //IIC从机0数据寄存器
#define MPU_I2CSLV1_DO_REG 0X64 //IIC从机1数据寄存器
#define MPU_I2CSLV2_DO_REG 0X65 //IIC从机2数据寄存器
#define MPU_I2CSLV3_DO_REG 0X66 //IIC从机3数据寄存器
#define MPU_I2CMST_DELAY_REG 0X67 //IIC主机延时管理寄存器
#define MPU_SIGPATH_RST_REG 0X68 //信号通道复位寄存器
#define MPU_MDETECT_CTRL_REG 0X69 //运动检测控制寄存器
#define MPU_USER_CTRL_REG 0X6A //用户控制寄存器
#define MPU_PWR_MGMT1_REG 0X6B //电源管理寄存器1
#define MPU_PWR_MGMT2_REG 0X6C //电源管理寄存器2
#define MPU_FIFO_CNTH_REG 0X72 //FIFO计数寄存器高八位
#define MPU_FIFO_CNTL_REG 0X73 //FIFO计数寄存器低八位
#define MPU_FIFO_RW_REG 0X74 //FIFO读写寄存器
#define MPU_DEVICE_ID_REG 0X75 //器件ID寄存器
下面我们开始用stm32来读取MPU6050的数据
开启iic,设置成标准或者快速模式都可以的
初始化iic后来寻找设备
源代码如下:
for(uint8_t i=0;i<255;i++)
{
if(HAL_I2C_IsDeviceReady (&hi2c1 ,i ,1 ,1000)== HAL_OK )
{
printf("发现iic设备 %d\r\n",i);
break;
}
}
将程序下载到开发板后,可以看到数据如下所示
这里我们前面提到过,只有前七位是设备地址,最后一位有AD0来决定,所以我们将208(0XD0)进行移位操作,就可以获取到我们的设备地址了,这里读取到的是0X68完全正确
这里就是先定义一个结构体,这样我们后面看数据方便
初始化mpu6050
获取数据,因为他的数据,加速度,角加速度,温度正好是在一起的连续地址,所以我们就可以连续读取数据,读取数据的函数如下所示:
最后在主函数中调用就行了
将程序下载到开发板,可以看书数据如下所示
mpu6050.c
/*
* mpu6050.c
*
* Created on: Mar 5, 2022
* Author: LX
*/
#include "mpu6050.h"
extern I2C_HandleTypeDef hi2c1;
IMU_Parameter IMU_Data;
#define MPU6050_ADDR 0xD0
float gyrox, gyroy, gyroz, accelx, accely, accelz, temp;
void MPU6050_Init(void)
{
uint8_t check,data;
HAL_I2C_Mem_Read(&hi2c1 ,MPU6050_ADDR,MPU_DEVICE_ID_REG,1,&check ,1,0xff); //读设备
if(check == 104)//如果是0x68
{
data = 0x00;
HAL_I2C_Mem_Write(&hi2c1,MPU6050_ADDR,MPU_PWR_MGMT1_REG,1,&data,1,0xff);
data = 0x07;
HAL_I2C_Mem_Write(&hi2c1,MPU6050_ADDR,MPU_SAMPLE_RATE_REG,1,&data,1,0xff);
data = 0x00;
HAL_I2C_Mem_Write(&hi2c1,MPU6050_ADDR,MPU_CFG_REG,1,&data,1,0xff);
data = 0x00;
HAL_I2C_Mem_Write(&hi2c1,MPU6050_ADDR,MPU_GYRO_CFG_REG,1,&data,1,0xff);
}
}
void MPU6050_GET_Data(void)
{
uint8_t buf[14]={0};
HAL_I2C_Mem_Read(&hi2c1,MPU6050_ADDR,MPU_ACCEL_XOUTH_REG,1,buf,14,1000);
accelx = (float) (((int16_t) (buf[0] << 8) + buf[1])/16384.0f);
accely = (float) (((int16_t) (buf[2] << 8) + buf[3])/16384.0f);
accelz = (float) (((int16_t) (buf[4] << 8) + buf[5])/16384.0f);
temp = (float) (((int16_t) (buf[6] << 8) + buf[7])/340 + 36.53f);
gyrox = (float) (((int16_t) (buf[8] << 8) + buf[9])/131.0f);
gyroy = (float) (((int16_t) (buf[10] << 8) + buf[11])/131.0f);
gyroz = (float) (((int16_t) (buf[12] << 8) + buf[13])/131.0f);
IMU_Data.Accel_X = accelx - IMU_Data.offset_Accel_X;
IMU_Data.Accel_Y = accely - IMU_Data.offset_Accel_Y;
IMU_Data.Accel_Z = accelz - IMU_Data.offset_Accel_Z;
IMU_Data.Temp = temp;
IMU_Data.Gyro_X = gyrox - IMU_Data.offset_Gyro_X;
IMU_Data.Gyro_Y = gyroy - IMU_Data.offset_Gyro_Y;
IMU_Data.Gyro_Z = gyroz - IMU_Data.offset_Gyro_Z;
}
mpu6050.h
/*
* mpu6050.h
*
* Created on: Mar 5, 2022
* Author: LX
*/
#ifndef MPU6050_H_
#define MPU6050_H_
#include "main.h"
#define MPU_SELF_TESTX_REG 0X0D //自检寄存器X
#define MPU_SELF_TESTY_REG 0X0E //自检寄存器Y
#define MPU_SELF_TESTZ_REG 0X0F //自检寄存器Z
#define MPU_SELF_TESTA_REG 0X10 //自检寄存器A
#define MPU_SAMPLE_RATE_REG 0X19 //采样频率分频器
#define MPU_CFG_REG 0X1A //配置寄存器
#define MPU_GYRO_CFG_REG 0X1B //陀螺仪配置寄存器
#define MPU_ACCEL_CFG_REG 0X1C //加速度计配置寄存器
#define MPU_MOTION_DET_REG 0X1F //运动检测阀值设置寄存器
#define MPU_FIFO_EN_REG 0X23 //FIFO使能寄存器
#define MPU_I2CMST_CTRL_REG 0X24 //IIC主机控制寄存器
#define MPU_I2CSLV0_ADDR_REG 0X25 //IIC从机0器件地址寄存器
#define MPU_I2CSLV0_REG 0X26 //IIC从机0数据地址寄存器
#define MPU_I2CSLV0_CTRL_REG 0X27 //IIC从机0控制寄存器
#define MPU_I2CSLV1_ADDR_REG 0X28 //IIC从机1器件地址寄存器
#define MPU_I2CSLV1_REG 0X29 //IIC从机1数据地址寄存器
#define MPU_I2CSLV1_CTRL_REG 0X2A //IIC从机1控制寄存器
#define MPU_I2CSLV2_ADDR_REG 0X2B //IIC从机2器件地址寄存器
#define MPU_I2CSLV2_REG 0X2C //IIC从机2数据地址寄存器
#define MPU_I2CSLV2_CTRL_REG 0X2D //IIC从机2控制寄存器
#define MPU_I2CSLV3_ADDR_REG 0X2E //IIC从机3器件地址寄存器
#define MPU_I2CSLV3_REG 0X2F //IIC从机3数据地址寄存器
#define MPU_I2CSLV3_CTRL_REG 0X30 //IIC从机3控制寄存器
#define MPU_I2CSLV4_ADDR_REG 0X31 //IIC从机4器件地址寄存器
#define MPU_I2CSLV4_REG 0X32 //IIC从机4数据地址寄存器
#define MPU_I2CSLV4_DO_REG 0X33 //IIC从机4写数据寄存器
#define MPU_I2CSLV4_CTRL_REG 0X34 //IIC从机4控制寄存器
#define MPU_I2CSLV4_DI_REG 0X35 //IIC从机4读数据寄存器
#define MPU_I2CMST_STA_REG 0X36 //IIC主机状态寄存器
#define MPU_INTBP_CFG_REG 0X37 //中断/旁路设置寄存器
#define MPU_INT_EN_REG 0X38 //中断使能寄存器
#define MPU_INT_STA_REG 0X3A //中断状态寄存器
#define MPU_ACCEL_XOUTH_REG 0X3B //加速度值,X轴高8位寄存器
#define MPU_ACCEL_XOUTL_REG 0X3C //加速度值,X轴低8位寄存器
#define MPU_ACCEL_YOUTH_REG 0X3D //加速度值,Y轴高8位寄存器
#define MPU_ACCEL_YOUTL_REG 0X3E //加速度值,Y轴低8位寄存器
#define MPU_ACCEL_ZOUTH_REG 0X3F //加速度值,Z轴高8位寄存器
#define MPU_ACCEL_ZOUTL_REG 0X40 //加速度值,Z轴低8位寄存器
#define MPU_TEMP_OUTH_REG 0X41 //温度值高八位寄存器
#define MPU_TEMP_OUTL_REG 0X42 //温度值低8位寄存器
#define MPU_GYRO_XOUTH_REG 0X43 //陀螺仪值,X轴高8位寄存器
#define MPU_GYRO_XOUTL_REG 0X44 //陀螺仪值,X轴低8位寄存器
#define MPU_GYRO_YOUTH_REG 0X45 //陀螺仪值,Y轴高8位寄存器
#define MPU_GYRO_YOUTL_REG 0X46 //陀螺仪值,Y轴低8位寄存器
#define MPU_GYRO_ZOUTH_REG 0X47 //陀螺仪值,Z轴高8位寄存器
#define MPU_GYRO_ZOUTL_REG 0X48 //陀螺仪值,Z轴低8位寄存器
#define MPU_I2CSLV0_DO_REG 0X63 //IIC从机0数据寄存器
#define MPU_I2CSLV1_DO_REG 0X64 //IIC从机1数据寄存器
#define MPU_I2CSLV2_DO_REG 0X65 //IIC从机2数据寄存器
#define MPU_I2CSLV3_DO_REG 0X66 //IIC从机3数据寄存器
#define MPU_I2CMST_DELAY_REG 0X67 //IIC主机延时管理寄存器
#define MPU_SIGPATH_RST_REG 0X68 //信号通道复位寄存器
#define MPU_MDETECT_CTRL_REG 0X69 //运动检测控制寄存器
#define MPU_USER_CTRL_REG 0X6A //用户控制寄存器
#define MPU_PWR_MGMT1_REG 0X6B //电源管理寄存器1
#define MPU_PWR_MGMT2_REG 0X6C //电源管理寄存器2
#define MPU_FIFO_CNTH_REG 0X72 //FIFO计数寄存器高八位
#define MPU_FIFO_CNTL_REG 0X73 //FIFO计数寄存器低八位
#define MPU_FIFO_RW_REG 0X74 //FIFO读写寄存器
#define MPU_DEVICE_ID_REG 0X75 //器件ID寄存器
typedef struct
{
float Accel_X;
float Accel_Y;
float Accel_Z;
float offset_Accel_X;
float offset_Accel_Y;
float offset_Accel_Z;
float Gyro_X;
float Gyro_Y;
float Gyro_Z;
float offset_Gyro_X;
float offset_Gyro_Y;
float offset_Gyro_Z;
float Angle_X;
float Angle_Y;
float Angle_Z;
float Temp;
}IMU_Parameter;
void MPU6050_Init(void);
void MPU6050_GET_Data(void);
#endif /* MPU6050_H_ */