STM32F4移植MPU6050输出欧拉角

本文详细介绍了MPU6050传感器的初始化步骤及数据读取方法,包括寄存器配置、陀螺仪和加速度传感器设置,并提供了完整的代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

MPU6050初始化的步骤:

1、 复位MPU6050,让MPU6050内部的所有寄存器恢复默认值(向0X6B写入0x80)

2、设置电源管理寄存器位0x00,以唤醒MPU6050,进入正常工作状态(向0x6B写入0x00)


   3、 陀螺仪配置寄存器(0x1B)设置MPU6050陀螺仪传感器满量程范围,这里选择正负2000dps


   

4、加速度传感器配置寄存器(0x1C)这里选择正负2g


   

 

5、陀螺仪采样率,由采样率分频寄存器(0x19)控制;这里设置为50hz即输出频率=1KHz,SMPLRT_DIV=19


   

6、设置MPU6050的数字低通滤波器,因为配置为50hz,找一个接近值,所以配置为0x03,42hz

 

 

7、设置PLL,一般选择x轴陀螺PLL作为时钟源,以获得更高精度的时钟。(向0X6B写入0x01)

8、设置加速度与陀螺仪都工作(向0X6C写入0x00)

这里还有一个寄存器可以用来检测是否有mpu6050(当AD0接地时,向0x75读取数据则返回0x68;当AD0接VCC时,向0x75读取数据则返回0x69)

 以上是初始化的部分,初始化完成之后开始读取数据:

读取温度的地址:

读取陀螺仪测量值(原始值)分别有X/Y/Z轴的数据

 读取加速度计测量值(原始值)分别有X/Y/Z轴的数据

 

 上代码:

mpu6050.c

#include "mpu6050.h"

//IIC连续写
//addr:器件地址 
//reg:寄存器地址
//len:写入长度
//buf:数据区
//返回值:0,正常
//    其他,错误代码
u8 MPU_Write_Len(u8 addr,u8 reg,u8 len,u8 *buf)
{
	u8 i; 
    IIC_Start(); 
	IIC_Write((addr<<1)|0);//发送器件地址+写命令	
	if(IIC_Whit_Ack())	//等待应答
	{
		IIC_Stop();		 
		return 1;		
	}
    IIC_Write(reg);	//写寄存器地址
    IIC_Whit_Ack();		//等待应答
	for(i=0;i<len;i++)
	{
		IIC_Write(buf[i]);	//发送数据
		if(IIC_Whit_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_Write((addr<<1)|0);//发送器件地址+写命令	
	if(IIC_Whit_Ack())	//等待应答
	{
		IIC_Stop();		 
		return 1;		
	}
    IIC_Write(reg);	//写寄存器地址
    IIC_Whit_Ack();		//等待应答
    IIC_Start();
	IIC_Write((addr<<1)|1);//发送器件地址+读命令	
    IIC_Whit_Ack();		//等待应答 
	while(len)
	{
		if(len==1)
		{
			*buf=IIC_Read();//读数据,发送nACK 0
			IIC_Send_Ack(1);
		}
		else {
			*buf=IIC_Read();	//1
			IIC_Send_Ack(0);			
			//读数据,发送ACK 
		}			
		len--;
		buf++; 
	}    
    IIC_Stop();	//产生一个停止条件 
	return 0;	
}

//写
char MPU6050_WriteReg(u8 reg_add,u8 reg_dat)
{
	IIC_Start();
	IIC_Write((0x68<<1)|0);
	if( IIC_Whit_Ack() == 1 ) return 1;
	IIC_Write(reg_add);
	if( IIC_Whit_Ack() == 1 ) return 2;
	IIC_Write(reg_dat);
	if( IIC_Whit_Ack() == 1 ) return 3;
	IIC_Stop();
}
//读
char MPU6050_ReadData(u8 reg_add,unsigned char*Read,u8 num)
{
	unsigned char i;
	
	IIC_Start();
	IIC_Write((0x68<<1)|0);
	if( IIC_Whit_Ack() == 1 ) return 1;
	IIC_Write(reg_add);
	if( IIC_Whit_Ack() == 1 ) return 2;
	
	IIC_Start();
	IIC_Write((0x68<<1)|1);
	if( IIC_Whit_Ack() == 1 ) return 3;
	
	for(i=0;i<(num-1);i++){
		*Read=IIC_Read();
		Read++;
		IIC_Send_Ack(0);
	}
	*Read=IIC_Read();
	IIC_Send_Ack(0);
	IIC_Stop();
	return 0;
}
/**********************************************
函数名称:MPU_Set_Gyro_Fsr
函数功能:设置MPU6050陀螺仪传感器满量程范围
函数参数:fsr:0,±250dps;1,±500dps;2,±1000dps;3,±2000dps
函数返回值:0,设置成功  其他,设置失败
**********************************************/
u8 MPU_Set_Gyro_Fsr(u8 fsr)
{
	return MPU6050_WriteReg(MPU_GYRO_CFG_REG,fsr<<3); //设置陀螺仪满量程范围
}              

/**********************************************
函数名称:MPU_Set_Accel_Fsr
函数功能:设置MPU6050加速度传感器满量程范围
函数参数:fsr:0,±2g;1,±4g;2,±8g;3,±16g
函数返回值:0,设置成功  其他,设置失败
**********************************************/
u8 MPU_Set_Accel_Fsr(u8 fsr)
{
	return MPU6050_WriteReg(MPU_ACCEL_CFG_REG,fsr<<3); //设置加速度传感器满量程范围  
}

/**********************************************
函数名称:MPU_Set_LPF
函数功能:设置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 MPU6050_WriteReg(MPU_CFG_REG,data);//设置数字低通滤波器  
}
   
/**********************************************
函数名称:MPU_Set_Rate
函数功能:设置MPU6050的采样率(假定Fs=1KHz)
函数参数:rate:4~1000(Hz)  初始化中rate取50
函数返回值:0,设置成功  其他,设置失败
**********************************************/
u8 MPU_Set_Rate(u16 rate)
{
	u8 data;
	if(rate>1000)rate=1000;
	if(rate<4)rate=4;
	data=1000/rate-1;
	data=MPU6050_WriteReg(MPU_SAMPLE_RATE_REG,data);	//设置数字低通滤波器 19
 	return MPU_Set_LPF(rate/2);											//自动设置LPF为采样率的一半
}

/************************************************************
 * 函数名称:MPU6050_Init
 * 函数说明:MPU6050的初始化
 * 型    参:无
 * 返 回 值:0=失败没有检测到MPU6050  =1配置成功
 * 备    注:无
*************************************************************/
char MPU6050_Init(void)
{
	delay_ms(10);
	//复位6050
	MPU6050_WriteReg(MPU6050_RA_PWR_MGMT_1, 0x80);
	delay_ms(100);
	//电源管理寄存器
	//选择X轴陀螺作为参考PLL的时钟源,设置CLKSEL=001
	MPU6050_WriteReg(MPU6050_RA_PWR_MGMT_1, 0x00);
	
	MPU_Set_Gyro_Fsr(3);										//陀螺仪传感器,±2000dps
	MPU_Set_Accel_Fsr(0);										//加速度传感器,±2g
	MPU_Set_Rate(50);	

	MPU6050_WriteReg(MPU_INT_EN_REG ,  0x00);	//关闭所有中断
	MPU6050_WriteReg(MPU_USER_CTRL_REG,0x00);	//I2C主模式关闭
	MPU6050_WriteReg(MPU_FIFO_EN_REG,  0x00);		//关闭FIFO
	MPU6050_WriteReg(MPU_INTBP_CFG_REG,0X80);	//INT引脚低电平有效
          
	if( MPU6050ReadID() == 0 )//检查是否有6050
	{       
		MPU6050_WriteReg(MPU6050_RA_PWR_MGMT_1, 0x01	);//设置CLKSEL,PLL X轴为参考
		MPU6050_WriteReg(MPU_PWR_MGMT2_REG, 0x00	);//加速度与陀螺仪都工作
		MPU_Set_Rate(50);	
		printf("MPU6050初始化成功\r\n");
		return 1;
	}
	return 0;
}

//得到温度值
//返回值:温度值(扩大了100倍)
short MPU_Get_Temperature(void)
{
    u8 buf[2]; 
    short raw;
	float temp;
	MPU_Read_Len(0x68,MPU_TEMP_OUTH_REG,2,buf); 
    raw=((u16)buf[0]<<8)|buf[1];  
	//温度换算公式为:Temperature = 36.53 + regval/340
	//单位为℃
    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;  
		//MPU_GYRO_XOUTH_REG = MPU6050陀螺仪数据寄存器地址
	//陀螺仪数据输出寄存器总共由6个寄存器组成,
	//输出X/Y/Z三个轴的陀螺仪传感器数据,高字节在前,低字节在后。
	//每一个轴16位,按顺序为xyz
	res=MPU_Read_Len(0x68,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;;
}
//得到加速度值(原始值)
//gx,gy,gz:陀螺仪x,y,z轴的原始读数(带符号)
//返回值:0,成功
//    其他,错误代码
u8 MPU_Get_Accelerometer(short *ax,short *ay,short *az)
{
    u8 buf[6],res;  
	res=MPU_Read_Len(0x68,MPU_ACCEL_XOUTH_REG,6,buf);
	
		//MPU_ACCEL_XOUTH_REG = MPU6050加速度数据寄存器地址
	//加速度传感器数据输出寄存器总共由6个寄存器组成,
	//输出X/Y/Z三个轴的加速度传感器值,高字节在前,低字节在后。
	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;;
}

/************************************************************
 * 函数名称:MPU6050ReadID
 * 函数说明:读取MPU6050的器件地址
 * 型    参:无
 * 返 回 值:0=检测不到MPU6050   1=能检测到MPU6050
 * 备    注:
*************************************************************/
uint8_t MPU6050ReadID(void)
{
	unsigned char Re[2] = {0};
	//器件ID寄存器 = 0x75
	printf("mpu=%d\r\n",MPU6050_ReadData(0X75,Re,1)); //读器件地址
	
	if (Re[0] != 0x68) 
	{
		printf("检测不到 MPU6050 模块");
		return 1;
 	} 
	else
	{
		printf("MPU6050 ID = %x\r\n",Re[0]);
		return 0;
	}
	return 0;
}

 mpu6050.h

#ifndef _MPU6050_H_
#define _MPU6050_H_

#include "stm32f4xx.h"
#include "delay.h"
#include "usart.h"
#include "iic.h"


//MPU6050的AD0是IIC地址引脚,接地则IIC地址为0x68,接VCC则IIC地址为0x69



#define MPU_INT_EN_REG							0X38	//中断使能寄存器
#define MPU_USER_CTRL_REG						0X6A	//用户控制寄存器
#define MPU_FIFO_EN_REG							0X23	//FIFO使能寄存器
#define MPU6050_RA_PWR_MGMT_1                   0x6B 	//电源管理寄存器
#define MPU_PWR_MGMT2_REG						0X6C	//电源管理寄存器2
#define MPU_GYRO_CFG_REG						0X1B	//陀螺仪配置寄存器
#define MPU_ACCEL_CFG_REG						0X1C	//加速度计配置寄存器
#define MPU_CFG_REG								0X1A	//配置寄存器
#define MPU_SAMPLE_RATE_REG					    0X19	//采样频率分频器
#define MPU_INTBP_CFG_REG						0X37	//中断/旁路设置寄存器
	
#define MPU6050_RA_TEMP_OUT_H 	0x41	//温度高位
#define MPU6050_RA_TEMP_OUT_L 	0x42	//温度低位

#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位寄存器





char MPU6050_Init(void);
uint8_t MPU6050ReadID(void);
//
u8 MPU_Write_Len(u8 addr,u8 reg,u8 len,u8 *buf);
u8 MPU_Read_Len(u8 addr,u8 reg,u8 len,u8 *buf);

short MPU_Get_Temperature(void);
u8 MPU_Get_Gyroscope(short *gx,short *gy,short *gz);
u8 MPU_Get_Accelerometer(short *ax,short *ay,short *az);

#endif

 IIC.c

#include "iic.h"

//PB6-SCL  PB7-SDA
void IIC_GPIO_Init(void)
{
	GPIO_InitTypeDef GPIOINIT={0};
	
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB,ENABLE);
	
	GPIOINIT.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7;
	GPIOINIT.GPIO_OType = GPIO_OType_OD;
	GPIOINIT.GPIO_PuPd = GPIO_PuPd_UP;
	GPIOINIT.GPIO_Speed = GPIO_Speed_100MHz;
	GPIOINIT.GPIO_Mode = GPIO_Mode_OUT;
	GPIO_Init(GPIOB,&GPIOINIT);
}

//IIC起始信号
void IIC_Start(void)
{
	SDA_OUT();
	
	SDA(1);
	delay_us(5);
	SCL(1); 
	delay_us(5);
	
	SDA(0);
	delay_us(5);
	SCL(0);
	delay_us(5);
	               
}
//IIC停止信号
void IIC_Stop(void)
{
	SDA_OUT();
	SCL(0);
	SDA(0);
	
	SCL(1);
	delay_us(5);
	SDA(1);
	delay_us(5);
	
}

//主机发送应答
//0应答
//1非应答
char IIC_Send_Ack(unsigned char ack)
{
	SDA_OUT();
	SCL(0);
	SDA(0);
	delay_us(5);
	if(!ack) SDA(0);
	else		 SDA(1);
	SCL(1);
	delay_us(5);
	SCL(0);
	SDA(1);
	return 0;
}
//等待从机应答
unsigned char IIC_Whit_Ack(void)
{
	
	char ack = 0;
	unsigned char ack_flag = 10;
//	SCL(0);
//	SDA(1);
	SDA_IN();
	delay_us(5);
	SCL(1);
	delay_us(5);
	while( (GETSDA()==1) && ( ack_flag ) )
	{
		ack_flag--;
		delay_us(5);
	}
	
	if( ack_flag <= 0 )
	{
		IIC_Stop();
		return 1;
	}
	else
	{
		SCL(0);
		SDA_OUT();
	}
	return ack;
}
//写一个字节
void IIC_Write(unsigned char dat)
{
	int i = 0;
	SDA_OUT();
	SCL(0);//拉低时钟开始数据传输
	
	for( i = 0; i < 8; i++ )
	{
		SDA( (dat & 0x80) >> 7 );
		__nop();
		SCL(1);
		delay_us(5);
		SCL(0);
		delay_us(5);
		dat<<=1;
	}	
}

//读1个字节
unsigned char IIC_Read(void)
{
	unsigned char i,receive=0;
	SDA_IN();//SDA设置为输入
  for(i=0;i<8;i++ )
	{
    SCL(0);
    delay_us(5);
	  SCL(1);
	  delay_us(5);
    receive<<=1;
		if( GETSDA() )
		{	
			receive|=1;   
		}
	  delay_us(5); 
   }					 
	SCL(0); 
  return receive;
}




IIC.h

#ifndef _IIC_H_
#define _IIC_H_

#include "stm32f4xx.h"
#include "delay.h"
#include "usart.h"

#define SDA_IN()    {GPIOB->MODER &= ~(0X03<<14);} //设置SDA为输入模式
#define SDA_OUT() 	{GPIOB->MODER |=  (0X01<<14);} //设置SDA为输出模式


#define SCL(BIT)  GPIO_WriteBit( GPIOB, GPIO_Pin_6, BIT)
#define SDA(BIT)  GPIO_WriteBit( GPIOB, GPIO_Pin_7, BIT)

#define GETSDA()  GPIO_ReadInputDataBit( GPIOB, GPIO_Pin_7)

///////////////////		IIC		///////////////////
void 					IIC_GPIO_Init(void);
void 					IIC_Start(void);
void 					IIC_Stop(void);
char 					IIC_Send_Ack(unsigned char ack);
unsigned char           IIC_Whit_Ack(void);
void					IIC_Write(unsigned char dat);
unsigned char           IIC_Read(void);



#endif

到这里可以尝试一下能不能通信成功了,我先测试了一下读取温度,是可以读出来的。

main.c

#include "stm32f4xx.h"
#include "usart.h"
#include "delay.h"
#include "iic.h"
#include "mpu6050.h"
#include "inv_mpu.h"
       
/***************************************

编 译 版 本:MDK-keil5.37--CC5 
编 辑 时 间:2022-12-12
编 辑 人 员:老怪.

****************************************/

int main(void)
{
	float pitch,roll,yaw; 		//欧拉角
	short aacx,aacy,aacz;			//加速度传感器原始数据
	short gyrox,gyroy,gyroz;	//陀螺仪原始数据
	short temp;								//温度

	//中断分组 2组
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	
	//滴答定时器初始化
	delay_init(168);

	//串口1配置
	USART1_Init();	        
	
	//MPU6050的IIC引脚初始化
	IIC_GPIO_Init();
	//MPU6050的寄存器初始化
	MPU6050_Init();
	

	while(1)               
	{   	 
		printf("温度:%d\r\n",MPU_Get_Temperature()/100);
		delay_ms(200);
	}
}

如果想要输出角度等数据,可以使用正点原子提供的五个源码,MPU6050处理寄存器的相关数据时需要移植几个官方库,以便将数据处理为所需要的欧拉角。

 将他们导入工程(记得.h也要导入!)我这里新建了一个分组导入.c

 导入.h

 

如果使用的延时和导入的.c不一样子,可以在这里修改

完成之后直接修改一下主函数,再编译下载

main.c

#include "stm32f4xx.h"
#include "usart.h"
#include "delay.h"
#include "iic.h"
#include "mpu6050.h"
#include "inv_mpu.h"
       
/***************************************

编 译 版 本:MDK-keil5.37--CC5 
编 辑 时 间:2022-12-12
编 辑 人 员:老怪.

****************************************/

int main(void)
{
	float pitch,roll,yaw; 		//欧拉角
	short aacx,aacy,aacz;			//加速度传感器原始数据
	short gyrox,gyroy,gyroz;	//陀螺仪原始数据
	short temp;								//温度

	//中断分组 2组
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	
	//滴答定时器初始化
	delay_init(168);

	//串口1配置
	USART1_Init();	        
	
	//MPU6050的IIC引脚初始化
	IIC_GPIO_Init();
	//MPU6050的寄存器初始化
	MPU6050_Init();
	
	//MPU6050的DMP初始化 成功返回0
	while(mpu_dmp_init())
	{
		printf("DMP初始化失败\r\n");
		delay_ms(200);
	}
	printf("开始\r\n");

	while(1)               
	{   	 
		
		if(mpu_dmp_get_data(&pitch,&roll,&yaw)==0)  //从DMP获取数据
		{ 
			temp=MPU_Get_Temperature();	              //得到温度值    
			MPU_Get_Accelerometer(&aacx,&aacy,&aacz);	//得到加速度传感器数据
			MPU_Get_Gyroscope(&gyrox,&gyroy,&gyroz);	//得到陀螺仪数据
			
		    printf("\r\n\r\n俯仰 =%.2f\r\n翻滚 =%.2f\r\n偏航 =%.2f\r\n温度 =%d\r\n\r\n",pitch*10,roll*10,yaw*10,temp/100);

		}           

		delay_ms(200);
	}       
		
}

 最终得到效果:

 如果对其他的配置感兴趣就去正点原子吧

工程代码连接:

链接:https://pan.baidu.com/s/1Kfm0e-5cEKyiqh5pQRDtcw?pwd=1234
提取码:1234

 

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

老怪.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值