软件I2C读写MPU6050&硬件I2C读写MPU6050

目录

软件I2C读写MPU6050

MyI2C

MPU6050

主函数

硬件I2C读写MPU6050


软件I2C读写MPU6050

MyI2C

 写6个基本时序单元的函数,然后将这些函数拼接起来写 发送数据接收数据,发送应答接收应答函数。

#include "stm32f10x.h"                  // Device header
#include "DELAY.H"

void MyI2C_Init(void)
{
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
	
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_OD;//开漏输出模式仍然可以输入,输入时,先输出1                    再直接读取输入寄存器
	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);  	//都置高电平,进行初始化
}

void MyI2C_W_SCL(uint8_t BitValue) //W 释放,输出
{
	GPIO_WriteBit(GPIOB,GPIO_Pin_10,(BitAction)BitValue);   //BitAction:Bit_RESET;Bit_SET
	Delay_us(10);
}            

void MyI2C_W_SDA(uint8_t BitValue)
{
	GPIO_WriteBit(GPIOB,GPIO_Pin_11,(BitAction)BitValue);   
	Delay_us(10);
}

uint8_t MyI2C_R_SDA(void)
{
	uint8_t BitValue;
	BitValue=GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_11);
	Delay_us(10);
	return BitValue;
}


void MyI2C_Start(void)
{
	MyI2C_W_SDA(1);						//把这个放前面,同时兼容重复起始条件
	MyI2C_W_SCL(1);
	MyI2C_W_SDA(0);
	MyI2C_W_SCL(0);
}
void MyI2C_Stop(void)
{
	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));   //为了获得某一位。传入参数ox....到函数里会变成1/0
		MyI2C_W_SCL(1);                //释放SCL,从机会读取SDA。
		MyI2C_W_SCL(0);  			   //除了终止的函数,其余的在最后把SCL拉低,为了方便拼接
	}
}

uint8_t MyI2C_RecieveByte(void)
{
	uint8_t Byte=0x00;
	MyI2C_W_SDA(1);    				 //主机释放SDA也相当于切换为输入模式,从机把数据放到SDA
	uint8_t i;
	for(i=0;i<8;i++)
	{
		MyI2C_W_SCL(1);      		//主机可以读取SDA
		if(MyI2C_R_SDA()==1)
		{
			Byte|=(0x80>>i);
		}
		MyI2C_W_SCL(0);
	}
	return Byte;
}

void MyI2C_SendAck(uint8_t Ack)
{
		MyI2C_W_SDA(Ack);   			//为了获得某一位。传入参数ox....到函数里会变成1/0
		MyI2C_W_SCL(1);                //释放SCL,从机会读取SDA。
		MyI2C_W_SCL(0);  			   //除了终止的函数,其余的在最后把SCL拉低,为了方便拼接
}

uint8_t MyI2C_RecieveAck(void)
{
	uint8_t Ack;
	MyI2C_W_SDA(1);    			 //主机释放SDA也相当于切换为输入模式,从机把数据放到SDA
	MyI2C_W_SCL(1);      		//主机可以读取SDA
	Ack=MyI2C_R_SDA();
	MyI2C_W_SCL(0);
	return Ack;
}

MPU6050

初始化MPU6050将MyI2C封装,将发送数据接收数据,发送应答接收应答函数完成完整的I2C时序,进行对指定地址读,指定地址写。 

#include "stm32f10x.h"                  // Device header
#include "MYI2C.H"

#define MPU6050_Address 0xD0

void MPU6050_WriteReg(uint8_t RegAddress,uint8_t data)
{
	MyI2C_Start();
	MyI2C_SendByte(MPU6050_Address);
	MyI2C_RecieveAck();
	MyI2C_SendByte(RegAddress);
	MyI2C_RecieveAck();
	MyI2C_SendByte(data);
	MyI2C_RecieveAck();
	MyI2C_Stop();
}
uint8_t MPU6050_ReadReg(uint8_t RegAddress)
{
	uint8_t data;
	MyI2C_Start();
	MyI2C_SendByte(MPU6050_Address);
	MyI2C_RecieveAck();
	MyI2C_SendByte(RegAddress);
	MyI2C_RecieveAck();
	
	MyI2C_Start();      					//重新开始
	MyI2C_SendByte(MPU6050_Address|0x01);	//换成读
	data=MyI2C_RecieveByte();
	MyI2C_SendAck(1);						//不传输数据了,将总线控制权交给主机
	MyI2C_Stop();
	
	return data;
}

void MPU6050_Init(void)
{
	MyI2C_Init();

    MPU6050_WriteReg(MPU6050_PWR_MGMT_1,0x01);  //解除睡眠  内部晶振000,陀螺仪001
	MPU6050_WriteReg(MPU6050_PWR_MGMT_2,0X00);	//均不待机
	MPU6050_WriteReg(MPU6050_SMPLRT_DIV,0x09);  //十分频
	MPU6050_WriteReg(MPU6050_CONFIG,0x06);   	//110最平滑的滤波
	MPU6050_WriteReg(MPU6050_GYRO_CONFIG,0x18); //最大量程.16g
	MPU6050_WriteReg(MPU6050_ACCEL_CONFIG,0x18); 

}

//一定要注意这里的符号
void MPU6050_GetData(int16_t *AccX,int16_t *AccY, int16_t *AccZ,
	int16_t *GyroX,int16_t *GyroY, int16_t *GyroZ)
{
	uint8_t datah,datal;
	datah=MPU6050_ReadReg(MPU6050_ACCEL_XOUT_H);
	datal=MPU6050_ReadReg(MPU6050_ACCEL_XOUT_L);
	*AccX = (datah<<8) | datal;			//16位无符号补码
	
	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;

}

uint8_t MPU6050_Get_ID(void)
{
	return MPU6050_ReadReg(MPU6050_WHO_AM_I);
}

主函数

    int16_t AX,AY,AZ,GX,GY,GZ;

    MPU6050_Init();
	ID=MPU6050_Get_ID();
	OLED_ShowHexNum(4,1,ID,2);

	while(1)
	{
		MPU6050_GetData(&AX,&AY,&AZ,&GX,&GY,&GZ);	//要放在while循环里,要不然数据不会变化
		
		OLED_ShowSignedNum(1,1,AX,5);
		OLED_ShowSignedNum(2,1,AY,5);
		OLED_ShowSignedNum(3,1,AZ,5);  //2070/32768=x/16  x=1.010g
		
		OLED_ShowSignedNum(1,8,GX,5);
		OLED_ShowSignedNum(2,8,GY,5);
		OLED_ShowSignedNum(3,8,GZ,5);
	}

硬件I2C读写MPU6050

硬件读写不需要手动翻转电平。不需要上面的MyI2C.c和MyI2C.h文件,修改MPU6050读寄存器和写寄存器代码(根据上一篇的主机发送和主机接收来配置每一步)

void MPU6050_WaitEvent(I2C_TypeDef* I2Cx, uint32_t I2C_EVENT)
{
	uint32_t Timeout=1000;
	while(I2C_CheckEvent(I2Cx,I2C_EVENT) != SUCCESS)
	{
		Timeout--;
		if(Timeout == 0)
		{
			break;
		}
	}
}

void MPU6050_WriteReg(uint8_t RegAddress,uint8_t data)
{
	
	//软件函数内部有DELAY,运行完后对应的波形发送完毕可紧跟下一个函数
	//这些函数非阻塞型,调用后需要等待相应标志位确保函数操作执行到位
	I2C_GenerateSTART(I2C2,ENABLE);								
	MPU6050_WaitEvent(I2C2,I2C_EVENT_MASTER_MODE_SELECT);	//STM32默认为从机,发送起始条件后变为主机

	I2C_Send7bitAddress(I2C2,MPU6050_Address,I2C_Direction_Transmitter);
	MPU6050_WaitEvent(I2C2,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED);
	
	I2C_SendData(I2C2,RegAddress);	//第一个数据写入DR会立即进入移位寄存器,第二个数据不用等
	MPU6050_WaitEvent(I2C2,I2C_EVENT_MASTER_BYTE_TRANSMITTING);
	
	I2C_SendData(I2C2,data);        //发多个字节时,中间的字节写入DR需要等待event8,最后一个要等待event8_2
	MPU6050_WaitEvent(I2C2,I2C_EVENT_MASTER_BYTE_TRANSMITTED);
	
	I2C_GenerateSTOP(I2C2,ENABLE);
}
uint8_t MPU6050_ReadReg(uint8_t RegAddress)
{
	uint8_t data;
	
	I2C_GenerateSTART(I2C2,ENABLE);								
	MPU6050_WaitEvent(I2C2,I2C_EVENT_MASTER_MODE_SELECT);	

	I2C_Send7bitAddress(I2C2,MPU6050_Address,I2C_Direction_Transmitter);
	MPU6050_WaitEvent(I2C2,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED);
	
	I2C_SendData(I2C2,RegAddress);			
	MPU6050_WaitEvent(I2C2,I2C_EVENT_MASTER_BYTE_TRANSMITTED);   //可以改成tansmitted
	
	
	//这里按照图246从头开始配置
	I2C_GenerateSTART(I2C2,ENABLE);								
	MPU6050_WaitEvent(I2C2,I2C_EVENT_MASTER_MODE_SELECT);	
	
	I2C_Send7bitAddress(I2C2,MPU6050_Address,I2C_Direction_Receiver);	//读
	MPU6050_WaitEvent(I2C2,I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED);
	
	//读取多字节时,等待eve7读取DR,最后一个字节前eve7_1。
	//读取一个字节时,发生event6_1 :恰好在eve6之后,要ack=0,stop=1。所以要现在配置
	I2C_AcknowledgeConfig(I2C2,DISABLE);
	I2C_GenerateSTOP(I2C2,ENABLE);

	MPU6050_WaitEvent(I2C2,I2C_EVENT_MASTER_BYTE_RECEIVED);  //RXNE=1,可以读取数据 
	data=I2C_ReceiveData(I2C2);
	
	I2C_AcknowledgeConfig(I2C2,ENABLE);  		//为了方便多字节

	
	return data;
}

猜你喜欢

转载自blog.csdn.net/m0_70732442/article/details/130950515