MPU6050

一、运动传感器与姿态测量

1、欧拉角

欧拉角:以运动物体建立坐标系,通过绕轴旋转来表示运动物体当前的姿态

(Yaw -偏航角 Roll-翻滚角)

(Pitch -俯仰角)

2、加速度计测量姿态

加速度计,也被称为重力传感器G-Sensor,是一种测量物体加速度的传感器

加速度计通过测量物体在三个轴向上的加速度来推算物体的姿态。在静止或匀速直线运动状态下,加速度计可以准确地测量出重力加速度在三个轴向上的分量,从而推算出物体的俯仰角(Pitch)和横滚角(Roll)。然而,由于加速度计无法直接测量绕垂直轴的旋转(即偏航角Yaw),因此无法单独测量出完整的欧拉角。

优点:能直接算出欧拉角

缺点:外部震动会引入噪声

3、陀螺仪测量姿态

陀螺仪是一种测量角速度的传感器,它可以感知物体绕三个轴的旋转角速度。通过积分陀螺仪输出的角速度信号,可以得到物体的旋转角度,从而推算出欧拉角。然而,陀螺仪的积分过程会导致误差的累积,特别是在长时间运行或受到较大干扰时,误差会显著增加。

优点:准确、无干扰

缺点:误差会累积

4、传感器融合

加速度计和陀螺仪在测量欧拉角时的优缺点:

为了克服加速度计和陀螺仪各自的缺点,提高姿态测量的准确性和稳定性,通常会将两者的数据进行融合。数据融合的方法有多种,包括互补滤波、卡尔曼滤波等。这里利用的是互补滤波的方法,它利用加速度计在静止或匀速直线运动状态下测量准确的优点,以及陀螺仪在动态过程中测量角速度的优点,通过加权平均或叉乘运算将两者的数据进行融合。这种方法可以减小陀螺仪积分过程中的误差累积,同时提高加速度计在动态过程中的响应速度。

二、MPU6050介绍

说明:

DMP(Digital Motion Processor,数字运动处理器)是一种专门用于处理和分析运动数据的集成电路或处理器。DMP通常与传感器(如加速度计、陀螺仪和磁力计)结合使用,以提供精确、实时的姿态和运动信息。

工作原理:DMP通过内置的算法和滤波器对传感器数据进行处理,从而提取出有用的运动信息。这些算法可以包括姿态估计、运动分类、步态分析等。DMP能够高效地处理传感器数据,减少噪声和误差的影响,提供准确的运动参数。

三、MPU6050通信及配置

1、通信方式

IIC通信,可支持快速IIC

2、器件地址

有一个引脚可以产生逻辑电平0 1

如果地址引脚接地 七位器件地址0x68

如果地址引脚接高 七位器件地址0x69

我们板子默认 接地 七位器件地址0x68

注意,要加读写控制位

写: (0x68 << 1) //0xd0

读: (0x68 << 1) | 0x01 //0xd1

3、MUP6050通信时序

1.主控芯片发送一个字节到MPU6050

设置一个寄存器的时序

2.主控芯片发送多个字节到MPU6050

设置地址连续的多个寄存器

3.主控芯片从MPU6050中读一个字节回来

读某一个寄存器里面的值

4.主控芯片从MPU6050中连续读多个字节回来

读地址连续的多个寄存器的值,比如读xyz方向的值

四、MPU6050相关寄存器

MPU6050初始化就是把上面的寄存器配置

五、MPU6050获取陀螺仪和加速度数据

初始化后,发送数据寄存器地址,就可以读到数据寄存器的内容,将两个8位数据合成16位数据

带入到公式中就可以得到具体角度值和加速度值

说明:

数据寄存器因为地址连续,所以可以连续读出

六、MPU6050程序设计

①IIC通信相关程序

复制代码
/***********************************************
*函数名    :iic_IO_init
*函数功能  :IIC所用IO口初始化配置
*函数参数  :无
*函数返回值:无
*函数描述  :SCL----PB8
            SDA----PB9
************************************************/
void iic_IO_init(void)
{
	//端口时钟使能
	RCC->AHB1ENR |= (1<<1);
	//端口模式配置
	GPIOB->MODER &= ~((3<<16)|(3<<18));
	GPIOB->MODER |= ((1<<16)|(1<<18));
	//输出类型
	GPIOB->OTYPER &= ~(1<<8);         //时钟线配置位推挽输出
	GPIOB->OTYPER |= (1<<9);          //数据线配置为开漏输出
	//输出速度
	GPIOB->OSPEEDR &= ~((3<<16)|(3<<18));
	//上下拉
	GPIOB->PUPDR &= ~((3<<16)|(3<<18));
	//输出数据寄存器让时钟线和数据线处于空闲转态
	GPIOB->ODR |= ((1<<8) | (1<<9));
}


/***********************************************
*函数名    :iic_star
*函数功能  :IIC起始信号函数
*函数参数  :无
*函数返回值:无
*函数描述  :         
************************************************/
void iic_star(void)
{
	//时钟线拉低    可以动数据线
	IIC_SCL_L;
	//数据线拉高    保证可以出现下降沿
	IIC_SDA_OUT_H;
	
	
	//时钟线拉高    起始信号的条件
	IIC_SCL_H;
	TIM11_delay_us(5);
	//数据线拉低    产生了起始信号
	IIC_SDA_OUT_L;
	TIM11_delay_us(5);
	
	IIC_SCL_L;//安全作用
}



/***********************************************
*函数名    :iic_stop
*函数功能  :IIC停止信号函数
*函数参数  :无
*函数返回值:无
*函数描述  :         
************************************************/
void iic_stop(void)
{
	IIC_SCL_L;
	IIC_SDA_OUT_L;
	
	IIC_SCL_H;
	TIM11_delay_us(5);
	IIC_SDA_OUT_H;
	TIM11_delay_us(5);
	
}




/***********************************************
*函数名    :iic_send_ack
*函数功能  :IIC发送应答/不应答信号函数
*函数参数  :u8 ack   
*函数返回值:无
*函数描述  :ack  传入 0   表示发送应答
            ack  传入 1   表示发送不应答
************************************************/
void iic_send_ack(u8 ack)
{
	IIC_SCL_L;
	TIM11_delay_us(3);
	
	if(ack == 0) IIC_SDA_OUT_L;
	else         IIC_SDA_OUT_H;  
	TIM11_delay_us(2);
	
	IIC_SCL_H;
	TIM11_delay_us(5); 
	
	IIC_SCL_L;//安全作用
}



/***********************************************
*函数名    :iic_get_ack
*函数功能  :IIC检测应答/不应答信号函数
*函数参数  :无   
*函数返回值:u8
*函数描述  :0    应答信号
            1    不应答信号
************************************************/
u8 iic_get_ack(void)
{
	u8 ack;
	
	/*将数据线切换位输入模式*/
	IIC_SCL_L;
	IIC_SDA_OUT_H;  
	
	/*检测应答*/
	IIC_SCL_L;      //主机帮助从机把时钟线拉低,从机才可以自动改变数据线
	TIM11_delay_us(5);
	IIC_SCL_H;      //主机拉高时钟线才可以读数据线
	TIM11_delay_us(5);
	if(IIC_SDA_IN)   ack = 1;    //不应答信号
	else             ack = 0;    //应答信号
	
	
	IIC_SCL_L;    //安全作用
	return ack;
}




/***********************************************
*函数名    :iic_send_byte
*函数功能  :IIC发送一个字节函数
*函数参数  :u8 data  
*函数返回值:无
*函数描述  :
************************************************/
void iic_send_byte(u8 data)
{
	u8 i;
	
	for(i=0;i<8;i++)
	{
		IIC_SCL_L;
		TIM11_delay_us(3);
		
		if(data & 0x80)
		{
			IIC_SDA_OUT_H;  
		}
		else 
		{
			IIC_SDA_OUT_L;
		}
		TIM11_delay_us(2);
		
		IIC_SCL_H;       //帮助从机拉高时钟线,从机才可以读这一位数据
		TIM11_delay_us(5);
		
		//下一位数据
		data = data << 1;
		
	}
	
	IIC_SCL_L;      //安全作用
	
}




/***********************************************
*函数名    :iic_rec_byte
*函数功能  :IIC接收一个字节函数
*函数参数  :无  
*函数返回值:u8
*函数描述  :
************************************************/
u8 iic_rec_byte(void)
{
	u8 i;
	u8 data;
	
	/*IO切换为输入模式*/
	IIC_SCL_L;
	IIC_SDA_OUT_H;  
	
	/*接收一个字节数据*/
	for(i=0;i<8;i++)
	{
		IIC_SCL_L;          //帮助从机拉低时钟线,从才会改变数据线
		TIM11_delay_us(5);
		
		IIC_SCL_H;          //主机可以读数据线
		TIM11_delay_us(5);
	
		data = data << 1;
		if(IIC_SDA_IN)
		{
			data |= 0x01;
		}
	}
	
	IIC_SCL_L;     //安全作用
	
	
	return data;
}

②MPU6050相关程序

主控芯片发送多个字节到MPU6050函数

复制代码
/***********************************************
*函数名    :mpu6050_Write
*函数功能  :写多个字节数据到MPU6050
*函数参数  :u8 reg, u8 len, u8* data
*函数返回值:无
*函数描述  :
***********************************************/
void mpu6050_Write(u8 reg,u8 len,u8* data)
{
    u8 i;
    iic_star();
	
    iic_send_byte(0x68<<1);     //器件地址+写控制位
    iic_get_ack();
		
    iic_send_byte(reg);         //发送寄存器地址
    iic_get_ack();
	
		//连续发送数据
    for (i = 0; i < len; i++)
		{
        iic_send_byte(data[i]);
        iic_get_ack();
    }
    iic_stop();
    
}

主控芯片从MPU6050中连续读多个字节回来函数

复制代码
/***********************************************
*函数名    :mup6050_Read
*函数功能  :从MPU6050读多个字节数据
*函数参数  :u8 reg,u8 len, u8* buf
*函数返回值:无
*函数描述  :
***********************************************/
void mup6050_Read(u8 reg,u8 len, u8* buf)
{
    iic_star();
    iic_send_byte(0x68<<1);
    iic_get_ack();
	
    iic_send_byte(reg);       //寄存器的起始地址
    iic_get_ack();
	
	
    iic_star();
    iic_send_byte(0x68<<1 | 0x01);
    iic_get_ack();
	

		while(1)                               
		{
			*buf = iic_rec_byte();   
			len--;
			buf++;	
			if(len == 0)
			{
				iic_send_ack(1);
				break;
			}
			else
			{
				iic_send_ack(0);
			}
		}
	
    iic_stop();
   
}

MPU6050初始化配置函数

复制代码
/***********************************************
*函数名    :MPU6050_init
*函数功能  :MPU6050_init 初始化配置
*函数参数  :无
*函数返回值:无
*函数描述  :
***********************************************/
void MPU6050_init(void)
{
	u8 re_buff[] = {0x89,0x09,0x18,0x00,0x04,0x13};   //采样频率计算值19 十六进制0x13
	
	/*IIC初始化*/
	iic_IO_init();
	
	/*MPU6050*/
	mpu6050_Write(PWR_MGMT_1,1,&re_buff[0]);     //复位MPU6050
	tim11_delay_ms(100);                           //不放延时会出问题 
	mpu6050_Write(PWR_MGMT_1, 1,&re_buff[1]);     //解除休眠状态
	mpu6050_Write(GYRO_CONFIG, 1,&re_buff[2]);    //陀螺仪范围 2000    16.4
	mpu6050_Write(ACCEL_CONFIG, 1,&re_buff[3]);   //2g                 16384
	mpu6050_Write(CONFIG, 1,&re_buff[4]);         //20带宽  1KHZ
	mpu6050_Write(SMPLRT_DIV, 1,&re_buff[5]);     //采样频率19

}

获取XYZ方向数据函数

复制代码
/***********************************************
*函数名    :DataSynthesis
*函数功能  :获取某个方向的高低8位数据并且合成16位数据
*函数参数  :寄存器地址
*函数返回值:short
*函数描述  :
***********************************************/
short DataSynthesis(u8 REG_Address)	
{
	u8  uByte[2]; 

	mup6050_Read(REG_Address,2,uByte)  ;

	return ((uByte[0] << 8) | uByte[1]);   /*返回合成数据*/
}



/***********************************************
*函数名    :ReadAcceData
*函数功能  :读加速度和陀螺仪三个方向的数据
*函数参数  :无
*函数返回值:ACCG_t
*函数描述  :
***********************************************/
ACCG_t ReadAcceData(void)
{
	  ACCG_t ag;
		//读加速度
		ag.x_Axis = DataSynthesis(ACCEL_XOUT_H) / 16384.0 ; 
		ag.y_Axis = DataSynthesis(ACCEL_YOUT_H) / 16384.0; 
		ag.z_Axis = DataSynthesis(ACCEL_ZOUT_H) / 16384.0 ; 
		//陀螺仪
		ag.x_Gxis = DataSynthesis(GYRO_XOUT_H)  / 16.4; 
		ag.y_Gxis = DataSynthesis(GYRO_YOUT_H)  / 16.4; 
		ag.z_Gxis = DataSynthesis(GYRO_ZOUT_H)  / 16.4;
	
	
		return ag;
}
相关推荐
可编程芯片开发7 小时前
基于MATLAB的PEF湍流风场生成器模拟与仿真
算法
罗西的思考7 小时前
【Agentic RL / 强化学习 / OPD】OpenClaw-RL 源码阅读笔记 --- (9)--- Reward Judging
人工智能·算法·机器学习
Mr.HeBoYan9 小时前
一次持续三天才出现的丢包故障——深入解析 DPDK Memory Ordering、rte_ring 与 CPU Memory Barrier (下)
linux·网络·算法·架构·dpdk
wabs6669 小时前
关于图论【深度优先搜索的理论基础】
算法·深度优先·图论
巴巴媛66610 小时前
STM32学习笔记【38.DHT11实验】
笔记·stm32·学习
先吃饱再说10 小时前
LeetCode 101. 对称二叉树
算法
深圳市泰凌微电子10 小时前
HK航顺 HK32F407RGT7替STM32F405RGT6 微控制器32位MCU
stm32·单片机·嵌入式硬件
是Dream呀10 小时前
人眼看不出的伪造,AI如何识别?实测合合信息跨模态鉴伪与去反光技术
算法
QN1幻化引擎11 小时前
SFA 信号场注意力:用8KB参数换248x KV Cache压缩,边缘设备也能跑长序列
人工智能·算法·gitee·gitlab
段一凡-华北理工大学11 小时前
向量数据库实战:选型、调优与落地~系列文章03:向量相似度算法全解:余弦、欧氏、内积,到底该用哪个?
大数据·数据库·人工智能·算法·机器学习·向量相似度·高炉炼铁