欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  科技

STM32通过IIC读取MPU6050原始数据过程详解

程序员文章站 2022-03-16 11:06:08
STM32通过IIC读取MPU6050数据过程详解一:硬件介绍此款MPU6050是通过IIC来与MCU通信的,它有两个IIC接口,第一个是SCL和SDA与主IIC通信;第二个是AUX_CL和AUX_DA,这个接口可用来连接外部从设备,比如磁传感器,这样就可以组成一个九轴传感器。VLOGIC 是 IO 口电压,该引脚最低可以到 1.8V,我们一般直接接 VDD 即可。AD0 是从 IIC 接口(接 MCU)的地址控制引脚,该引脚控制IIC 地址的最低位。如果接 GND,则 MPU6050 的 IIC 地...

STM32通过IIC读取MPU6050数据过程详解

一:硬件介绍
STM32通过IIC读取MPU6050原始数据过程详解

STM32通过IIC读取MPU6050原始数据过程详解此款MPU6050是通过IIC来与MCU通信的,它有两个IIC接口,第一个是主IIC,通过SCL和SDA两条线与MCU通信;第二个辅助IIC通道,通过AUX_CL和AUX_DA连接外部从设备,比如磁传感器,这样就可以组成一个九轴传感器。VLOGIC 是 IO 口电压,该引脚最低可以到 1.8V,我们一般直接接 VDD 即可。AD0 是从 IIC 接口(接 MCU)的地址控制引脚,该引脚控制IIC 地址的最低位。如果接 GND,则 MPU6050 的 IIC 地址是:0X68,如果接 VDD,则是0X69,注意:这里的地址是不包含数据传输的最低位的(最低位用来表示读写)!!

这里是 ATK-MPU6050 模块与MiniSTM32F103 开发板的连接。ATK-MPU6050 模块原理图如下图所示:
STM32通过IIC读取MPU6050原始数据过程详解从上图可知,ATK-MPU6050 模块,通过 P1 排针与外部连接,引出了 VCC、GND、IIC_SDA、IIC_SCL、MPU_INT 和MPU_AD0 等信号,其中,IIC_SDA 和 IIC_SCL 带了 4.7K上拉电阻,外部可以不用再加上拉电阻了,另外 MPU_AD0 自带了 10K 下拉电阻,当 AD0悬空时,默认 IIC 地址为(0X68)
引脚说明:
STM32通过IIC读取MPU6050原始数据过程详解

二:相关寄存器介绍

1:电源管理寄存器(0x6B)
STM32通过IIC读取MPU6050原始数据过程详解
该寄存器的地址为0x6B,其中DEVICE_RESET 位用来控制复位,设置为 1,复位 MPU6050,复位结束后,MPU硬件自动清零该位。SLEEEP 位用于控制 MPU6050 的工作模式,复位后,该位为 1,即进入了睡眠模式(低功耗),所以我们要清零该位,以进入正常工作模式。TEMP_DIS 用于设置是否使能温度传感器,设置为 0,则使能。最后 CLKSEL[2:0]用于选择系统时钟源,选择关系如表 1.1.1 所示:
STM32通过IIC读取MPU6050原始数据过程详解STM32通过IIC读取MPU6050原始数据过程详解默认是使用内部 8M RC 晶振的,精度不高,所以我们一般选择 X/Y/Z 轴陀螺作为参考的 PLL 作为时钟源,一般设置 CLKSEL=001 即可.

2:陀螺仪配置寄存器(0x1B)
STM32通过IIC读取MPU6050原始数据过程详解该寄存器地址为:0X1B, 其中FS_SEL[1:0]这两个位用于设置陀螺仪的满量程范围:0,±250°/S;1,±500°/S;2,±1000°/S;3,±2000°/S;我们一般设置为 3,即±2000°/S,因为陀螺仪的 ADC 为 16 位分辨率,所以得到灵敏度为:65536/4000=16.4LSB/(°/S)。

3:加速度传感器配置寄存器(0x1C)
STM32通过IIC读取MPU6050原始数据过程详解该寄存器地址为:0X1C,其中AFS_SEL[1:0]这两个位,用于设置加速度传感器的满量程范围:0,±2g;1,±4g;2,±8g;3,±16g;我们一般设置为 0,即±2g,因为加速度传感器的ADC 也是 16 位,所以得到灵敏度为:65536/4=16384LSB/g。

4: FIFO 使能寄存器(0X1C)
STM32通过IIC读取MPU6050原始数据过程详解
该寄存器地址为:0X1C,用于控制 FIFO 使能,在简单读取传感器数据的时候,可以不用 FIFO,设置对应位为 0 即可禁止 FIFO,设置为 1,则使能 FIFO。注意加速度传感器的 3 个轴,全由 1个位(ACCEL_FIFO_EN)控制,只要该位置 1,则加速度传感器的三个通道都开启 FIFO了。

5:陀螺仪采样率分频寄存器(0x19)
STM32通过IIC读取MPU6050原始数据过程详解该寄存器地址为:0X19,用于设置 MPU6050 的陀螺仪采样频率,计算公式为:
采样频率 = 陀螺仪输出频率 / (1+SMPLRT_DIV)
这里陀螺仪的输出频率,是 1Khz 或者 8Khz,与数字低通滤波器(DLPF)的设置有关,当 DLPF_CFG=0/7 的时候,频率为 8Khz,其他情况是 1Khz。而且 DLPF 滤波频率一般设置为采样率的一半。采样率,我们假定设置为 50Hz,那么 SMPLRT_DIV=1000/50-1=19。

6:配置寄存器(0x1A)
STM32通过IIC读取MPU6050原始数据过程详解
该寄存器地址为:0X1A,这里,我们主要关心数字低通滤波器(DLPF)的设置位,即:DLPF_CFG[2:0],加速度计和陀螺仪,都是根据这三个位的配置进行过滤的。DLPF_CFG 不同配置对应的过滤情况如表 1. 1. 2 所示
STM32通过IIC读取MPU6050原始数据过程详解这里的加速度传感器,输出速率(Fs)固定是 1Khz,而角速度传感器的输出速率(Fs),则根据 DLPF_CFG 的配置有所不同。一般我们设置角速度传感器的带宽为其采样率的一半,如前面所说的,如果设置采样率为 50Hz,那么带宽就应该设置为 25Hz,取近似值 20Hz,就应该设置 DLPF_CFG=100。

7:电源管理寄存器(0x6C)
STM32通过IIC读取MPU6050原始数据过程详解该寄存器的 LP_WAKE_CTRL 用于控制低功耗时的唤醒频率,剩下的 6位,分别控制加速度和陀螺仪的 x/y/z 轴是否进入待机模式,这里我们全部都不进入待机模式,所以全部设置为 0 即可。

8:陀螺仪数据输出寄存器(0x43-0x48)
STM32通过IIC读取MPU6050原始数据过程详解总共有 8 个寄存器组成,地址为:0X43~0X48,通过读取这 8 个寄存器,就可以读到陀螺仪 x/y/z 轴的值,比如 x 轴的数据,可以通过读取0X43(高 8 位)和 0X44(低 8 位)寄存器得到,其他轴以此类推。

9:加速度传感器数据输出寄存器(:0x3B~0x40)
STM32通过IIC读取MPU6050原始数据过程详解同样,加速度传感器数据输出寄存器,也有 8 个,地址为:0X3B~0X40,通过读取这 8个寄存器,就可以读到加速度传感器 x/y/z 轴的值,比如读 x 轴的数据,可以通过读取 0X3B(高 8 位)和 0X3C(低 8 位)寄存器得到,其他轴以此类推。

10:温度数据寄存器(0x41-0x42)
STM32通过IIC读取MPU6050原始数据过程详解Temperature = 36.53 + regval/340其中,Temperature 为计算得到的温度值,单位为℃,regval 为从 0X41 和 0X42 读到的温度传感器值。

11:相关寄存器的宏定义
在STM32中,相关寄存器的宏定义在mpu6050.h头文件中声明:

STM32通过IIC读取MPU6050原始数据过程详解STM32通过IIC读取MPU6050原始数据过程详解
STM32通过IIC读取MPU6050原始数据过程详解

三:相关程序解释

1:初始化程序,全是通过配置相关寄存器的相应位来设置mpu6050的各种模式和参数,可以参考寄存器的相关解释来看相应的初始化程序。IIC协议不懂的可以看博主前面的教程。

//初始化MPU6050
//返回值:0,成功
//    其他,错误代码
u8 MPU_Init(void)
{ 
	u8 res;
	IIC_Init();//初始化IIC总线
	MPU_Write_Byte(MPU_PWR_MGMT1_REG,0X80);	//通过设置电源管理寄存器的相应位复位MPU6050
    delay_ms(100);
	MPU_Write_Byte(MPU_PWR_MGMT1_REG,0X00);	//设置电源管理寄存器的相应位全部为0,唤醒MPU6050
	MPU_Set_Gyro_Fsr(3);	 //陀螺仪传感器,正负2000dps
	MPU_Set_Accel_Fsr(0);					//加速度传感器,正负2g
	MPU_Set_Rate(50);						//采样率50Hz
	MPU_Write_Byte(MPU_INT_EN_REG,0X00);	//关闭所有中断
	MPU_Write_Byte(MPU_USER_CTRL_REG,0X00);	//I2主模式关闭
	MPU_Write_Byte(MPU_FIFO_EN_REG,0X00);	//关闭FIFO
	MPU_Write_Byte(MPU_INTBP_CFG_REG,0X80);	//INT引脚低电平有效
	res=MPU_Read_Byte(MPU_DEVICE_ID_REG);
	if(res==MPU_ADDR)//器件ID正确
	{
		MPU_Write_Byte(MPU_PWR_MGMT1_REG,0X01);	//设置CLKSET,PLL,x轴为参考
		MPU_Write_Byte(MPU_PWR_MGMT2_REG,0X00);	//加速度与陀螺仪都工作
		MPU_Set_Rate(50);						//采样频率设置50Hz
 	}else return 1;
	return 0;
}
//设置MPU6050陀螺仪传感器的满量程范围
//fsr:0,±250dps;1,±500dps;2,±1000dps;3,±2000dps
//返回值:0设置成功
//    其它,设置失败
u8 MPU_Set_Gyro_Fsr(u8 fsr)
{
	return MPU_Write_Byte(MPU_GYRO_CFG_REG,fsr<<3);//通过配置相关寄存器,设置陀螺仪的满量程范围
}

//设置mpu6050加速度传感器满量程范围
//fsr:0,±2g;1,±4g;2,±8g;3,±16g
//返回值:0,设置成功
//    其它,设置失败
u8 MPU_Set_Accel_Fsr(u8 fsr)
{
	return MPU_Write_Byte(MPU_ACCEL_CFG_REG,fsr<<3);
}
//设置mpu6050的数字低通滤波器
//lpf:数字低通滤波器频率(Hz)
//返回值:0,设置成功
//    其它,设置失败
u8 MPU_Set_LPF(u16 lpf)
{
	u8 data=0;
	if(lpf>=188)data=1;
	else if(lpf>=98)data=2;
	else if(lpf>=42)data=3;
	else if(lpf>=20)data=4;
	else if(lpf>=10)data=5;
	else data=6; 
	return MPU_Write_Byte(MPU_CFG_REG,data);
}
//设置mpu6050的采样率(假定Fs=1KHz)
//rate:4~1000(Hz)
//返回值:0,设置成功
//    其它,设置失败
u8 MPU_Set_Rate(u16 rate)
{
	u8 data;
	if(rate>1000)rate=1000;
	if(rate<4)rate=4;
	data=1000/rate-1;
	data=MPU_Write_Byte(MPU_SAMPLE_RATE_REG,data);	//设置数字低通滤波器
 	return MPU_Set_LPF(rate/2);	//自动设置LPF为采样率的一半
}

2:通过IIC读写,通过IIC协议读取相应数据寄存器内的数据

//得到温度值
//返回值:温度值(扩大了100倍)
short MPU_Get_Temperature(void)
{
    u8 buf[2]; 
    short raw;
	float temp;
	MPU_Read_Len(MPU_ADDR,MPU_TEMP_OUTH_REG,2,buf); 
    raw=((u16)buf[0]<<8)|buf[1];  
    temp=36.53+((double)raw)/340;  
    return temp*100;;
}

//得到陀螺仪值(原始值)
//gx,gy,gz:陀螺仪x,y,z轴的原始读数(带符号)
//返回值: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;;
}
//得到加速度值(原始值)
//ax,ay,az:加速度x,y,z轴的原始读数(带符号)
//返回值:0,成功
//    其它:错误代码
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;;
}

//IIC连续写
//addr:器件地址
//reg:寄存器地址
//len:写入长度
//buf:数据区
//返回值:0,成功
//    其它:错误代码
u8 MPU_Write_Len(u8 addr,u8 reg,u8 len,u8 *buf)
{
	u8 i; 
    IIC_Start(); 
	IIC_Send_Byte((addr<<1)|0);//发送器件地址+写命令,注意器件地址不包括最低位,所以左移1位,最低位为0时代表写。
	if(IIC_Wait_Ack())	//等待应答
	{
		IIC_Stop();		 
		return 1;		
	}
    IIC_Send_Byte(reg);	//写寄存器地址
    IIC_Wait_Ack();		//等待应答
	for(i=0;i<len;i++) //连续写
	{
		IIC_Send_Byte(buf[i]);	//发送数据
		if(IIC_Wait_Ack())		//等待ACK
		{
			IIC_Stop();	 
			return 1;		 
		}		
	}    
    IIC_Stop();	 
	return 0;	
} 

//IIC连续读
//addr:器件地址
//reg:要读取的寄存器地址
//len:要读取的长度
//buf:读取到的数据存储区
//返回值:0,成功
//    其它:错误代码
u8 MPU_Read_Len(u8 addr,u8 reg,u8 len,u8 *buf)
{ 
 	IIC_Start(); 
	IIC_Send_Byte((addr<<1)|0);//发送器件地址+写命令,注意器件地址不包括最低位,所以右移1位,最低位为0时代表写。
	if(IIC_Wait_Ack())	//等待应答
	{
		IIC_Stop();		 
		return 1;		
	}
    IIC_Send_Byte(reg);	//写寄存器地址
    IIC_Wait_Ack();		//等待应答
    IIC_Start();
	IIC_Send_Byte((addr<<1)|1);//发送器件地址+读命令,注意器件地址不包括最低位,所以左移1位,最低位为1时代表写。
    IIC_Wait_Ack();		//等待应答
	while(len)
	{
		if(len==1)*buf=IIC_Read_Byte(0);//读数据,到最后一位时发送nACK
		else *buf=IIC_Read_Byte(1);		//读数据,发送nACK
		len--;
		buf++; 
	}    
    IIC_Stop();	//产生一个停止条件
	return 0;	
}

//IIC写一个字节
//reg:寄存器地址
//data:数据
//返回值:0,成功
//    其它:错误代码
u8 MPU_Write_Byte(u8 reg,u8 data) 				 
{ 
  IIC_Start(); 
	IIC_Send_Byte((MPU_ADDR<<1)|0);//发送器件地址+写命令,注意器件地址不包括最低位,所以左移1位,最低位为0时代表写。
	if(IIC_Wait_Ack())	
	{
		IIC_Stop();		 
		return 1;		
	}
    IIC_Send_Byte(reg);	//写器件地址
    IIC_Wait_Ack();		
	IIC_Send_Byte(data);//发送数据
	if(IIC_Wait_Ack())	
	{
		IIC_Stop();	 
		return 1;		 
	}		 
    IIC_Stop();	 
	return 0;
}

//IIC读一个字节
//reg:寄存器地址
//返回值:读到的数据
u8 MPU_Read_Byte(u8 reg)
{
	u8 res;
    IIC_Start(); 
	IIC_Send_Byte((MPU_ADDR<<1)|0);//发送器件地址+写命令,注意器件地址不包括最低位,所以左移1位,最低位为0时代表写。
	IIC_Wait_Ack();		
    IIC_Send_Byte(reg);	
    IIC_Wait_Ack();		
    IIC_Start();
	IIC_Send_Byte((MPU_ADDR<<1)|1);//发送器件地址+读命令
    IIC_Wait_Ack();		
	res=IIC_Read_Byte(0); //读取数据发送nACK
    IIC_Stop();			//产生一个停止条件
	return res;		
}

至此就可以在主程序中读到mpu6050加速度计和陀螺仪的原始数据了

temp=MPU_Get_Temperature();	//获取温度值
MPU_Get_Accelerometer(&aacx,&aacy,&aacz);//获取三轴加速度值
MPU_Get_Gyroscope(&gyrox,&gyroy,&gyroz); //获得三轴角速度值

当然读到的原始数据还不能直接使用,要转化成四元数,欧拉角后,获得器件的姿态角才有用,而 MPU6050 自带了数字运动处理器,即 DMP,并且,InvenSense 提供了一个 MPU6050 的嵌入式运动驱动库,结合 MPU6050 的 DMP,可以将我们的原始数据,直接转换成四元数输出,而得到四元数之后,就可以很方便的计算出欧拉角,从而得到 yaw、roll 和 pitch。这部分会在后面的博客进行介绍。

参考:
《MPU-6000 & MPU-6050 寄存器表及其描述(中文版)》
《ATK-MPU6050六轴传感器模块使用说明(Mini V3)_AN1507》
《ATK-MPU6050六轴传感器模块用户手册_V1.0》
正点原子相关教程

本文地址:https://blog.csdn.net/w1050321758/article/details/108996091

相关标签: STM32 MPU