- #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;
- }
-
-