21:I2C三:MPU6050的使用
MPU6050的使用
- 1、MPU6050简介
- 1.1:加速度与姿态测量
- 1.2:陀螺仪与姿态测量
- 1.3:MPU6050内部结构
- 1.4:模块内部寄存器
- 2、程序模拟I2C读写MPU6050
- 2.1:数据的读取
- 2.2:转换为角度并进行融合
- 3、片上外设I2C2读写MPU6050
1、MPU6050简介
MPU6050是一个6轴姿态传感器,可以测量芯片自身X、Y、Z轴的加速度、角速度参数,通过数据融合,可进一步得到姿态角,常应用于平衡车、飞行器等需要检测自身姿态的场景。
1.1:加速度与姿态测量
主要是基于重力加速度g,进行测量X、Y、Z轴的的受力点的加速度。如下图所示:芯片的内部在X、Y、Z轴各有一个测力计。
如图:芯片内部就像是一个弹簧测力计。当芯片静止/匀速运动的时候,芯片内部的那个小滑块受重力G和弹簧的支撑力F1(Z轴方向G=F1),弹簧被压缩,而受力点5只受弹簧压缩的力F2,而此力方向向下,和滑块的重力相等F2 = G。而弹簧压缩就驱动电位器改变电阻大小,然后输出电压。而通过数模转换器将电压的大小代表受力点的受力大小F2。而F2/滑块的质量m = g(重力加速度)。所以得出了一个竖直向下的重力加速度g。
如上图所示:如果模块如图倾斜α角度倾斜(绕x轴旋转,其角度为翻滚角roll),那么受力点5和受力点3均受力,而受到的力为滑块的重力的分力。分力F1和F2除以滑块的质量那就得出了各个方向的加速度。那么怎么求出角度α喃?如上图所示:tanα = g2 / g1。那么α = arctan(g2/g1)。由此可得,我们可以判断那个受力点受力,进而判断是往那边倾斜,而通过计数出α的值,进而判断倾斜了多少度。进而得到了模块的姿态。
【注】①这种方法只能是模块静止或者匀速运动的时候才能使用,而当物体外部收到其他的作用力时,这个方法就会存在很大的误差。②如果物体绕z轴旋转产生的角度即偏航角yaw是没法用这个方法测量出来的。
1.2:陀螺仪与姿态测量
为了避免上面那种方法的误差,所以人们发明了陀螺仪与姿态测量,通过测量X、Y、Z轴的角速度。
综上:
所以通过2种方法测到的结果进行数据的融合,进而得到更准确的结果。
1.3:MPU6050内部结构
如图所示:这个模块里面里面有加速度计、陀螺仪计,温度计(一般不用)。我们只需要通过I2C协议去读取gx,gy,gz(受力点的加速度),ax,ay,az(旋转方向的角速度)这些数据,然后在通过计数和数据融合,进而得到模块的姿态。
1.4:模块内部寄存器
模块的不同的寄存器有不同的地址值,且不同的寄存器功能不一样,我们通过I2C总线对模块内部的寄存器进行读/写,进而得到我们需要的数据。
下图为我们需要使用到的寄存器:
采样频率分频寄存器:不使用低通滤波器时采样频率 = 8KHz / (1+x),使用低通滤波器时采样频率 = 1KHz / (1+x),而这个x就是我们写入寄存器的数据。
配置寄存器:主要是后面的低通滤波器的设置。
陀螺仪配置寄存器:设置测量角速度的量程
加速度配置寄存器:设置测量加速度g的量程
电池管理寄存器1:用于复位和唤醒
2、程序模拟I2C读写MPU6050
2.1:数据的读取
①I2C.c文件使用程序模拟I2C时序程序如下:
#include "stm32f10x.h"
#include "Delay.h" //#define SCL(x) GPIO_WriteBit(GPIOB,GPIO_Pin_10,(BitAction)(x))
//#define SDA(x) GPIO_WriteBit(GPIOB,GPIO_Pin_11,(BitAction)(x))void I2C_W_SCL(uint8_t BitValue)//拉低SCL/释放SCL(拉高)
{GPIO_WriteBit(GPIOB,GPIO_Pin_10,(BitAction)BitValue);Delay_us(10);
}void I2C_W_SDA(uint8_t BitValue)//给SDA写数据(拉低SDA/释放SDA(拉高))
{GPIO_WriteBit(GPIOB,GPIO_Pin_11,(BitAction)BitValue);Delay_us(10);
}uint8_t I2C_R_SDA(void)//主机读SDA数据,即判断引脚的电平
{uint8_t BitValue;BitValue = GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_11);Delay_us(10);return BitValue;
}void MyI2C_Init(void)
{//1. 使能挂载在APB2总线上面的片上外设时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);//2. 对GPIO_PA10/PA11进行配置GPIO_InitTypeDef GPIOInitStruct;GPIOInitStruct.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11;GPIOInitStruct.GPIO_Mode = GPIO_Mode_Out_OD;//输出开漏模式,0才有驱动能力,开漏模式没有输出低电平时,也可以作为输入GPIOInitStruct.GPIO_Speed = GPIO_Speed_50MHz;//最大输出速度GPIO_Init(GPIOB,&GPIOInitStruct);GPIO_SetBits(GPIOB,GPIO_Pin_10 | GPIO_Pin_11);//先给输出高电平,释放总线//PB10连接SCL。PB11连接SDA
}void MyI2C_Start(void)//起始信号
{I2C_W_SDA(1);//释放SDAI2C_W_SCL(1);//释放SCLI2C_W_SDA(0);//拉低SDAI2C_W_SCL(0);//拉低SDA
}void MyI2C_Stop(void)
{I2C_W_SCL(0);I2C_W_SDA(0);I2C_W_SCL(1);I2C_W_SDA(1);
}void MyI2C_SendByte(uint8_t Byte)//主机向从机发送一个字节,高位先行
{for(uint8_t i = 0;i<8;i++){I2C_W_SDA(Byte & (0x80 >> i));//给SDA写入数据,只要Byte不是0,那么写入的就是1。因为BitActionI2C_W_SCL(1);//释放SCL,从机读取数据I2C_W_SCL(0);//拉低SCL,主机准备给SDA写入字节的次高位数据}
}uint8_t MyI2C_ReceiveByte(void)
{uint8_t Byte = 0x00;//接收数据的变量I2C_W_SDA(1);//主机释放SDA,让控制权给从机for(uint8_t i =0; i<8;i++){I2C_W_SCL(1);//主机释放SCL,准备开始读取SDA上面的数据if(I2C_R_SDA() == 1){Byte |= (0x80 >> i);} I2C_W_SCL(0);//主机拉低SCL,让从机给SDA写入数据 }return Byte;
}void MyI2C_SendACK(uint8_t ACKBit)//主机发送应答
{
/*从机发送完一个字节后,SCL为低电平,等待主机给SDA上面写数据,如果拉低代表接收成功。
*/I2C_W_SDA(ACKBit);I2C_W_SCL(1);I2C_W_SCL(0);
}uint8_t MyI2C_ReceiveACK(void)//主机接收应答
{
/*主机发送完一个字节后,SCL为低电平,等待从机给SDA上面写入数据,如果拉低则代表接收成功
*/uint8_t ACKBit;I2C_W_SDA(1);//主机释放SDA,让控制权给从机I2C_W_SCL(1);//主机释放SCL,准备开始读取SDA上面的数据ACKBit = I2C_R_SDA();I2C_W_SCL(0);//主机拉低SCL,进入下一个时序单元,主机准备给SDA写入字节的数据return ACKBit;
}
②MPU6050Reg.h的代码如下:
/*将需要使用到的寄存器地址通过寄存器名宏定义
*/
#ifndef __MPU6050_H
#define __MPU6050_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
#define MPU6050_ACCEL_XOUT_L 0x3C
#define MPU6050_ACCEL_YOUT_H 0x3D
#define MPU6050_ACCEL_YOUT_L 0x3E
#define MPU6050_ACCEL_ZOUT_H 0x3F
#define MPU6050_ACCEL_ZOUT_L 0x40
#define MPU6050_TEMP_OUT_H 0x41
#define MPU6050_TEMP_OUT_L 0x42
#define MPU6050_GYRO_XOUT_H 0x43
#define MPU6050_GYRO_XOUT_L 0x44
#define MPU6050_GYRO_YOUT_H 0x45
#define MPU6050_GYRO_YOUT_L 0x46
#define MPU6050_GYRO_ZOUT_H 0x47
#define MPU6050_GYRO_ZOUT_L 0x48#define MPU6050_PWR_MGMT_1 0x6B
#define MPU6050_PWR_MGMT_2 0x6C
#define MPU6050_WHO_AM_I 0x75#endif
③MPU6050.c文件的代码如下:
#include "stm32f10x.h" // Device header
#include "MyI2C.h"
#include "MPU6050reg.h"#define MPU6050_Address 0xD0//从机地址/*给MPU6050的寄存器写入一个字节数据
*/
void MPU6050_WriteReg(uint8_t Address,uint8_t Data)//寄存器地址,需要发送的数据
{MyI2C_Start();MyI2C_SendByte(MPU6050_Address);//从机地址 + 0,代表写入数据MyI2C_ReceiveACK();//接收应答,先不处理MyI2C_SendByte(Address);//发送MPU6050寄存器的地址MyI2C_ReceiveACK();//接收应答,先不处理MyI2C_SendByte(Data);MyI2C_ReceiveACK();//接收应答,先不处理MyI2C_Stop();
}/*读取MPU6050的寄存器里面的一个字节数据
*/
uint8_t MPU6050_ReadReg(uint8_t Address)
{uint8_t Data;MyI2C_Start();MyI2C_SendByte(MPU6050_Address);//从机地址MyI2C_ReceiveACK();//接收应答,先不处理MyI2C_SendByte(Address);//发送MPU6050寄存器的地址MyI2C_ReceiveACK();//接收应答,先不处理MyI2C_Start();MyI2C_SendByte(MPU6050_Address | 0x01);//从机地址,从机地址 + 1,代表读取数据MyI2C_ReceiveACK();//接收应答,先不处理Data = MyI2C_ReceiveByte();//接收数据MyI2C_SendACK(1);MyI2C_Stop();return Data;
}/*给MPU6050初始化配置
*/
void MPU6050_Init(void)/**/
{MyI2C_Init();MPU6050_WriteReg(MPU6050_PWR_MGMT_1,0x00);//给电源管理寄存器1发送0x00,解除睡眠模式MPU6050_WriteReg(MPU6050_PWR_MGMT_2,0x00);//配置电源管理寄存器2MPU6050_WriteReg(MPU6050_SMPLRT_DIV,0x09);//采样率分频10分频MPU6050_WriteReg(MPU6050_CONFIG,0x06);//数字低通滤波MPU6050_WriteReg(MPU6050_GYRO_CONFIG,0x18);//角速度的量程,满量程MPU6050_WriteReg(MPU6050_ACCEL_CONFIG,0x18);//加速度g的量程,满量程
}/*获取数据寄存器里面的数据ACC代表加速度g的值Gyrox代表角数据的值
*/
void MPU6050_GetData(int16_t *ACCx,int16_t *ACCy,int16_t *ACCz,int16_t *Gyrox,int16_t *Gyroy,int16_t *Gyroz)//读取寄存器里面的数据
{uint16_t DataH , DataL;DataH = MPU6050_ReadReg(MPU6050_ACCEL_XOUT_H);//读取x轴加速度计的高8位DataL = MPU6050_ReadReg(MPU6050_ACCEL_XOUT_L);//读取x轴加速度计的第8位*ACCx = (DataH << 8) | DataL;DataH = MPU6050_ReadReg(MPU6050_ACCEL_YOUT_H);//读取Y轴加速度计的高8位DataL = MPU6050_ReadReg(MPU6050_ACCEL_YOUT_L);*ACCy = (DataH << 8) | DataL;DataH = MPU6050_ReadReg(MPU6050_ACCEL_ZOUT_H);//读取Z轴加速度计的高8位DataL = MPU6050_ReadReg(MPU6050_ACCEL_ZOUT_L);*ACCz = (DataH << 8) | DataL;DataH = MPU6050_ReadReg(MPU6050_GYRO_XOUT_H);//读取x轴陀螺仪的高8位DataL = MPU6050_ReadReg(MPU6050_GYRO_XOUT_L);*Gyrox = (DataH << 8) | DataL;DataH = MPU6050_ReadReg(MPU6050_GYRO_YOUT_H);//读取y轴陀螺仪的高8位DataL = MPU6050_ReadReg(MPU6050_GYRO_YOUT_H);*Gyroy = (DataH << 8) | DataL;DataH = MPU6050_ReadReg(MPU6050_GYRO_ZOUT_H);//读取z轴陀螺仪的高8位DataL = MPU6050_ReadReg(MPU6050_GYRO_ZOUT_H);*Gyroz = (DataH << 8) | DataL;
}
④主函数main.c的代码如下:
/*软件模拟I2C控制MPU6050
*/#include "stm32f10x.h"
#include "OLED.h"
#include "MPU6050.h"int main(void)
{OLED_Init();OLED_Clear();int16_t AX,AY,AZ,GX,GY,GZ; MPU6050_Init();while(1){MPU6050_GetData(&AX,&AY,&AZ,&GX,&GY,&GZ);OLED_ShowSignedNum(2,1,AX,5);//显示X轴的加速度g的大小OLED_ShowSignedNum(3,1,AY,5);//显示Y轴的加速度g的大小OLED_ShowSignedNum(4,1,AZ,5);//显示Z轴的加速度g的大小OLED_ShowSignedNum(2,8,GX,5);//显示X轴的角速度a的大小OLED_ShowSignedNum(3,8,GY,5);//显示Y轴的角速度a的大小OLED_ShowSignedNum(4,8,GZ,5);//显示Z轴的角速度a的大小}
}
下图为显示结果:
如上图所示:模块静止平放在桌面上面,z轴的加速度值为+1823,那么可以判断z轴的方向为垂直芯片向里。+1823换算为加速度g:(+1823)/(+2^15) = x/(+16g),那么算出x = +0.89g。
如上图所示:模块如图所放置,可见gx和gz都约为0,而gy = +2038。那么可以判断出Y轴的方向是横向向左。
如上图所示:模块如图所放置,可见gy和gz都约为0,而gx = -1962。那么可以判断出X轴的方向是纵向向上。
2.2:转换为角度并进行融合
/*通过数据寄存器里面的值计算出加速度g和角速度a通过g和a计算出欧拉角,然后在进行数据融合。
*/void MPU6050_GatResult(float *yaw ,float *roll ,float *pitch)
{float gleX,gleY,gleZ,aleX,aleY,aleZ;//定义重力加速度和角速度int16_t AX,AY,AZ,GX,GY,GZ; MPU6050_GetData(&AX,&AY,&AZ,&GX,&GY,&GZ);gleX = AX / 2048.0f;//x轴的重力加速度gleY = AY / 2048.0f;gleZ = AZ / 2048.0f;aleX = GX / 16.4f;//x轴的角速度aleY = GY / 16.4f;aleZ = GZ / 16.4f;/*通过重力加速度对欧拉角的计数*/float roll_a = atan2(gleY,gleZ) / 3.141593 * 180.0f;//翻滚角的角度float pitch_a = atan2(gleX,gleZ) / 3.141593 * 180.0f;//俯仰角的角度/*通过角速度计数欧拉角*/float yaw_g = *yaw + aleX * 0.005;//偏航角的角度float roll_g = *roll + aleY * 0.005;//翻滚角的角度float pitch_g = *pitch + aleZ * 0.005;//俯仰角的角度/*角度融合*/const float alpha = 0.95238;*yaw = yaw_g;//偏航角*roll = roll_a * alpha + (1 - alpha) * roll_g;//翻滚角*pitch = pitch_a * alpha + (1 - alpha) * pitch_g;//俯仰角
}
主函数main.c的代码如下:
/*软件模拟I2C控制MPU6050
*/#include "stm32f10x.h"
#include "OLED.h"
#include "MPU6050.h"int main(void)
{OLED_Init();OLED_Clear();MPU6050_Init();float yaw ,roll ,pitch;OLED_ShowString(1,1,"yaw: ");OLED_ShowString(2,1,"roll: ");OLED_ShowString(3,1,"pitch: ");while(1){MPU6050_GatResult(&yaw ,&roll ,&pitch);OLED_ShowSignedNum(1,6,yaw,3);//偏航角OLED_ShowSignedNum(2,7,roll,3);//翻滚角OLED_ShowSignedNum(3,8,pitch,3);//俯仰角}
}
下图为显示结果:
如上图所示:模块如图所放置,所显示的俯仰角(绕Y轴旋转)为+84°
如上图所示:模块如图所放置,所显示的翻滚角(X轴旋转)为+81°
3、片上外设I2C2读写MPU6050
使用片上外设读写MPU6050只需要将程序模拟的I2C时序替换为硬件的I2C时序即可。
①MPU6050Reg.h的代码如下:
/*将需要使用到的寄存器地址通过寄存器名宏定义
*/
#ifndef __MPU6050_H
#define __MPU6050_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
#define MPU6050_ACCEL_XOUT_L 0x3C
#define MPU6050_ACCEL_YOUT_H 0x3D
#define MPU6050_ACCEL_YOUT_L 0x3E
#define MPU6050_ACCEL_ZOUT_H 0x3F
#define MPU6050_ACCEL_ZOUT_L 0x40
#define MPU6050_TEMP_OUT_H 0x41
#define MPU6050_TEMP_OUT_L 0x42
#define MPU6050_GYRO_XOUT_H 0x43
#define MPU6050_GYRO_XOUT_L 0x44
#define MPU6050_GYRO_YOUT_H 0x45
#define MPU6050_GYRO_YOUT_L 0x46
#define MPU6050_GYRO_ZOUT_H 0x47
#define MPU6050_GYRO_ZOUT_L 0x48#define MPU6050_PWR_MGMT_1 0x6B
#define MPU6050_PWR_MGMT_2 0x6C
#define MPU6050_WHO_AM_I 0x75#endif
②MPU6050.c文件的代码如下:
#include "stm32f10x.h"
#include "MPU6050reg.h"
#include "MyI2C.h"#define MPU6050_Address 0xD0//从机地址/*给MPU6050的寄存器写入一个字节数据
*/
void MPU6050_WriteReg(uint8_t Address,uint8_t Data)//寄存器地址,需要发送的数据
{//MyI2C_Start();//MyI2C_SendByte(MPU6050_Address);//从机地址 + 0,代表写入数据//MyI2C_ReceiveACK();//接收应答,先不处理//MyI2C_SendByte(Address);//发送MPU6050寄存器的地址//MyI2C_ReceiveACK();//接收应答,先不处理//MyI2C_SendByte(Data);//MyI2C_ReceiveACK();//接收应答,先不处理//MyI2C_Stop();I2C_GenerateSTART(I2C2,ENABLE);//发送一个起始信号while(I2C_CheckEvent(I2C2,I2C_EVENT_MASTER_MODE_SELECT) != SUCCESS);//如果起始信号没有发送成功则一直在这循环I2C_Send7bitAddress(I2C2,MPU6050_Address,I2C_Direction_Transmitter);//发送地址+写while(I2C_CheckEvent(I2C2,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED) != SUCCESS);I2C_SendData(I2C2,Address);//发送MPU6050寄存器的地址while(I2C_CheckEvent(I2C2,I2C_EVENT_MASTER_BYTE_TRANSMITTING) != SUCCESS);I2C_SendData(I2C2,Data);while(I2C_CheckEvent(I2C2,I2C_EVENT_MASTER_BYTE_TRANSMITTED) != SUCCESS);I2C_GenerateSTOP(I2C2,ENABLE);
}/*读取MPU6050的寄存器里面的一个字节数据
*/
uint8_t MPU6050_ReadReg(uint8_t Address)
{uint8_t Data;//MyI2C_Start();//MyI2C_SendByte(MPU6050_Address);//从机地址//MyI2C_ReceiveACK();//接收应答,先不处理//MyI2C_SendByte(Address);//发送MPU6050寄存器的地址//MyI2C_ReceiveACK();//接收应答,先不处理//MyI2C_Start();//MyI2C_SendByte(MPU6050_Address | 0x01);//从机地址,从机地址 + 1,代表读取数据//MyI2C_ReceiveACK();//接收应答,先不处理//Data = MyI2C_ReceiveByte();//接收数据//MyI2C_SendACK(1);//MyI2C_Stop();I2C_GenerateSTART(I2C2,ENABLE);//发送一个起始信号while(I2C_CheckEvent(I2C2,I2C_EVENT_MASTER_MODE_SELECT) != SUCCESS);//如果起始信号没有发送成功则一直在这循环I2C_Send7bitAddress(I2C2,MPU6050_Address,I2C_Direction_Transmitter);//发送地址+写while(I2C_CheckEvent(I2C2,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED) != SUCCESS);I2C_SendData(I2C2,Address);//发送MPU6050寄存器的地址while(I2C_CheckEvent(I2C2,I2C_EVENT_MASTER_BYTE_TRANSMITTING) != SUCCESS);I2C_GenerateSTART(I2C2,ENABLE);//发送一个起始信号while(I2C_CheckEvent(I2C2,I2C_EVENT_MASTER_MODE_SELECT) != SUCCESS);I2C_Send7bitAddress(I2C2,MPU6050_Address,I2C_Direction_Receiver);//发送地址+读while(I2C_CheckEvent(I2C2,I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED) != SUCCESS);I2C_AcknowledgeConfig(I2C2,DISABLE);//非应答I2C_GenerateSTOP(I2C2,ENABLE);//在接收最后一个字节提前申请停止信号while(I2C_CheckEvent(I2C2,I2C_EVENT_MASTER_BYTE_RECEIVED) != SUCCESS);Data = I2C_ReceiveData(I2C2);return Data;
}/*给MPU6050初始化配置
*/
void MPU6050_Init(void)/**/
{//1 .初始化IO引脚RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);GPIO_InitTypeDef GPIOInitStruct;GPIOInitStruct.GPIO_Mode = GPIO_Mode_AF_OD;//复用输出开漏模式GPIOInitStruct.GPIO_Pin = GPIO_Pin_10 |GPIO_Pin_11;GPIOInitStruct.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOB,&GPIOInitStruct);//2 .开启I2C挂载APB1总线的时钟RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C2,ENABLE);//开启时钟RCC_APB1PeriphResetCmd(RCC_APB1Periph_I2C2,ENABLE);//对I2C1进行复位RCC_APB1PeriphResetCmd(RCC_APB1Periph_I2C2,DISABLE);//对I2C1进行释放//3 .配置I2C1的参数I2C_InitTypeDef I2CInitStruct;I2CInitStruct.I2C_ClockSpeed = 400000;//配置波特率,最高400KI2CInitStruct.I2C_Mode = I2C_Mode_I2C;//标准的I2C模式,一般不使用SMBusI2CInitStruct.I2C_DutyCycle = I2C_DutyCycle_2;//2:1I2C_Init(I2C2,&I2CInitStruct);//4 .使能I2CI2C_Cmd(I2C2,ENABLE);//闭合开关,PEMPU6050_WriteReg(MPU6050_PWR_MGMT_1,0x00);//给电源管理寄存器1发送0x00,解除睡眠模式MPU6050_WriteReg(MPU6050_PWR_MGMT_2,0x00);//配置电源管理寄存器2MPU6050_WriteReg(MPU6050_SMPLRT_DIV,0x09);//采样率分频10分频MPU6050_WriteReg(MPU6050_CONFIG,0x06);//数字低通滤波MPU6050_WriteReg(MPU6050_GYRO_CONFIG,0x18);//角速度的量程,满量程MPU6050_WriteReg(MPU6050_ACCEL_CONFIG,0x18);//加速度g的量程,满量程
}/*获取数据寄存器里面的数据ACC代表加速度g的值Gyrox代表角数据的值
*/
void MPU6050_GetData(int16_t *ACCx,int16_t *ACCy,int16_t *ACCz,int16_t *Gyrox,int16_t *Gyroy,int16_t *Gyroz)//读取寄存器里面的数据
{uint16_t DataH , DataL;DataH = MPU6050_ReadReg(MPU6050_ACCEL_XOUT_H);//读取x轴加速度计的高8位DataL = MPU6050_ReadReg(MPU6050_ACCEL_XOUT_L);//读取x轴加速度计的第8位*ACCx = (DataH << 8) | DataL;DataH = MPU6050_ReadReg(MPU6050_ACCEL_YOUT_H);//读取Y轴加速度计的高8位DataL = MPU6050_ReadReg(MPU6050_ACCEL_YOUT_L);*ACCy = (DataH << 8) | DataL;DataH = MPU6050_ReadReg(MPU6050_ACCEL_ZOUT_H);//读取Z轴加速度计的高8位DataL = MPU6050_ReadReg(MPU6050_ACCEL_ZOUT_L);*ACCz = (DataH << 8) | DataL;DataH = MPU6050_ReadReg(MPU6050_GYRO_XOUT_H);//读取x轴陀螺仪的高8位DataL = MPU6050_ReadReg(MPU6050_GYRO_XOUT_L);*Gyrox = (DataH << 8) | DataL;DataH = MPU6050_ReadReg(MPU6050_GYRO_YOUT_H);//读取y轴陀螺仪的高8位DataL = MPU6050_ReadReg(MPU6050_GYRO_YOUT_H);*Gyroy = (DataH << 8) | DataL;DataH = MPU6050_ReadReg(MPU6050_GYRO_ZOUT_H);//读取z轴陀螺仪的高8位DataL = MPU6050_ReadReg(MPU6050_GYRO_ZOUT_H);*Gyroz = (DataH << 8) | DataL;
}
④主函数main.c的代码如下:
/*软件模拟I2C控制MPU6050
*/#include "stm32f10x.h"
#include "OLED.h"
#include "MPU6050.h"int main(void)
{OLED_Init();OLED_Clear();int16_t AX,AY,AZ,GX,GY,GZ; MPU6050_Init();while(1){MPU6050_GetData(&AX,&AY,&AZ,&GX,&GY,&GZ);OLED_ShowSignedNum(2,1,AX,5);//显示X轴的加速度g的大小OLED_ShowSignedNum(3,1,AY,5);//显示Y轴的加速度g的大小OLED_ShowSignedNum(4,1,AZ,5);//显示Z轴的加速度g的大小OLED_ShowSignedNum(2,8,GX,5);//显示X轴的角速度a的大小OLED_ShowSignedNum(3,8,GY,5);//显示Y轴的角速度a的大小OLED_ShowSignedNum(4,8,GZ,5);//显示Z轴的角速度a的大小}
}
显示的结果和上图一样。