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);//释放SDA
I2C_W_SCL(1);//释放SCL
I2C_W_SDA(0);//拉低SDA
I2C_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。因为BitAction
I2C_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);//配置电源管理寄存器2
MPU6050_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;//配置波特率,最高400K
I2CInitStruct.I2C_Mode = I2C_Mode_I2C;//标准的I2C模式,一般不使用SMBus
I2CInitStruct.I2C_DutyCycle = I2C_DutyCycle_2;//2:1
I2C_Init(I2C2,&I2CInitStruct);
//4 .使能I2C
I2C_Cmd(I2C2,ENABLE);//闭合开关,PE
MPU6050_WriteReg(MPU6050_PWR_MGMT_1,0x00);//给电源管理寄存器1发送0x00,解除睡眠模式
MPU6050_WriteReg(MPU6050_PWR_MGMT_2,0x00);//配置电源管理寄存器2
MPU6050_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的大小
}
}
显示的结果和上图一样。