10-2软件I2C读写MPU6050

MPU6050简介

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

MPU6050参数

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

硬件电路

硬件电路

引脚功能
VCC、GND电源
SCL、SDAI2C通信引脚
XCL、XDA主机I2C通信引脚
AD0从机地址最低位
INT中断信号输出

MPU6050框图

MPU6050框图

软件I2C读写MPU6050

MyI2C.c

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
#include "stm32f10x.h"                  // Device header#include "Delay.h" void MyI2C_W_SCL(uint8_t BitValue)//调用此函数,参数给1或者0,可以释放或拉低SCL{	GPIO_WriteBit(GPIOB,GPIO_Pin_10,(BitAction)BitValue);	Delay_us(10);//延时一段时间,避免CPU主频太快,从设备跟不上} void MyI2C_W_SDA(uint8_t BitValue)//调用此函数,参数给1或者0,可以释放或拉低SDA{	GPIO_WriteBit(GPIOB,GPIO_Pin_11,(BitAction)BitValue);	Delay_us(10);//延时一段时间,避免CPU主频太快,从设备跟不上} uint8_t MyI2C_R_SDA(void)//读SDA{	uint8_t BitValue;	BitValue = GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_11);	Delay_us(10);//延时一段时间,避免CPU主频太快,从设备跟不上	return BitValue;} void MyI2C_Init(void){	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);//把PB10和11都置为高电平	} void MyI2C_Start(void)//I2C起始{	MyI2C_W_SDA(1);//先把SCL和SDA都释放,先释放SDA,再释放SCL,这个顺序是为了兼容重复起始	MyI2C_W_SCL(1);	MyI2C_W_SDA(0);//起始条件:先拉低SDA,再拉低SCL	MyI2C_W_SCL(0);} void MyI2C_Stop(void)//I2C停止{	MyI2C_W_SDA(0);//终止条件:先拉低SDA,再释放SCL,再释放SDA	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));//取出每一位,SDA根据传入的Byte修改电平		MyI2C_W_SCL(1);//释放SCL		MyI2C_W_SCL(0);//拉低SCL	}} uint8_t MyI2C_ReceiveByte(void){	uint8_t i, Byte = 0x00;//先定义一个接收字节	MyI2C_W_SDA(1);//释放SDA	for(i = 0; i < 8; i++)	{		MyI2C_W_SCL(1);//释放SCL		if(MyI2C_R_SDA() == 1)		{			Byte |= (0x80>>i);		}		MyI2C_W_SCL(0);//拉低SCL	}	return Byte;} void MyI2C_SendAck(uint8_t AckBit){	MyI2C_W_SDA(AckBit);	MyI2C_W_SCL(1);	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);//拉低SCL	return AckBit;} 

MPU6050.c

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677
#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();//I2C启动	MyI2C_SendByte(MPU6050_ADDRESS);//发送MPU6050的地址	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();//I2C启动	MyI2C_SendByte(MPU6050_ADDRESS);//发送MPU6050的地址	MyI2C_ReceiveAck();//接收应答,下面还可以判断,此处省略	MyI2C_SendByte(RegAddress);//发送要读的地址	MyI2C_ReceiveAck();//接收应答,下面还可以判断,此处省略 	MyI2C_Start();//重复启动	MyI2C_SendByte(MPU6050_ADDRESS | 0x01);//发送MPU6050的地址和读写位	MyI2C_ReceiveAck();//接收应答,下面还可以判断,此处省略	Data = MyI2C_ReceiveByte();//接收字节	MyI2C_SendAck(1);	MyI2C_Stop();//停止 	return Data;} void MPU6050_Init(void){	MyI2C_Init();	MPU6050_WriteReg(MPU6050_PWR_MGMT_1,0x01);	MPU6050_WriteReg(MPU6050_PWR_MGMT_2,0x00);	MPU6050_WriteReg(MPU6050_SMPLRT_DIV,0x09);	MPU6050_WriteReg(MPU6050_CONFIG,0x06);	MPU6050_WriteReg(MPU6050_GYRO_CONFIG,0x18);	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; 	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;} 

main.c

1234567891011121314151617181920212223242526272829
#include "stm32f10x.h"                  // Device header#include "Delay.h"#include "OLED.h"#include "MPU6050.h" int16_t AX,AY,AZ,GX,GY,GZ; int main(void){	OLED_Init();	MPU6050_Init();	//MPU6050_WriteReg(0x6B,0x00);//取消睡眠模式	//MPU6050_WriteReg(0x19,0x66);//采样模式修改	//uint8_t ID = MPU6050_ReadReg(0x19); 	//OLED_ShowHexNum(1,1,ID,2); 	while(1)	{		MPU6050_GetData(&AX,&AY,&AZ,&GX,&GY,&GZ);		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);	}                      } 
🔍 ×