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、SDA | I2C通信引脚 |
| XCL、XDA | 主机I2C通信引脚 |
| AD0 | 从机地址最低位 |
| INT | 中断信号输出 |
MPU6050框图

软件I2C读写MPU6050
MyI2C.c
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495 | 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 | 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 | 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); } } |