#include "stm32f4xx.h"
#include "MyMPU6050.h"
#include "delay.h"
#include "usart.h"
//初始化MPU6050
//返回值:0,成功
// 其他,错误代码
u8 MPU6050_Init(void)
{
//该步骤严格按读取MPU6050姿态的步骤进行
u8 res;
IIC_Init();
//#define MPU_PWR_MGMT1_REG 0X6B //电源管理寄存器1
MPU6050_Write_Byte(MPU_PWR_MGMT1_REG,0X80); //复位MPU6050 通过对电源管理寄存器1的位7写1来实现
//位7 DEVICE_RESET:该位设置1,重启内部寄存器到默认值。复位完成后该位自动清0。
delay_ms(100);
MPU6050_Write_Byte(MPU_PWR_MGMT1_REG,0X00); //唤醒MPU6050 通过使电源管理寄存器1清0,进入正常工作模式
//设置角速度传感器(陀螺仪)和加速度传感器的满量程范围
//设置两个传感器的满量程范围(FSR),分别通过陀螺仪配置寄存器(0X1B)和加速度传感器配置寄存器(0X1C)设置。
//我们一般设置陀螺仪的满量程范围为2000dps,加速度传感器的满量程范围为2g。
MPU6050_Set_Gyro_Fsr(3); //陀螺仪传感器,±2000dps
MPU6050_Set_Accel_Fsr(0); //加速度传感器,±2g
MPU6050_Set_Rate(50); //设置采样率50Hz
//设置其他参数,其中包括关闭中断、关闭AUX IIC接口、禁止FIFO、设置陀螺仪采样率和设置数字低通滤波器(DLPF)
MPU6050_Write_Byte(MPU_INT_EN_REG,0X00); //关闭所有中断 将中断使能寄存器的所有位写入0,关闭所有中断
MPU6050_Write_Byte(MPU_USER_CTRL_REG,0X00); //I2C主模式关闭 也就是MPU6050充当主机,通过IIC和磁力传感器进行通讯,实现九轴传感器
MPU6050_Write_Byte(MPU_FIFO_EN_REG,0X00); //关闭FIFO 将FIFO使能寄存器的所有位写入0,来关闭FIFO
MPU6050_Write_Byte(MPU_INTBP_CFG_REG,0X80); //INT引脚低电平有效
res=MPU6050_Read_Byte(MPU_DEVICE_ID_REG); //通过读取WHO_AM_I寄存器获取MPU6050的ID
if(res==MPU_Address)//器件ID正确 //判断ID是否是0X68
{
//配置系统时钟源并使能角速度传感器和加速度传感器
MPU6050_Write_Byte(MPU_PWR_MGMT1_REG,0X01); //设置CLKSEL,PLL X轴为参考 通过设置电源管理寄存器1的最低位,设置系统时钟为001
MPU6050_Write_Byte(MPU_PWR_MGMT2_REG,0X00); //加速度与陀螺仪都工作 通过设置电源管理寄存器2的所有位为0来使能加速度计和陀螺仪,设置为1则加速度计和陀螺仪的X,Y,Z轴进入待机模式
MPU6050_Set_Rate(50); //设置采样率为50Hz
}
else
return 1; //ID错误
return 0;
}
//设置MPU6050的陀螺仪传感器满量程范围
//FS_SEL:0,±250dps;1,±500dps;2,±1000dps;3,±2000dps
//返回值:0,设置成功
// 其他,设置失败
u8 MPU6050_Set_Gyro_Fsr(u8 FS_SEL)
{
return MPU6050_Write_Byte(MPU_GYRO_CFG_REG,FS_SEL<<3); //设置陀螺仪配置寄存器的位3和位4,这里选择量程3,±2000dps,所以配置为3即可
}
//设置MPU6050加速度传感器满量程范围
//AFS_SEL::0,±2g;1,±4g;2,±8g;3,±16g
//返回值:0,设置成功
// 其他,设置失败
u8 MPU6050_Set_Accel_Fsr(u8 AFS_SEL)
{
return MPU6050_Write_Byte(MPU_ACCEL_CFG_REG,AFS_SEL<<3); //配置加速度传感器配置寄存器的位3和位4,所以需要左移三位,这里设置0,±2g;
}
//设置MPU6050的数字低通滤波器
//PinLv:数字低通滤波频率
//返回值:0,设置成功
// 其他,设置失败
u8 MPU6050_Set_LPF(u16 PinLv)
{
u8 Data=0;
if(PinLv>=188) //这里解释一下,为什么分别设置数字低通滤波频率为188 98 42 20 10 并且得到的低通滤波频率为1 2 3 4 5 6
//首先设置MPU6050的数字低通滤波器其实质是设置配置寄存器的低3位,根据官方MPU6050寄存器手册
Data=1; //当设置的数字低通滤波器频率大于188Hz时,配置寄存器的低三位写入001,也就是1
else if(PinLv>=98)
Data=2; //当设置的数字低通滤波器频率大于98Hz时,配置寄存器的低三位写入010,也就是2
else if(PinLv>=42)
Data=3; //当设置的数字低通滤波器频率大于42Hz时,配置寄存器的低三位写入011,也就是3
else if(PinLv>=20)
Data=4; //当设置的数字低通滤波器频率大于20Hz时,配置寄存器的低三位写入100,也就是4
else if(PinLv>=10)
Data=5; //当设置的数字低通滤波器频率大于10Hz时,配置寄存器的低三位写入101,也就是5
else
Data=6; //其他情况下均写入111,表示6
return MPU6050_Write_Byte(MPU_CFG_REG,Data); //通过写配置寄存器的第三位即可设置数字低通滤波器
//#define MPU_CFG_REG 0X1A //配置寄存器
}
//设置MPU6050采样率
//Rate:4~1000Hz
//返回值:0,设置成功
// 其他,设置失败
u8 MPU6050_Set_Rate(u16 Rate) //这里一定要假设MPU6050的输出频率为1Khz,输出频率可以是1Khz或者8Khz,其值和数字低通滤波器的设置有关,当数字低通滤波器的低三位写入0或者7时,为8Khz,其余均是1Khz
{
u8 Data; //定义Data是采样率分频寄存器写入的8位数值
if(Rate>1000) //设置范围
Rate=1000;
if(Rate<4) //设置范围
Rate=4;
Data=1000/Rate-1; //采样频率 = 陀螺仪输出频率 / (1+SMPLRT_DIV) 其中SMPLRT_DIV就是Data,寄存器中写入的值
//采样频率 = 陀螺仪输出频率 / (1+Data) 其中输出频率是1Khz
Data=MPU6050_Write_Byte(MPU_SAMPLE_RATE_REG,Data); //设置数字低通滤波器
return MPU6050_Set_LPF(Rate/2); //自动设置数字低通滤波器为采样频率的一半
}
//得到温度值
//返回值:温度值(扩大了100倍)
short MPU6050_Get_Temperature(void)
{
u8 Buffer[2]; //温度的值是由两个八位寄存器读取的,所以定义一个存储两字节大小的数组
short raw; //短整型16位
float temperature;
MPU6050_Read_Len(MPU_Address,MPU_TEMP_OUTH_REG,2,Buffer);
raw=((u16)Buffer[0]<<8)|Buffer[1]; //16位温度值需要两个8位进行或运算
temperature=36.53+((double)raw)/340; //Temperature = 36.53 + regval/340 ,计算温度的公式 其中regval是从0X41和0X42寄存器读出的值
return temperature*100;
}
//得到陀螺仪原始值
//GX,GY,GZ:陀螺仪X,Y,Z轴的原始读数
//返回值:0,成功
// 其他,错误代码
u8 MPU6050_Get_Gyroscope(short *GX,short *GY,short *GZ)
{
u8 Buffer[6];
u8 res;
res=MPU6050_Read_Len(MPU_Address,MPU_GYRO_XOUTH_REG,6,Buffer);//读陀螺仪的原始值是通过读6个陀螺仪数据输出寄存器,这些寄存器都是8位的,每两个寄存器拼接成一个16位的原始数据
if(res==0)//返回值为0,表示读成功
{
*GX=((u16)Buffer[0]<<8)|Buffer[1];//因为先读的是寄存器的高8位
*GY=((u16)Buffer[2]<<8)|Buffer[3];
*GZ=((u16)Buffer[4]<<8)|Buffer[5];
}
return res;
}
//得到加速度计原始值
//AX,AY,AZ:加速度计X,Y,Z轴的原始读数
//返回值:0,成功
// 其他,错误代码
u8 MPU6050_Get_Accelerometer(short *AX,short *AY,short *AZ)
{
u8 Buffer[6];
u8 res;
res=MPU6050_Read_Len(MPU_Address,MPU_ACCEL_XOUTH_REG,6,Buffer);//读加速度计的原始值是通过读6个加速度数据输出寄存器,这些寄存器都是8位的,每两个寄存器拼接成一个16位的原始数据
if(res==0)//返回值为0,表示读成功
{
*AX=((u16)Buffer[0]<<8)|Buffer[1];//因为先读的是寄存器高8位
*AY=((u16)Buffer[2]<<8)|Buffer[3];
*AZ=((u16)Buffer[4]<<8)|Buffer[5];
}
return res;
}
//IIC连续写
//Address:器件地址
//Register:寄存器地址
//Length:要写入的长度
//Buffer:数据区
//返回值:0,正常
// 其他,错误代码
u8 MPU6050_Write_Len(u8 Address,u8 Register,u8 Length,u8 *Buffer)
{
u8 i;
IIC_Start(); //发送起始信号
IIC_Send_Byte((Address<<1)|0); //主机向从机发送器件地址,也就是主机想要和从机的哪块地址进行通讯,地址最低位是读写位
//IIC发送的从机地址是7位,最低位是R/W:主从写方向位,(Address<<1)|0表示左移一位再把最低位置0,也就表示主机写数据到从机
if(IIC_Wait_Ack()) //等待从机应答,IIC_Wait_Ack该函数的返回值若为1,则表示没有接收到从机的应答信号,IIC通讯结束
{
IIC_Stop();
return 1;
}
IIC_Send_Byte(Register); //跳过if判断语句就意味着从机接收到了主机的信号,主机发送寄存器地址
IIC_Wait_Ack(); //等待从机应答
for(i=0;i<Length;i++)
{
IIC_Send_Byte(Buffer[i]);//通过循环一位一位的发送数据,发送Length字节长的数据
if(IIC_Wait_Ack())//IIC时序规定每发送一位,从机都要应答一次
{
IIC_Stop();
return 1;
}
}
IIC_Stop(); //发送完毕,IIC通讯结束
return 0;
}
//IIC连续读
//Address:器件地址
//Register:要读取的寄存器地址
//Length:要读取的长度
//Buffer:读取到的数据存储区
//返回值:0,正常
// 其他,错误代码
u8 MPU6050_Read_Len(u8 Address,u8 Register,u8 Length,u8 *Buffer)
{
IIC_Start(); //发送起始信号
IIC_Send_Byte((Address<<1)|0); //主机向从机发送器件地址,也就是主机想要和从机的哪块地址进行通讯
//IIC发送的从机地址是7位,最低位是R/W:主从写方向位,(Address<<1)|0表示左移一位再把最低位置0,也就表示主机写数据到从机
if(IIC_Wait_Ack()) //等待从机应答,IIC_Wait_Ack该函数的返回值若为1,则表示没有接收到从机的应答信号,IIC通讯结束
{
IIC_Stop();
return 1;
}
IIC_Send_Byte(Register); //跳过if判断语句就意味着从机接收到了主机的信号,主机发送寄存器地址
IIC_Wait_Ack(); //等待从机应答
IIC_Start(); //发送起始信号
IIC_Send_Byte((Address<<1)|1); //主机向从机发送器件地址,也就是主机想要和从机的哪块地址进行通讯
//IIC发送的从机地址是7位,最低位是R/W:主从写方向位,(Address<<1)|1表示左移一位再把最低位置1,也就表示主机从从机中读数据
IIC_Wait_Ack(); //等待从机应答
while(Length)
{
if(Length==1)//如果只写入了一个节长的数据,那么发送NAck
{
*Buffer=IIC_Read_Byte(0); //不产生应答
}
else
*Buffer=IIC_Read_Byte(1);//产生应答
Length--;
Buffer++;
}
IIC_Stop();
return 0;
}
//IIC写一个字节
//Register:寄存器地址
//Data:数据
//返回值:0,正常
// 其他,错误代码
u8 MPU6050_Write_Byte(u8 Register,u8 Data)
{
IIC_Start();
IIC_Send_Byte((MPU_Address<<1)|0); //注意写一位写字节时,发送的是从机IIC的地址
if(IIC_Wait_Ack()) //等待从机应答,IIC_Wait_Ack该函数的返回值若为1,则表示没有接收到从机的应答信号,IIC通讯结束
{
IIC_Stop();
return 1;
}
IIC_Send_Byte(Register);
IIC_Wait_Ack();
IIC_Send_Byte(Data);
if(IIC_Wait_Ack()) //等待从机应答,IIC_Wait_Ack该函数的返回值若为1,则表示没有接收到从机的应答信号,IIC通讯结束
{
IIC_Stop();
return 1;
}
IIC_Stop();
return 0;
}
//IIC读一个字节
//Register:寄存器地址
//返回值:读到的数据
u8 MPU6050_Read_Byte(u8 Register)
{
u8 res;
IIC_Start();
IIC_Send_Byte((MPU_Address<<1)|0);
IIC_Wait_Ack();
IIC_Send_Byte(Register);
IIC_Wait_Ack();
IIC_Start();
IIC_Send_Byte((MPU_Address<<1)|1);
IIC_Wait_Ack();
res=IIC_Read_Byte(0);
IIC_Stop();
return res;
}