硬件I2C读写MPU6050

一.硬件I2C基本信息

stm32内部集成了硬件I2C收发电路,可以由硬件自动执行时钟生成、起始终止条件生成、应答位收发、数据收发等功能
控制寄存器CR 数据寄存器DR 状态寄存器SR

硬件I2C流程与软件基本一致

二.硬件I2C基本流程

1.指定地址写

I2C_GenerateSTART();生成开始事件
I2C_CheckEvent();检查EV5事件是否发生
I2C_Send7bitAddress();发送7位从机地址以及1位读写位,(Transmitter)就是发送也就是最低位置0, (Receive)就是接收最低位置1
(注:发送应答和接收应答不需要处理,因为接收数据和发送数据都自带应答功能,如果应答错误,硬件就会通过标志位和中断提示我们)
I2C_CheckEvent();检查EV6事件
进入EV8_1事件,不需要等待,数据通过DR寄存器,直接发送数据,.I2C_SendData();
I2C_CheckEcent();检查EV8事件(字节正在发送)
然后进入下一个数据发送I2C_SendData();
之后I2C_Check();检查EV8_2事件(字节发送完毕)
之后终止时序I2C_GenerateStop();

2.指定地址读

I2C_GenerateSTART();生成开始事件
I2C_CheckEvent();检查EV5事件是否发生
I2C_Send7bitAddress();发送7位从机地址以及1位读写位,(Transmitter)就是发送也就是最低位置0, (Receive)就是接收最低位置1
I2C_CheckEvent();检查EV6事件
进入EV8_1事件,不需要等待,数据通过DR寄存器,直接发送数据,.I2C_SendData();
I2C_CheckEcent();检查EV8事件(字节发送完成)
I2C_GenerateSTART();再次生成开始事件
I2C_CheckEvent();再次检查EV5事件是否发生
I2C_Send7bitAddress();这次接收数据(Recrive)
I2C_CheckEvent();再次检查EV6事件
进入EV6_1事件提前给应答位和停止位,非应答和停止.(注:这里应答与软件相反,不应答(0)应答(1))
进入EV7事件等待数据发送I2C_CheckEvent();
I2C_ReceiveData();读取数据
恢复Ack应答给应答默认Ack=1

三.代码实现

main.c

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

int8_t AX,AY,AZ,GX,GY,GZ;
uint8_t ID;

int main(void)
{
	OLED_Init (); 
	MPU6050_Init();
	
	//显示MPU6050_GetID里面从机寄存器数据
    OLED_ShowString(4,1,"ID:");
	ID = MPU6050_GetID();
	OLED_ShowHexNum (4,4,ID,2);
	
	
	while(1)
	{
		//显示加速度XYZ轴,陀螺仪XYZ轴寄存器数据
        MPU6050_GetData(&AX,&AY,&AZ,&GX,&GY,&GZ);
		OLED_ShowSignedNum (1,1,AX,5);
		OLED_ShowSignedNum (2,1,AY,5);
		OLED_ShowSignedNum (3,1,AZ,5);
		OLED_ShowSignedNum (1,8,GX,5);
		OLED_ShowSignedNum (2,8,GY,5);
		OLED_ShowSignedNum (3,8,GZ,5);
    }
}

MPU6050.c

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

//宏定义从机地址
#define MPU6050_ADDRESS 0xD0 //宏定义从机MPU6050地址

//封装等待事件
void MPU6050_WriteEvent(I2C_TypeDef* I2Cx, uint32_t I2C_EVENT)
{
	uint32_t Timerout;
	Timerout = 10000;//定义一个时间结束的变量
	while(I2C_CheckEvent(I2Cx,I2C_EVENT) != SUCCESS )
	{
		Timerout--;//时间自减,等待事件
		if(Timerout == 0)
		{
			break;//当时间走完直接结束事件,不等了
		}
	}
}

//指定地址写
void MPU6050_WriteReg(uint8_t RegAddress,uint8_t Data)
{
    I2C_GenerateSTART(I2C2,ENABLE);//开启I2C
	MPU6050_WriteEvent(I2C2,I2C_EVENT_MASTER_MODE_SELECT);//等待EV5事件完成
	
	I2C_Send7bitAddress(I2C2,MPU6050_ADDRESS,I2C_Direction_Transmitter);//选择从机发送模式
	MPU6050_WriteEvent(I2C2,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED);//等待EV6事件完成(发送)
	
	I2C_SendData (I2C2,RegAddress);//发送寄存器地址
    MPU6050_WriteEvent(I2C2,I2C_EVENT_MASTER_BYTE_TRANSMITTING);//等待EV8事件完成(寄存地址输送)

    I2C_SendData (I2C2,Data);//发送硬件数据
    MPU6050_WriteEvent (I2C2,I2C_EVENT_MASTER_BYTE_TRANSMITTED);//等待EV8_2事件完成(数据传输完成)

	I2C_GenerateSTOP(I2C2,ENABLE);//停止I2C
}

//指定地址读
uint8_t MPU6050_ReadReg(uint8_t RegAddress)
{
	uint8_t Data;//接收数据
    
	I2C_GenerateSTART(I2C2,ENABLE);//开启I2C
	MPU6050_WriteEvent(I2C2,I2C_EVENT_MASTER_MODE_SELECT);//等待EV5事件完成
	
	I2C_Send7bitAddress(I2C2,MPU6050_ADDRESS,I2C_Direction_Transmitter);//选择从机发送模式
	MPU6050_WriteEvent(I2C2,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED);//等待EV6事件完成(发送)
	
	I2C_SendData (I2C2,RegAddress);//发送寄存器地址
    MPU6050_WriteEvent(I2C2,I2C_EVENT_MASTER_BYTE_TRANSMITTED);//等待EV8_2事件完成(寄存地址输送)
	
	I2C_GenerateSTART(I2C2,ENABLE);//开启I2C
	MPU6050_WriteEvent(I2C2,I2C_EVENT_MASTER_MODE_SELECT);//等待EV5事件完成
	
	I2C_Send7bitAddress(I2C2,MPU6050_ADDRESS,I2C_Direction_Receiver);//选择从机接收模式
	MPU6050_WriteEvent(I2C2,I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED);//等待EV6事件完成(接收)
		
	I2C_AcknowledgeConfig(I2C2,DISABLE);//在数据传输之前提前应答(选择不应答)
	I2C_GenerateSTOP(I2C2,ENABLE );//因为数据发送过快提前停止
	
	MPU6050_WriteEvent(I2C2,I2C_EVENT_MASTER_BYTE_RECEIVED);//等待EV7事件完成(数据接收)
	Data = I2C_ReceiveData (I2C2);//将接收的数据传给Data
	
	I2C_AcknowledgeConfig(I2C2,ENABLE);//再次开启应答
	
    return Data;
}

//定义MPU6050函数
void MPU6050_Init(void)
{
	
	//开启时钟
	RCC_APB1PeriphClockCmd (RCC_APB1Periph_I2C2,ENABLE);//开启I2C时钟
	RCC_APB2PeriphClockCmd (RCC_APB2Periph_GPIOB,ENABLE);//开启GPIOB时钟
	
	//初始化GPIO
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD ;//复用推挽输出
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11;//引脚PB10PB11
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz ;//速度50
	GPIO_Init(GPIOB,&GPIO_InitStructure);
	
	//初始化I2C
	I2C_InitTypeDef I2C_InitStructure;
	I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;//应答默认应答
	I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;//选择7位从机地址
	I2C_InitStructure.I2C_ClockSpeed = 50000;//时钟速度这里我给的50000KHz
	I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;//占空比我给的2:1
	I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;//I2C模式
	I2C_InitStructure.I2C_OwnAddress1 = 0x00;//自身地址从机地址才有效
	I2C_Init(I2C2,&I2C_InitStructure);
	
	//打开或关闭开关
	I2C_Cmd (I2C2,ENABLE);
	
	//初始化从机写入寄存器地址,需要的时候直接主函数调用读取寄存器地址就可以获取寄存器地址下的数据
	MPU6050_WriteReg(MPU6050_PWR_MGMT_1,0x01);//电源管理寄存器1:关闭0x0关闭睡眠模式,1陀螺仪时钟
	MPU6050_WriteReg(MPU6050_PWR_MGMT_2,0x00);//电源管理寄存器2:不待机
	MPU6050_WriteReg(MPU6050_SMPLRT_DIV,0x09);//采样分频寄存器:0x00-0x09,控制传输速度,越大约快
	MPU6050_WriteReg(MPU6050_CONFIG,0x06);//配置寄存器:给0x06是最平滑的滤波
	MPU6050_WriteReg(MPU6050_GYRO_CONFIG,0x18);//陀螺仪配置寄存器:0x18是满量程
	MPU6050_WriteReg(MPU6050_ACCEL_CONFIG,0x18);//加速度配置寄存器:0x18满量程
}

//获取MPU6050_WHO_AM_I寄存器数据
uint8_t MPU6050_GetID(void)
{
	return MPU6050_ReadReg (MPU6050_WHO_AM_I);//MPU6050_WHO_AM_I:从机寄存器编号
}

//获取加速度、陀螺仪角速度寄存器中数据
void MPU6050_GetData(int8_t *AccrX,int8_t *AccrY,int8_t *AccrZ,
                     int8_t *GyroX,int8_t *GyroY,int8_t *GyroZ)
{
	uint8_t DataH,DataL;//定义一个接收高8位和低8位数据的变量
	
	//加速度X轴
	DataH = MPU6050_ReadReg(MPU6050_ACCEL_XOUT_H);
	DataL = MPU6050_ReadReg(MPU6050_ACCEL_XOUT_L);
	*AccrX = (DataH << 8) | DataL;//将高低电平传给取地址*AccrX
	//加速度Y轴
	DataH = MPU6050_ReadReg(MPU6050_ACCEL_YOUT_H);
	DataL = MPU6050_ReadReg(MPU6050_ACCEL_YOUT_L);
	*AccrY = (DataH << 8) | DataL;//将高低电平传给取地址*AccrY
	//加速度Z轴
	DataH = MPU6050_ReadReg(MPU6050_ACCEL_YOUT_H);
	DataL = MPU6050_ReadReg(MPU6050_ACCEL_YOUT_L);
	*AccrZ = (DataH << 8) | DataL;//将高低电平传给取地址*AccrY
	//陀螺仪X轴
	DataH = MPU6050_ReadReg(MPU6050_GYRO_XOUT_H);
	DataL = MPU6050_ReadReg(MPU6050_GYRO_XOUT_L);
	*GyroX = (DataH << 8) | DataL;//将高低电平传给取地址*GyroX
	//陀螺仪Y轴
	DataH = MPU6050_ReadReg(MPU6050_GYRO_YOUT_H);
	DataL = MPU6050_ReadReg(MPU6050_GYRO_YOUT_L);
	*GyroY = (DataH << 8) | DataL;//将高低电平传给取地址*GyroY
	//陀螺仪Z轴
	DataH = MPU6050_ReadReg(MPU6050_GYRO_ZOUT_H);
	DataL = MPU6050_ReadReg(MPU6050_GYRO_ZOUT_L);
	*GyroZ = (DataH << 8) | DataL;//将高低电平传给取地址*GyroY
}

MPU6050.h

#ifndef _MPU6050_H
#define _MPU6050_H


void MPU6050_WriteReg(uint8_t RegAddress,uint8_t Data);
uint8_t MPU6050_ReadReg(uint8_t RegAddress);
void MPU6050_Init(void);
uint8_t MPU6050_GetID(void);
void MPU6050_GetData(int8_t *AccrX,int8_t *AccrY,int8_t *AccrZ,
                     int8_t *GyroX,int8_t *GyroY,int8_t *GyroZ);

#endif

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       //加速度X轴高8位
#define	MPU6050_ACCEL_XOUT_L	0x3C       //加速度X轴低8位
#define	MPU6050_ACCEL_YOUT_H	0x3D       //加速度Y轴高8位
#define	MPU6050_ACCEL_YOUT_L	0x3E       //加速度Y轴低8位
#define	MPU6050_ACCEL_ZOUT_H	0x3F       //加速度Z轴高8位
#define	MPU6050_ACCEL_ZOUT_L	0x40       //加速度Z轴低8位
#define	MPU6050_TEMP_OUT_H		0x41       
#define	MPU6050_TEMP_OUT_L		0x42       
#define	MPU6050_GYRO_XOUT_H		0x43       //陀螺仪X轴高8位
#define	MPU6050_GYRO_XOUT_L		0x44       //陀螺仪X轴低8位
#define	MPU6050_GYRO_YOUT_H		0x45       //陀螺仪Y轴高8位
#define	MPU6050_GYRO_YOUT_L		0x46       //陀螺仪Y轴低8位
#define	MPU6050_GYRO_ZOUT_H		0x47       //陀螺仪Z轴高8位
#define	MPU6050_GYRO_ZOUT_L		0x48       //陀螺仪Z轴低8位
                                           
#define	MPU6050_PWR_MGMT_1		0x6B       //电源配置寄存器2
#define	MPU6050_PWR_MGMT_2		0x6C       //电源配置寄存器1
#define	MPU6050_WHO_AM_I		0x75       //从机地址编号

#endif


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值