STM32学习-MPU6050

系列文章目录


文章目录

前言

一、MPU6050简介

二、MPU6050模块知识

1. 重要参数

2.硬件电路

3.逻辑框图

三、I2C读取MPU6050

1. 软件 I2C读取MPU6050

1.1 I2C配置函数MyI2C.c

1.2 MPU6050初始化函数MPU6050.c

1.3 主函数

总结


前言

本文记录学习MPU6050的相关笔记。(参考b站江协科技STM32教程)


一、MPU6050简介

  • MPU6050是一个6轴姿态传感器,可以测量芯片自身X、Y、Z轴的加速度、角速度参数,通过数据融合,可进一步得到姿态角,常应用于平衡车、飞行器等需要检测自身姿态的场景
  • 3轴加速度计(Accelerometer):测量X、Y、Z轴的加速度
  • 3轴陀螺仪传感器(Gyroscope):测量X、Y、Z轴的角速度

f5bfd5c8c7964316b34758f0453cb07d.png

  • Yaw(偏航):在MPU6050中是绕Z轴旋转
  • Pitch(俯仰):在MPU6050中是绕Y轴旋转
  • Roll(翻滚): 在MPU6050中是绕X轴旋转

df0fcb61c90a4fa384c2660e845a899e.png


二、MPU6050模块知识

1. 重要参数

  • 16位ADC采集传感器的模拟信号,量化范围:-32768~32767
  • 加速度计满量程选择:±2、±4、±8、±16(g)
  • 陀螺仪满量程选择: ±250、±500、±1000、±2000(°/sec)
  • 可配置的数字低通滤波器
  • 可配置的时钟源
  • 可配置的采样分频
  • I2C从机地址:1101000(AD0=0)  1101001(AD0=1);将读写位融合的地址就是0xD0或0xD1

2.硬件电路

  • XCL、XDA主要是为了扩展芯片功能,通常用于外接磁力计或者气压计,DMP(Digital Motion Processor)进行数据融合和姿态解算。

d725742e80ef4d98b1708f212bd8ecdd.png

3.逻辑框图

  • 灰色为各个传感器,通过ADC进行模数转换,转换完成后,传感器数据都放到Sensor Registers

8272045e219e4f5eb0338d6fa9aaf592.png


三、I2C读取MPU6050

1. 软件 I2C读取MPU6050

1.1 I2C配置函数MyI2C.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"


void MyI2C_W_SCL(uint8_t BitValue)
{
	//SCL写配置函数
	GPIO_WriteBit(GPIOB, GPIO_Pin_10, (BitAction)BitValue);
	Delay_us(10);
}


void MyI2C_W_SDA(uint8_t BitValue)
{
	//SDA写配置函数
	GPIO_WriteBit(GPIOB, GPIO_Pin_11, (BitAction)BitValue);
	Delay_us(10);
}


uint8_t MyI2C_R_SDA(void)
{
	//SCL读配置函数
	uint8_t BitValue;
	BitValue = GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_11);
	Delay_us(10);
	return BitValue;
}


void MyI2C_Init(void)
{
	//初始化I2C
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
	
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;		//设置为开漏输出
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &GPIO_InitStructure);
	
	
	GPIO_SetBits(GPIOB, GPIO_Pin_10 | GPIO_Pin_11);//将SCL和SDA设置为高电平,总线处于空闲状态
}


void MyI2C_Start(void)
{
	//起始条件,先拉低SDA再拉低SCL
	MyI2C_W_SDA(1);	
	MyI2C_W_SCL(1);
	MyI2C_W_SDA(0);
	MyI2C_W_SCL(0);
}

void MyI2C_Stop(void)
{
	//终止条件,先拉低SDA再释放SCL和SDA
	MyI2C_W_SDA(0);	
	MyI2C_W_SCL(1);
	MyI2C_W_SDA(1);
}

void MyI2C_SendByte(uint8_t Byte)
{
	//发送字节
	uint8_t i;
	for (i = 0; i < 8; i++)
	{
		//循环一次右移一位
		MyI2C_W_SDA(Byte & 0x80 >> i);	//按位与 取出Byte最高位 放在SDA线上
		MyI2C_W_SCL(1);		//主机释放SCL 高电平读取数据
		MyI2C_W_SCL(0);		//低电平进入下一个时序
	}
}

uint8_t MyI2C_ReceiveByte(void)
{
	//接收字节 
	uint8_t i, Byte = 0x00;		//Byte默认
	MyI2C_W_SDA(1);		//主机释放SDA 交出控制权
	for (i = 0; i < 8; i++)
	{
		MyI2C_W_SCL(1);		//主机释放SCL 高电平读取数据
		if (MyI2C_R_SDA() == 1){Byte |= (0x80 >> i);}	//如果读到1 那就将Byte最高位置为1
		MyI2C_W_SCL(0);		//低电平进入下一个时序
	}
	return Byte;
}

void MyI2C_SendAck(uint8_t AckBit)
{
	//发送应答
	MyI2C_W_SDA(AckBit);	//将AckBit放到SDA上
	MyI2C_W_SCL(1);		//SCL高电平读取应答位
	MyI2C_W_SCL(0);		//低电平进入下一个时序
}

uint8_t MyI2C_ReceiveAck(void)
{
	//接收应答
	uint8_t AckBit;
	MyI2C_W_SDA(1);		//主机释放SDA 交出控制权
	MyI2C_W_SCL(1);		//SCL高电平 
	AckBit = MyI2C_R_SDA();		//主机读取应答位
	MyI2C_W_SCL(0);		//低电平进入下一个时序
	return AckBit;
}

1.2 MPU6050初始化函数MPU6050.c

#include "stm32f10x.h"                  // Device header
#include "MyI2C.h"
#include "MPU6050_Reg.h"

#define MPU6050_ADDRESS		0xD0

void MPU6050_WriteReg(uint8_t RegAddress, uint8_t Data)
{
	//指定地址写寄存器
	MyI2C_Start();	//起始
	MyI2C_SendByte(MPU6050_ADDRESS);//发送字节 指定从机地址和读写位
	MyI2C_ReceiveAck();//接收应答
	MyI2C_SendByte(RegAddress);//发送字节 指定寄存器地址
	MyI2C_ReceiveAck();//接收应答
	MyI2C_SendByte(Data);//写入寄存器的数据
	MyI2C_ReceiveAck();//接收应答
	MyI2C_Stop();//终止
	
}

uint8_t MPU6050_ReadReg(uint8_t RegAddress)
{
	//指定地址读
	uint8_t Data;//接收到的数据
	
	MyI2C_Start();	//起始
	MyI2C_SendByte(MPU6050_ADDRESS);	//发送字节 指定从机地址和读写位
	MyI2C_ReceiveAck();		//接收应答
	MyI2C_SendByte(RegAddress);		//发送字节 指定寄存器地址
	MyI2C_ReceiveAck();		//接收应答
	
	MyI2C_Start();	//重复起始
	MyI2C_SendByte(MPU6050_ADDRESS | 0x01);	//发送字节 指定从机地址和读写位 或0x01变成读
	MyI2C_ReceiveAck();		//接收应答
	Data = MyI2C_ReceiveByte();		//接收一个字节
	MyI2C_SendAck(1);	//发送应答 1为不给从机应答 0则为主机还要读字节
	MyI2C_Stop();	//终止
	
	return Data;	//返回读到的数据
}

void MPU6050_Init(void)
{
	//MPU6050硬件电路初始化配置
	MyI2C_Init(); 
	MPU6050_WriteReg(MPU6050_PWR_MGMT_1, 0x01);		//电源管理寄存器1 解除睡眠 配置陀螺仪时钟
	MPU6050_WriteReg(MPU6050_PWR_MGMT_2, 0x00);		//电源管理寄存器2 六轴均不待机
	MPU6050_WriteReg(MPU6050_SMPLRT_DIV, 0x09);		//采样率分频 分频为10
	MPU6050_WriteReg(MPU6050_CONFIG, 0x06);		//配置寄存器 滤波参数最大
	MPU6050_WriteReg(MPU6050_GYRO_CONFIG, 0x18);	//陀螺仪配置寄存器 最大量程
	MPU6050_WriteReg(MPU6050_ACCEL_CONFIG, 0x18);	//加速度计配置寄存器 最大量程
}

uint8_t MPU6050_GetID(void)
{
	//获取芯片ID号
	return MPU6050_ReadReg(MPU6050_WHO_AM_I);
}

void MPU6050_GetData(int16_t *AccX, int16_t *AccY, int16_t *AccZ, 
						int16_t *GyroX, int16_t *GyroY, int16_t *GyroZ)
{
	//读取MPU6050数据
	uint8_t DataH, DataL;//高八位 低八位
	
	//加速度计数据
	DataH = MPU6050_ReadReg(MPU6050_ACCEL_XOUT_H);
	DataL = MPU6050_ReadReg(MPU6050_ACCEL_XOUT_L);
	*AccX = (DataH << 8) | DataL;
	
	DataH = MPU6050_ReadReg(MPU6050_ACCEL_YOUT_H);
	DataL = MPU6050_ReadReg(MPU6050_ACCEL_YOUT_L);
	*AccY = (DataH << 8) | DataL;
	
	DataH = MPU6050_ReadReg(MPU6050_ACCEL_ZOUT_H);
	DataL = MPU6050_ReadReg(MPU6050_ACCEL_ZOUT_L);
	*AccZ = (DataH << 8) | DataL;
	
	//陀螺仪数据
	DataH = MPU6050_ReadReg(MPU6050_GYRO_XOUT_H);
	DataL = MPU6050_ReadReg(MPU6050_GYRO_XOUT_L);
	*GyroX = (DataH << 8) | DataL;
	
	DataH = MPU6050_ReadReg(MPU6050_GYRO_YOUT_H);
	DataL = MPU6050_ReadReg(MPU6050_GYRO_YOUT_L);
	*GyroY = (DataH << 8) | DataL;
	
	DataH = MPU6050_ReadReg(MPU6050_GYRO_ZOUT_H);
	DataL = MPU6050_ReadReg(MPU6050_GYRO_ZOUT_L);
	*GyroZ = (DataH << 8) | DataL;
}

1.3 主函数

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "MPU6050.h"

uint8_t ID;
int16_t AX, AY, AZ, GX, GY, GZ;		//加速度计和陀螺仪数据

int main(void)
{
	OLED_Init();
	MPU6050_Init(); 
	
	//显示芯片ID
	OLED_ShowString(1, 1, "ID:");		
	ID = MPU6050_GetID();
	OLED_ShowHexNum(1, 4, ID, 2);
	
	while (1)
	{
		MPU6050_GetData(&AX, &AY, &AZ, &GX, &GY, &GZ);		//读取MPU6050数据
		OLED_ShowSignedNum(2, 1, AX, 5);
		OLED_ShowSignedNum(3, 1, AY, 5);
		OLED_ShowSignedNum(4, 1, AZ, 5);
		OLED_ShowSignedNum(2, 8, GX, 5);
		OLED_ShowSignedNum(3, 8, GY, 5);
		OLED_ShowSignedNum(4, 8, GZ, 5);
	}
}


总结

以上就是关于MPU6050的相关知识及一些个人认为的重点。并且在最后给出如何使用软件模拟I2C通信来读取MPU6050数据的详细代码。

 

  • 0
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值