软件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;
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
江科大自化协软件模拟I2CMPU6050的过程可以分为两个主要步骤。首先,需要学习I2C协议规则,并使用软件模拟的方式实现协议。这包括了了解I2C协议的引脚配置、时序要求等相关内容。其次,需要学习STM32的I2C外设,并使用硬件实现协议。这一步骤可以进一步学习STM32的I2C外设和协议的硬件实现方式。\[1\]\[2\] 在软件模拟I2CMPU6050的过程中,可以采用多层的模块架构。最底层是I2C协议层,主要关注引脚配置、时序要求等与协议相关的内容。其次是MPU6050的驱动层,主要关注如何寄存器、配置寄存器以及取数据等与驱动相关的内容。最后是主函数应用层,通过调用MPU6050的驱动函数获取数据,并根据需要进行进一步的功能设计。\[3\] 因此,江科大自化协软件模拟I2CMPU6050的过程包括学习I2C协议规则、软件模拟实现协议,以及学习STM32的I2C外设并使用硬件实现协议。在软件模拟过程中,需要关注引脚配置、时序要求等与协议相关的内容。在硬件实现过程中,需要学习STM32的I2C外设和协议的硬件实现方式。最后,通过多层的模块架构,实现对MPU6050的操作,并根据需要进行进一步的功能设计。 #### 引用[.reference_title] - *1* *2* *3* [【STM32学习】&mdash;&mdash;I2C通信协议&amp;MPU6050姿态传感器&amp;软件I2CMPU6050](https://blog.csdn.net/weixin_51658186/article/details/129821841)[target=&quot;_blank&quot; data-report-click={&quot;spm&quot;:&quot;1018.2226.3001.9630&quot;,&quot;extra&quot;:{&quot;utm_source&quot;:&quot;vip_chatgpt_common_search_pc_result&quot;,&quot;utm_medium&quot;:&quot;distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt&quot;}} ] [.reference_item] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值