目录

前言

I2C

MPU6050 

 技术实现

原理图

连线图 

代码实现 

 技术要点

MPU6050初始化

事件超时处理

指定地址写

指定地址读

读取数据寄存器 

问题记录


前言

I2C

I2C(Inter-Integrated Circuit)是一种由飞利浦公司在1980年代开发的串行通信协议,主要用于在同一电路板上的短距离集成电路之间的通信。它以两线式接口著称,这两条线分别是SDA(数据线)和SCL(时钟线),允许通过这些线路在支持I2C协议的各种设备之间进行双向通信。I2C协议支持多主多从架构,使得多个设备可以通过共享的数据线和时钟线实现有效的通信。其特点是简单、成本低,并且能够支持多种速度标准,如标准模式(100 kbit/s)、快速模式(400 kbit/s)以及高速模式(3.4 Mbit/s),适用于各种应用场景,包括但不限于传感器数据交换、EEPROM编程等。

I2C主要特点 (部分)

  • 并行总线/I2C总线协议转换器
  • 多主机功能,该模块既可做主设备也可做从设备
  • I2C主设备功能

        ——产生时钟

        ——产生起始和终止信号    

  • I2C从设备功能

        ——可编程的I2C地址检测

        ——可响应两个从地址的双地址功能

        ——停止检测位

  • 支持不同的通讯速度

        ——标准速度(高达100kHz)

        ——快速(高达400kHz) 

模式选择

接口可以下列4种模式中的一种运行:

  • 从发送器模式
  • 从接收器模式
  • 主发送器模式
  • 主接收器模式

该模块默认地工作于从模式接口在生成起始条件后自动地从从模式切换到主模式: 当仲裁丢失或产生停止信号时,则从主模式切换到从模式。允许多主机功能。

通信流

 主模式时,I2C接口启动数据传输并产生时钟信号。串行数据传输总是以起始条件开始并以停止条件结束。起始条件和停止条件都是在主模式下由软件控制产生。

从模式时,I2C接口能识别它自己的地址(7位或10位)和广播呼叫地址。软件能够控制开启或禁止广播呼叫地址的识别。

数据和地址按8位/字节传输,高位在前。跟在起始条件之后的1或2个字节是地址(7位模式为1个字节,10位模式为2个字节)。地址只在主模式发送。

在一个字节传输的8个时钟后的第9个时钟期间,接收器必须回送一个应答位(ACK)给发送器。

软件可以开启或禁止应答(ACK),并可以设置I2C接口的地址(7位、10位地址或广播呼叫地址)

 I2C主模式

在主模式时,I2C接口启动数据传输并产生时钟信号。串行数据传输总是以起始条件开始并以停止条件结束。当通过START位在总线上产生了起始条件,设备就进入了主模式。

起始条件

当BUSY=0时,设置START=1,I2C接口将产生一个开始条件并切换至主模式。

一旦发出开始条件:SB位被硬件置位,然后主设备等待读SR1寄存器,紧跟着将从地址写入DR寄存器(EV5)。 

从地址的发送

 从地址通过内部移位寄存器被送到SDA线上。

在7位地址模式时,只需送出一个地址字节。

——一旦改地址字节被送出,ADDR位被硬件置位,随后主设备等待一次读SR1寄存器,跟着读SR2寄存器。根据送出从地址的最低位,主设备决定进入发送器模式还是接收器模式。

在 7位地址模式时,

——要进入发送器模式,主设备发送从地址时置最低位为‘0’。

——要进入接收器模式,主设备发送从地址时置最低为‘1’。

主发送器

在发送了地址和清除了ADDR位后,主设备通过内部移位寄存器将字节从DR寄存器发送到SDA线上。

主设备等待,直到TxE被清除。(EV8)

当收到应答脉冲时:

        TxE位被硬件置位,如果TxE被置位并且在上一次数据发送结束之前没有写入新的数据字节到DR寄存器,则BTF位被硬件置位,在清除BTF之前I2C接口将保持SCL为低电平;读出I2C_SR1之后再写入I2C_DR寄存器将清除BTF位。

关闭通信

在DR寄存器中写入最后一个字节后,通过设置STOP位产生一个停止条件(EV8_2)然后I2C接口将自动回到从模式。

主接收器

在发送地址和清除ADDR之后,I2C接口进入主接收器模式。在此模式下,I2C接口从SDA线接收数据字节,并通过内部移位寄存器送至DR寄存器。在每个字节后,I2C接口依次执行以下操作:

  • 如果ACK位被置位,发出一个应答脉冲。
  • 硬件设置RxNE=1(EV7)

如果RxNE位被置位,并且在接收新数据结束之前,DR寄存器中的数据没有被读走,硬件将设置BTF=1,在清除BTF之前I2C接口将保持SCL为低电平读出I2C_SR1之后再读出I2C_DR寄存器将清除BTF位。

关闭通信

主设备在从从设备接收到最后一个字节后发送一个NACK。接收到NACK后,从设备释放对SCL和SDA线的控制:主设备就可以发送一个停止/重起始条件。

  • 为了在收到最后一个字节后发送一个NACK,在读倒数第二个数据字节之后(在倒数第二个RxNE事件之后)必须清除ACK位。
  • 为了产生一个停止/重起始条件软件必须在读倒数第二个数据字节之后(在倒数第二个RxNE事件之后)设置STOP/START位。
  • 只接收一个字节时,刚好在EV6之后(EV6_1时,清除ADDR之后)要关闭应答和停止条件的产生位。

在产生了停止条件后,I2C接口自动回到从模式。

MPU6050 

MPU6050是一款集成的运动处理传感器,它结合了一个3轴陀螺仪和一个3轴加速度计,能够提供精确的角速度和加速度数据,常用于姿态检测、运动跟踪及导航等应用。该器件支持I2C和SPI通信接口,便于与微控制器(如Arduino、STM32等)连接,并且内置数字运动处理器(DMP),可以分担主控芯片的数据处理负担,提高系统效率。MPU6050广泛应用于无人机、机器人、可穿戴设备等领域,因其高性价比和易用性而受到开发者青睐。

 技术实现

原理图

连线图 

代码实现 

main.c

/**********************************************************
1.实验名称:I2C读取MPU6050
2.实验环境:STM32F103C8T6最小系统板
3.实验内容:使用I2C协议与MPU6050通信,读取寄存器获取加速度计
			和陀螺仪数据,显示加速度和角速度
4.作者;abai
5.实验时间:2025-4-28
**********************************************************/
#include "stm32f10x.h"                  // Device header
#include "Delay.h"						//延时函数
#include "OLED.h"
#include "MPU6050.h"

int main(void)
{
	int16_t Acce_x,Acce_y,Acce_z,Gyro_x,Gyro_y,Gyro_z;
	
	/*
		OLED初始化
	*/
	OLED_Init();
	MPU6050_Init();
	
	while(1)
	{
		MPU6050_GetValue(&Acce_x,&Acce_y,&Acce_z,&Gyro_x,&Gyro_y,&Gyro_z);
		OLED_ShowString(1,1,"Acce:");
		OLED_ShowString(1,9,"Gyro:");
		OLED_ShowSignedNum(2,1,Acce_x,5);
		OLED_ShowSignedNum(3,1,Acce_y,5);
		OLED_ShowSignedNum(4,1,Acce_z,5);
		OLED_ShowSignedNum(2,9,Gyro_x,5);
		OLED_ShowSignedNum(3,9,Gyro_y,5);
		OLED_ShowSignedNum(4,9,Gyro_z,5);
	}
}

MPU6050_Reg.h 

#ifndef MPU6050_REG_H
#define MPU6050_REG_H

//寄存器宏
#define MPU6050_SMPLRT_DIV   0X19
#define MPU6050_CONFIG	     0X1A
#define MPU6050_GYRO_CONFIG  0X1B
#define MPU6050_ACCEL_CONFIG 0X1C
#define MPU6050_ACCEL_XOUT_H 0X3B
#define MPU6050_ACCEL_XOUT_L 0X3C
#define MPU6050_ACCEL_YOUT_H 0X3D
#define MPU6050_ACCEL_YOUT_L 0X3E
#define MPU6050_ACCEL_ZOUT_H 0X3F
#define MPU6050_ACCEL_ZOUT_L 0X40
#define MPU6050_TEMP_OUT_H   0X41
#define MPU6050_TEMP_OUT_L   0X42
#define MPU6050_GYRO_XOUT_H  0X43
#define MPU6050_GYRO_XOUT_L  0X44
#define MPU6050_GYRO_YOUT_H  0X45
#define MPU6050_GYRO_YOUT_L  0X46
#define MPU6050_GYRO_ZOUT_H  0X47
#define MPU6050_GYRO_ZOUT_L  0X48
#define MPU6050_PWR_MGMT_1   0X6B
#define MPU6050_PWR_MGMT_2   0X6C
#define MPU6050_WHO_AM_I     0X75

#endif

MPU6050.h 

#ifndef MPU6050_H
#define MPU6050_H

#include "stm32f10x.h"                  // Device header

void MPU6050_Init(void);
void MPU6050_WriteReg(uint8_t RegAddress, uint8_t Data);
uint8_t MPU6050_RedReg(uint8_t RegAddress);
void MPU6050_GetValue(int16_t* Acce_x, int16_t* Acce_y, int16_t* Acce_z,
						int16_t* Gyro_x, int16_t* Gyro_y, int16_t* Gyro_z);
void MPU6050_RedTemp(int16_t* Temp);

#endif

MPU6050.c 

#include "MPU6050.h"
#include "MPU6050_Reg.h"

#define MPU6050_ADDRESS 0xD0

static void MPU6050_WaitEvent(I2C_TypeDef* I2Cx, uint32_t I2C_EVENT);

void MPU6050_Init(void)
{
	
	
//	MyI2C_Init();
	//开启时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C2,ENABLE);
	
	//GPIO
	GPIO_InitTypeDef GPIO_InitStruct;
	GPIO_InitStruct.GPIO_Pin 	= GPIO_Pin_10 | GPIO_Pin_11;
	GPIO_InitStruct.GPIO_Mode 	= GPIO_Mode_AF_OD;							//SDA和SCL均设置为复用开漏输出,将GPIO映射到片上外设
	GPIO_InitStruct.GPIO_Speed 	= GPIO_Speed_50MHz;
	
	GPIO_Init(GPIOB,&GPIO_InitStruct);
	
	//初始化I2C
	I2C_InitTypeDef I2C_InitStruct;
	I2C_InitStruct.I2C_Ack 					= I2C_Ack_Enable;
	I2C_InitStruct.I2C_AcknowledgedAddress 	= I2C_AcknowledgedAddress_7bit;	//主机自身地址为7位地址
	I2C_InitStruct.I2C_ClockSpeed 			= 20000;
	I2C_InitStruct.I2C_DutyCycle 			= I2C_DutyCycle_2;
	I2C_InitStruct.I2C_Mode 				= I2C_Mode_I2C;
	I2C_InitStruct.I2C_OwnAddress1 			= 0X00;							//这里I2C2只用作主机,不使用从机模式,这里地址随便设置,但不要和从机地址重复
	I2C_Init(I2C2,&I2C_InitStruct);
	//解除睡眠
	MPU6050_WriteReg(MPU6050_PWR_MGMT_1,0X01);								//电源管理寄存器1
	//6个轴均不待机
	MPU6050_WriteReg(MPU6050_PWR_MGMT_2,0X00);								//电源管理寄存器2
	MPU6050_WriteReg(MPU6050_SMPLRT_DIV,0X09);								//采样率分频寄存器
	MPU6050_WriteReg(MPU6050_CONFIG,0x06);									//不使用帧同步,低通滤波采用最平滑滤波即110B
	MPU6050_WriteReg(MPU6050_GYRO_CONFIG,0X18);								//陀螺仪配置寄存器s
	MPU6050_WriteReg(MPU6050_ACCEL_CONFIG,0X18);							//加速度计寄存器
	
}
//事件等待超时处理
static void MPU6050_WaitEvent(I2C_TypeDef* I2Cx, uint32_t I2C_EVENT)
{
	uint32_t Time_Out = 1000;
	while(I2C_CheckEvent(I2Cx,I2C_EVENT) != SUCCESS)
	{
		Time_Out--;
		if(Time_Out == 0)
		{
			break;
		}
	}
}
//指定地址写
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();
	
	I2C_GenerateSTART(I2C2,ENABLE);											//I2C起始信号
	MPU6050_WaitEvent(I2C2,I2C_EVENT_MASTER_MODE_SELECT);					//检查等待EV5事件的发生
	
	I2C_Send7bitAddress(I2C2,MPU6050_ADDRESS,I2C_Direction_Transmitter);	//发送从机地址
	//硬件会自动接收处理应答位,无需调用库函数接收
	MPU6050_WaitEvent(I2C2,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED);		//检查等待EV6事件的发生
	//不需要等待EV8_1事件的发生
	
	I2C_SendData(I2C2,RegAddress);											//发送指定的寄存器的地址
	MPU6050_WaitEvent(I2C2,I2C_EVENT_MASTER_BYTE_TRANSMITTING);				//等待EV8事件
	
	I2C_SendData(I2C2,Data);
	MPU6050_WaitEvent(I2C2,I2C_EVENT_MASTER_BYTE_TRANSMITTED);				//等待EV8_2事件
	
	I2C_GenerateSTOP(I2C2,ENABLE);
}
//指定地址读
uint8_t MPU6050_RedReg(uint8_t RegAddress)
{
	uint8_t ByteValue;
//	MyI2C_Start();
//	MyI2C_SendByte(MPU6050_ADDRESS);
//	MyI2C_ReceiveACK();
//	MyI2C_SendByte(RegAddress);
//	MyI2C_ReceiveACK();
//	
//	MyI2C_Start();
//	MyI2C_SendByte(MPU6050_ADDRESS | 0x01);
//	MyI2C_ReceiveACK();
//	ByteValue = MyI2C_ReceiveByte();
//	MyI2C_SendACK(1);
//	MyI2C_Stop();
	
	I2C_GenerateSTART(I2C2,ENABLE);											//I2C起始信号
	MPU6050_WaitEvent(I2C2,I2C_EVENT_MASTER_MODE_SELECT);					//检查等待EV5事件的发生
	
	I2C_Send7bitAddress(I2C2,MPU6050_ADDRESS,I2C_Direction_Transmitter);	//发送从机地址
	//硬件会自动接收处理应答位,无需调用库函数接收
	MPU6050_WaitEvent(I2C2,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED);		//检查等待EV6事件的发生
	//不需要等待EV8_1事件的发生
	
	I2C_SendData(I2C2,RegAddress);											//发送指定的寄存器的地址
	MPU6050_WaitEvent(I2C2,I2C_EVENT_MASTER_BYTE_TRANSMITTED);				//等待数据字节发送完毕,等待EV8_2事件的发生
	
	I2C_GenerateSTART(I2C2,ENABLE);											//I2C起始信号
	MPU6050_WaitEvent(I2C2,I2C_EVENT_MASTER_MODE_SELECT);					//检查等待EV5事件的发生
	
	I2C_Send7bitAddress(I2C2,MPU6050_ADDRESS,I2C_Direction_Receiver);		//发送从机地址
	//硬件会自动接收处理应答位,无需调用库函数接收
	MPU6050_WaitEvent(I2C2,I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED);		//检查等待EV6事件的发生
	//不需要等待EV6_1事件的发生
	
	//在接收最后一个字节之前发送,防止接受到最后一个字节后自动发送了应答位
	I2C_AcknowledgeConfig(I2C2,DISABLE);									//关闭发送ACK,主机自动发送非应答位
	I2C_GenerateSTOP(I2C2,ENABLE);											//申请产生I2C终止条件

	MPU6050_WaitEvent(I2C2,I2C_EVENT_MASTER_BYTE_RECEIVED);					//等待EV7事件的发生
	ByteValue = I2C_ReceiveData(I2C2);
	
	I2C_AcknowledgeConfig(I2C2,DISABLE);									//将ACK恢复默认为应答位
	
	return ByteValue;
}

//读取数据寄存器
void MPU6050_GetValue(int16_t* Acce_x, int16_t* Acce_y, int16_t* Acce_z,
						int16_t* Gyro_x, int16_t* Gyro_y, int16_t* Gyro_z)
{
	uint8_t Data_H,Data_L;
	//加速度计X轴
	Data_H = MPU6050_RedReg(MPU6050_ACCEL_XOUT_H);
	Data_L = MPU6050_RedReg(MPU6050_ACCEL_XOUT_L);
	*Acce_x = (Data_H << 8) | Data_L;
	//加速度计Y轴
	Data_H = MPU6050_RedReg(MPU6050_ACCEL_YOUT_H);
	Data_L = MPU6050_RedReg(MPU6050_ACCEL_YOUT_L);
	*Acce_y = (Data_H << 8) | Data_L;
	//加速度计Z轴
	Data_H = MPU6050_RedReg(MPU6050_ACCEL_ZOUT_H);
	Data_L = MPU6050_RedReg(MPU6050_ACCEL_ZOUT_L);
	*Acce_z = (Data_H << 8) | Data_L;
	
	//陀螺仪x轴
	Data_H = MPU6050_RedReg(MPU6050_GYRO_XOUT_H);
	Data_L = MPU6050_RedReg(MPU6050_GYRO_XOUT_L);
	*Gyro_x = (Data_H << 8) | Data_L;
	
	//陀螺仪y轴
	Data_H = MPU6050_RedReg(MPU6050_GYRO_YOUT_H);
	Data_L = MPU6050_RedReg(MPU6050_GYRO_YOUT_L);
	*Gyro_y = (Data_H << 8) | Data_L;
	
	//陀螺仪Z轴
	Data_H = MPU6050_RedReg(MPU6050_GYRO_ZOUT_H);
	Data_L = MPU6050_RedReg(MPU6050_GYRO_ZOUT_L);
	*Gyro_z = (Data_H << 8) | Data_L;
}

void MPU6050_RedTemp(int16_t* Temp)
{
	int16_t Data_H,Data_L;
	Data_H = MPU6050_RedReg(MPU6050_TEMP_OUT_H);
	Data_L = MPU6050_RedReg(MPU6050_TEMP_OUT_L);
	*Temp = (Data_H << 8) | Data_L;
}

  OLED部分代码参照文章《STM32基础教程——OLED显示》http://【STM32基础教程 ——OLED显示 - CSDN App】https://blog.csdn.net/2301_80319641/article/details/145837521?sharetype=blog&shareId=145837521&sharerefer=APP&sharesource=2301_80319641&sharefrom=link

 技术要点

MPU6050初始化

void MPU6050_Init(void)
{
	
	
//	MyI2C_Init();
	//开启时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C2,ENABLE);
	
	//GPIO
	GPIO_InitTypeDef GPIO_InitStruct;
	GPIO_InitStruct.GPIO_Pin 	= GPIO_Pin_10 | GPIO_Pin_11;
	GPIO_InitStruct.GPIO_Mode 	= GPIO_Mode_AF_OD;							//SDA和SCL均设置为复用开漏输出,将GPIO映射到片上外设
	GPIO_InitStruct.GPIO_Speed 	= GPIO_Speed_50MHz;
	
	GPIO_Init(GPIOB,&GPIO_InitStruct);
	
	//初始化I2C
	I2C_InitTypeDef I2C_InitStruct;
	I2C_InitStruct.I2C_Ack 					= I2C_Ack_Enable;
	I2C_InitStruct.I2C_AcknowledgedAddress 	= I2C_AcknowledgedAddress_7bit;	//主机自身地址为7位地址
	I2C_InitStruct.I2C_ClockSpeed 			= 20000;
	I2C_InitStruct.I2C_DutyCycle 			= I2C_DutyCycle_2;
	I2C_InitStruct.I2C_Mode 				= I2C_Mode_I2C;
	I2C_InitStruct.I2C_OwnAddress1 			= 0X00;							//这里I2C2只用作主机,不使用从机模式,这里地址随便设置,但不要和从机地址重复
	I2C_Init(I2C2,&I2C_InitStruct);
	//解除睡眠
	MPU6050_WriteReg(MPU6050_PWR_MGMT_1,0X01);								//电源管理寄存器1
	//6个轴均不待机
	MPU6050_WriteReg(MPU6050_PWR_MGMT_2,0X00);								//电源管理寄存器2
	MPU6050_WriteReg(MPU6050_SMPLRT_DIV,0X09);								//采样率分频寄存器
	MPU6050_WriteReg(MPU6050_CONFIG,0x06);									//不使用帧同步,低通滤波采用最平滑滤波即110B
	MPU6050_WriteReg(MPU6050_GYRO_CONFIG,0X18);								//陀螺仪配置寄存器s
	MPU6050_WriteReg(MPU6050_ACCEL_CONFIG,0X18);							//加速度计寄存器
	
}

 

1.开启GPIO和I2C2的时钟

2.初始化GPIO,查找引脚定义表,I2C2外设复用PB10和PB11引脚分别作为SCL和SDA,将他们初始化为复用开漏输出。

3.调用I2C_Init()函数初始化I2C,启用应答位,主机自身地址设置为7位地址,传播速率为20kHz,高速模式SCL低电平:高电平占空比2:1,但是这里使用的速率只有20kHz,属于标准模式。所以这个设置不起作用。I2C模式选用I2C模式(该外设兼容SMBus)。本实验只使用主模式,主机自身地址可随便设置。

 4.MPU6050初始化,先初始化I2C,然后指定电源管理寄存器1写入命令0x01,解除MPU6050睡眠,再指定电源管理寄存器2,写入命令0x00,设置6个轴均不待机。然后指定采样分频率寄存器,写入命令0x09,采用10分频。制定MPOU6050 配置寄存器,写入命令0x06,不采用帧同步,采用最平滑的滤波对应位写入110B。对陀螺仪和加速度计寄存器均配置为不自检模式,量程选择最大范围。

事件超时处理

//事件等待超时处理
static void MPU6050_WaitEvent(I2C_TypeDef* I2Cx, uint32_t I2C_EVENT)
{
	uint32_t Time_Out = 1000;
	while(I2C_CheckEvent(I2Cx,I2C_EVENT) != SUCCESS)
	{
		Time_Out--;
		if(Time_Out == 0)
		{
			break;
		}
	}
}

调用I2C_CheckEvent()函数进行事件检测,该函数适用于大多数情况事件检测。添加局部变量在死循环中计次,防止死循环在事件未发生的情况下卡住整个程序。当计次结束后,若事件仍未发生则执行break语句跳出循环。

指定地址写

//指定地址写
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();
	
	I2C_GenerateSTART(I2C2,ENABLE);											//I2C起始信号
	MPU6050_WaitEvent(I2C2,I2C_EVENT_MASTER_MODE_SELECT);					//检查等待EV5事件的发生
	
	I2C_Send7bitAddress(I2C2,MPU6050_ADDRESS,I2C_Direction_Transmitter);	//发送从机地址
	//硬件会自动接收处理应答位,无需调用库函数接收
	MPU6050_WaitEvent(I2C2,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED);		//检查等待EV6事件的发生
	//不需要等待EV8_1事件的发生
	
	I2C_SendData(I2C2,RegAddress);											//发送指定的寄存器的地址
	MPU6050_WaitEvent(I2C2,I2C_EVENT_MASTER_BYTE_TRANSMITTING);				//等待EV8事件
	
	I2C_SendData(I2C2,Data);
	MPU6050_WaitEvent(I2C2,I2C_EVENT_MASTER_BYTE_TRANSMITTED);				//等待EV8_2事件
	
	I2C_GenerateSTOP(I2C2,ENABLE);
}

  

调用I2C_GenerateSTART()函数发送I2C起始信号,然后检测等待EV5事件发生。 

发送7位地址,数据传输方向选择写数据,硬件会自动接收处理应答位,无需库函数去处理。然后检测等待EV6事件。

无需等待EV8_1事件,因为地址发送后,数据寄存器和移位寄存器全部都为空了。调用I2C_SendData()函数,发送寄存器地址。然后等待EV8事件,当EV8事件发生后,此时数据寄存器为空,可以向数据寄存器写入数据。

调用I2C_SendData()函数,发送数据,然后检测等待EV8_2事件。

发送停止信号。

指定地址读

//指定地址读
uint8_t MPU6050_RedReg(uint8_t RegAddress)
{
	uint8_t ByteValue;
//	MyI2C_Start();
//	MyI2C_SendByte(MPU6050_ADDRESS);
//	MyI2C_ReceiveACK();
//	MyI2C_SendByte(RegAddress);
//	MyI2C_ReceiveACK();
//	
//	MyI2C_Start();
//	MyI2C_SendByte(MPU6050_ADDRESS | 0x01);
//	MyI2C_ReceiveACK();
//	ByteValue = MyI2C_ReceiveByte();
//	MyI2C_SendACK(1);
//	MyI2C_Stop();
	
	I2C_GenerateSTART(I2C2,ENABLE);											//I2C起始信号
	MPU6050_WaitEvent(I2C2,I2C_EVENT_MASTER_MODE_SELECT);					//检查等待EV5事件的发生
	
	I2C_Send7bitAddress(I2C2,MPU6050_ADDRESS,I2C_Direction_Transmitter);	//发送从机地址
	//硬件会自动接收处理应答位,无需调用库函数接收
	MPU6050_WaitEvent(I2C2,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED);		//检查等待EV6事件的发生
	//不需要等待EV8_1事件的发生
	
	I2C_SendData(I2C2,RegAddress);											//发送指定的寄存器的地址
	MPU6050_WaitEvent(I2C2,I2C_EVENT_MASTER_BYTE_TRANSMITTED);				//等待数据字节发送完毕,等待EV8_2事件的发生
	
	I2C_GenerateSTART(I2C2,ENABLE);											//I2C起始信号
	MPU6050_WaitEvent(I2C2,I2C_EVENT_MASTER_MODE_SELECT);					//检查等待EV5事件的发生
	
	I2C_Send7bitAddress(I2C2,MPU6050_ADDRESS,I2C_Direction_Receiver);		//发送从机地址
	//硬件会自动接收处理应答位,无需调用库函数接收
	MPU6050_WaitEvent(I2C2,I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED);		//检查等待EV6事件的发生
	//不需要等待EV6_1事件的发生
	
	//在接收最后一个字节之前发送,防止接受到最后一个字节后自动发送了应答位
	I2C_AcknowledgeConfig(I2C2,DISABLE);									//关闭发送ACK,主机自动发送非应答位
	I2C_GenerateSTOP(I2C2,ENABLE);											//申请产生I2C终止条件

	MPU6050_WaitEvent(I2C2,I2C_EVENT_MASTER_BYTE_RECEIVED);					//等待EV7事件的发生
	ByteValue = I2C_ReceiveData(I2C2);
	
	I2C_AcknowledgeConfig(I2C2,ENABLE);									//将ACK恢复默认为应答位
	
	return ByteValue;
}

  

调用I2C_GenerateSTART()函数发送I2C起始信号,然后检测等待EV5事件发生。 

发送7位地址,数据传输方向选择写数据,硬件会自动接收处理应答位,无需库函数去处理。然后检测等待EV6事件。

无需等待EV8_1事件,因为地址发送后,数据寄存器和移位寄存器全部都为空了。调用I2C_SendData()函数,发送寄存器地址。然后等待EV8事件,当EV8事件发生后,此时数据寄存器为空,可以向数据寄存器写入数据。

再次调用I2C_GenerateSTART()函数,发送I2C起始信号,然后等待EV5事件的发生。

发送7位地址,数据传输方向选择读数据,硬件会自处理接收应答位,无需库函数去处理。然后检测等待EV6事件。

无需等待EV6_1事件发生。本函数一次只接收一个数据字节,在接收最后一个数据字节之前,先失能ACK信号的发送,故会发送非应答信号。发送I2C停止信号。 

然后等待EV7_1事件的发生,该事件发生后数据接收寄存器非空,此时读取接受数据寄存器,将接收的数据字节读出。

最后使能ACK信号,恢复默认,防止影响后续操作。

最后将接收的数据字节返回。

读取数据寄存器 

//读取数据寄存器
void MPU6050_GetValue(int16_t* Acce_x, int16_t* Acce_y, int16_t* Acce_z,
						int16_t* Gyro_x, int16_t* Gyro_y, int16_t* Gyro_z)
{
	uint8_t Data_H,Data_L;
	//加速度计X轴
	Data_H = MPU6050_RedReg(MPU6050_ACCEL_XOUT_H);
	Data_L = MPU6050_RedReg(MPU6050_ACCEL_XOUT_L);
	*Acce_x = (Data_H << 8) | Data_L;
	//加速度计Y轴
	Data_H = MPU6050_RedReg(MPU6050_ACCEL_YOUT_H);
	Data_L = MPU6050_RedReg(MPU6050_ACCEL_YOUT_L);
	*Acce_y = (Data_H << 8) | Data_L;
	//加速度计Z轴
	Data_H = MPU6050_RedReg(MPU6050_ACCEL_ZOUT_H);
	Data_L = MPU6050_RedReg(MPU6050_ACCEL_ZOUT_L);
	*Acce_z = (Data_H << 8) | Data_L;
	
	//陀螺仪x轴
	Data_H = MPU6050_RedReg(MPU6050_GYRO_XOUT_H);
	Data_L = MPU6050_RedReg(MPU6050_GYRO_XOUT_L);
	*Gyro_x = (Data_H << 8) | Data_L;
	
	//陀螺仪y轴
	Data_H = MPU6050_RedReg(MPU6050_GYRO_YOUT_H);
	Data_L = MPU6050_RedReg(MPU6050_GYRO_YOUT_L);
	*Gyro_y = (Data_H << 8) | Data_L;
	
	//陀螺仪Z轴
	Data_H = MPU6050_RedReg(MPU6050_GYRO_ZOUT_H);
	Data_L = MPU6050_RedReg(MPU6050_GYRO_ZOUT_L);
	*Gyro_z = (Data_H << 8) | Data_L;
}

读取加速度计和陀螺仪的数据寄存器,分别读取加速度计和陀螺仪的X,Y,Z轴高8位数据寄存器和低8位数据寄存器。传递指针参数存储相应的数据。

问题记录

暂无

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐