打印
[其他ST产品]

STM32 使用DMP库处理MPU6050数据

[复制链接]
楼主: 和下土
手机看帖
扫描二维码
随时随地手机跟帖
21
和下土|  楼主 | 2022-5-28 20:05 | 只看该作者 |只看大图 回帖奖励 |倒序浏览
10、温度传感器
温度传感器的值,可以通过读取 0X41(高 8 位)和 0X42(低 8 位)寄存器得到,温度换算公式为:
Temperature = 36.53 + regval/340
Temperature 为计算得到的温度值,单位为℃, regval 为从 0X41 和 0X42 读到的温度传感器值。

使用特权

评论回复
22
和下土|  楼主 | 2022-5-28 20:06 | 只看该作者
5、代码示例
1、读写数据

/**  
  *  功能:IIC写一个字节
  *  入口参数:reg,寄存器地址;data,数据
  *  返回值:0,正常;1,错误
  */
u8 MPU_Write_Byte(u8 reg,u8 data)
{
        MPU_IIC_Start();
        MPU_IIC_Send_Byte((MPU_ADDR<<1)|0);//ADDR左移一位+写操作
        if(MPU_IIC_Wait_Ack())//等待应答
        {
                MPU_IIC_Stop();
                return 1;
        }
        MPU_IIC_Send_Byte(reg);
        MPU_IIC_Wait_Ack();
        MPU_IIC_Send_Byte(data);
        if(MPU_IIC_Wait_Ack())
        {
                MPU_IIC_Stop();
                return 1;
        }
        MPU_IIC_Stop();
        return 0;
}
  
/**  
  *  功能:IIC读一个字节
  *  入口参数:reg,寄存器地址
  *  返回值:数据
  */
u8 MPU_Read_Byte(u8 reg)
{
        u8 res;
        MPU_IIC_Start();
        MPU_IIC_Send_Byte((MPU_ADDR<<1)|0);//外设地址+写命令
        MPU_IIC_Wait_Ack();
        MPU_IIC_Send_Byte(reg);//寄存器地址
        MPU_IIC_Wait_Ack();
        MPU_IIC_Start();
        MPU_IIC_Send_Byte((MPU_ADDR<<1)|1);
        MPU_IIC_Wait_Ack();
        res = MPU_IIC_Read_Byte(0);
        MPU_IIC_Stop();
        return res;
}
/**  
  *  功能:IIC连续写
  *  入口参数:addr,外设地址;reg,寄存器地址;len,写入长度;buf,数据
  *  返回值:0,正常;1,错误
  */
u8 MPU_Write_Len(u8 addr,u8 reg,u8 len,u8 *buf)
{
        u8 i;
        MPU_IIC_Start();
        MPU_IIC_Send_Byte((addr<<1)|0);
        if(MPU_IIC_Wait_Ack())
        {
                MPU_IIC_Stop();
                return 1;
        }
        MPU_IIC_Send_Byte(reg);
        MPU_IIC_Wait_Ack();
        for(i=0;i<len;i++)
        {
                MPU_IIC_Send_Byte(buf[i]);
                if(MPU_IIC_Wait_Ack())
                {
                        MPU_IIC_Stop();
                        return 1;
                }
        }
        MPU_IIC_Stop();
        return 0;
}
/**  
  *  功能:IIC连续读
  *  入口参数:addr,外设地址;reg,寄存器地址;len,读取长度;buf,储存数据
  *  返回值:0,正常;1,错误
  */
u8 MPU_Read_Len(u8 addr,u8 reg,u8 len,u8 *buf)
{
        MPU_IIC_Start();
        MPU_IIC_Send_Byte((addr<<1)|0);
        if(MPU_IIC_Wait_Ack())
        {
                MPU_IIC_Stop();
                return 1;
        }
        MPU_IIC_Send_Byte(reg);
        MPU_IIC_Wait_Ack();
        MPU_IIC_Start();
        MPU_IIC_Send_Byte((addr<<1)|1);
        MPU_IIC_Wait_Ack();
        while(len)
        {
                if(len==1)
                        *buf=MPU_IIC_Read_Byte(0);
                else               
                        *buf=MPU_IIC_Read_Byte(1);               
                len--;
                buf++;
        }
        MPU_IIC_Stop();
        return 0;
}

使用特权

评论回复
23
和下土|  楼主 | 2022-5-28 20:07 | 只看该作者
2、陀螺仪初始化代码
/**  
  *  功能:初始化MPU6050
  *  入口参数:无
  *  返回值:0,成功;其他,错误
  */
u8 MPU_Init(void)
{
        u8 res;
        GPIO_InitTypeDef GPIO_InitStructure;
       
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOA,ENABLE);
       
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_Init(GPIOA,&GPIO_InitStructure);
       
        GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE);//禁止JTAG,使PA15变为普通IO
       
        MPU_AD0_CTRL = 0;//控制MPU6050的AD0为低电平,从机地址=0x68;
                                         //                                         高电平,                  0x69;
        MPU_IIC_Init();
        MPU_Write_Byte(MPU_PWR_MGMT1_REG,0x80);//复位从机
        delay_ms(100);
        MPU_Write_Byte(MPU_PWR_MGMT1_REG,0x00);//唤醒从机
        MPU_Set_Gyro_Fsr(3);//陀螺仪传感器 +-2000dps
        MPU_Set_Accel_Fsr(0);//加速度传感器 +-2g
        MPU_Set_Rate(50);
        MPU_Write_Byte(MPU_INT_EN_REG,0x00);//关闭所有中断
        MPU_Write_Byte(MPU_USER_CTRL_REG,0x00);//IIC主模式关闭
        MPU_Write_Byte(MPU_FIFO_EN_REG,0x00);//关闭FIFO
        MPU_Write_Byte(MPU_INTBP_CFG_REG,0x80);//INT低电平有效
        res = MPU_Read_Byte(MPU_DEVICE_ID_REG);
        if(res == MPU_ADDR)
        {
                MPU_Write_Byte(MPU_PWR_MGMT1_REG,0x01);//设置CLKSEL PLL X轴为参考
                MPU_Write_Byte(MPU_PWR_MGMT2_REG,0x00);//加速度计和陀螺仪使能
                MPU_Set_Rate(50);
        }
        else
                return 1;
        return 0;
}
/**  
  *  功能:设置陀螺仪传感器满量程范围
  *  入口参数:fsr,0,+-250dps
  *                                   1,+-500dps
  *                                   2,+-1000dps
  *                                   3,+-2000dps       
  *  返回值:0,成功;1,失败
  */
u8 MPU_Set_Gyro_Fsr(u8 fsr)
{
        return MPU_Write_Byte(MPU_GYRO_CFG_REG,fsr<<3);
}
/**  
  *  功能:设置加速度传感器满量程范围
  *  入口参数:fsr,0,+-2g
  *                                    1,+-4g
  *                                    2,+-8g
  *                                    3,+-16g       
  *  返回值:0,成功;1,失败
  */
u8 MPU_Set_Accel_Fsr(u8 fsr)
{
        return MPU_Write_Byte(MPU_ACCEL_CFG_REG,fsr<<3);
}
/**  
  *  功能:设置数字低通滤波器
  *  入口参数:lpf,低通滤波器频率(Hz)
  *  返回值:0,成功;1,失败
  */
u8 MPU_Set_LPF(u16 lpf)
{
        u8 data=0;
        if(lpf>=188)data=1;
        else if(lpf>=98)data=2;
        else if(lpf>=42)data=3;
        else if(lpf>=20)data=4;
        else if(lpf>=10)data=5;
        else data=6;
        return MPU_Write_Byte(MPU_CFG_REG,data);
}
/**  
  *  功能:设置采样率(Fs=1KHz)
  *  入口参数:rate=[4,1000]Hz
  *  返回值:0,设置成功;1,设置失败
  */
u8 MPU_Set_Rate(u16 rate)
{
        u8 data;
        if(rate>1000)rate=1000;
        if(rate<4)rate=4;
        data=1000/rate-1;
        data=MPU_Write_Byte(MPU_SAMPLE_RATE_REG,data);
        return MPU_Set_LPF(rate/2);
}

使用特权

评论回复
24
和下土|  楼主 | 2022-5-28 20:07 | 只看该作者
3、获取原始数据代码
/**  
  *  功能:获取MPU内部温度
  *  入口参数:无
  *  返回值:温度*100
  */
short MPU_Get_Temperature(void)
{
        u8 buf[2];
        short raw;
        float temp;
        MPU_Read_Len(MPU_ADDR,MPU_TEMP_OUTH_REG,2,buf);
        raw=((u16)buf[0]<<8)|buf[1];
        temp = 36.53+((double)raw)/340;
        return temp*100;
}
/**  
  *  功能:获得陀螺仪原始值
  *  入口参数:gx,gy,gz,陀螺仪XYZ轴原始数据(带符号)
  *  返回值:0,成功;1,失败
  */
u8 MPU_Get_Gyroscope(short *gx,short *gy,short *gz)
{
        u8 buf[6],res;
        res=MPU_Read_Len(MPU_ADDR,MPU_GYRO_XOUTH_REG,6,buf);
        if(res == 0)
        {
                *gx=((u16)buf[0]<<8)|buf[1];
                *gy=((u16)buf[2]<<8)|buf[3];
                *gz=((u16)buf[4]<<8)|buf[5];
        }
        return res;
}
/**  
  *  功能:获得加速度原始值
  *  入口参数:ax,ay,az,加速度计XYZ的原始数据()
  *  返回值:0,正常;1,错误
  */
u8 MPU_Get_Accelerometer(short *ax,short *ay,short *az)
{
        u8 buf[6],res;
        res=MPU_Read_Len(MPU_ADDR,MPU_ACCEL_XOUTH_REG,6,buf);
        if(res ==0)
        {
                *ax=((u16)buf[0]<<8)|buf[1];
                *ay=((u16)buf[2]<<8)|buf[3];
                *az=((u16)buf[4]<<8)|buf[5];
        }
        return res;
}

使用特权

评论回复
25
和下土|  楼主 | 2022-5-28 20:08 | 只看该作者
4、DMP库函数调用
//mpu6050,dmp初始化
//返回值:0,正常
//    其他,失败
u8 mpu_dmp_init(void)
{
        u8 res=0;
        MPU_IIC_Init();         //初始化IIC总线
        if(mpu_init()==0)        //初始化MPU6050
        {         
                res=mpu_set_sensors(INV_XYZ_GYRO|INV_XYZ_ACCEL);//设置所需要的传感器
                if(res)return 1;
                res=mpu_configure_fifo(INV_XYZ_GYRO|INV_XYZ_ACCEL);//设置FIFO
                if(res)return 2;
                res=mpu_set_sample_rate(DEFAULT_MPU_HZ);        //设置采样率
                if(res)return 3;
                res=dmp_load_motion_driver_firmware();                //加载dmp固件
                if(res)return 4;
                res=dmp_set_orientation(inv_orientation_matrix_to_scalar(gyro_orientation));//设置陀螺仪方向
                if(res)return 5;
                res=dmp_enable_feature(DMP_FEATURE_6X_LP_QUAT|DMP_FEATURE_TAP|        //设置dmp功能
                    DMP_FEATURE_ANDROID_ORIENT|DMP_FEATURE_SEND_RAW_ACCEL|DMP_FEATURE_SEND_CAL_GYRO|
                    DMP_FEATURE_GYRO_CAL);
                if(res)return 6;
                res=dmp_set_fifo_rate(DEFAULT_MPU_HZ);        //设置DMP输出速率(最大不超过200Hz)
                if(res)return 7;   
                res=run_self_test();                //自检
                if(res)return 8;   
                res=mpu_set_dmp_state(1);        //使能DMP
                if(res)return 9;     
        }else return 10;
        return 0;
}
//得到dmp处理后的数据(注意,本函数需要比较多堆栈,局部变量有点多)
//pitch:俯仰角 精度:0.1°   范围:-90.0° <---> +90.0°
//roll:横滚角  精度:0.1°   范围:-180.0°<---> +180.0°
//yaw:航向角   精度:0.1°   范围:-180.0°<---> +180.0°
//返回值:0,正常
//    其他,失败
u8 mpu_dmp_get_data(float *pitch,float *roll,float *yaw)
{
        float q0=1.0f,q1=0.0f,q2=0.0f,q3=0.0f;
        unsigned long sensor_timestamp;
        short gyro[3], accel[3], sensors;
        unsigned char more;
        long quat[4];
        if(dmp_read_fifo(gyro, accel, quat, &sensor_timestamp, &sensors,&more))return 1;         
        /* Gyro and accel data are written to the FIFO by the DMP in chip frame and hardware units.
         * This behavior is convenient because it keeps the gyro and accel outputs of dmp_read_fifo and mpu_read_fifo consistent.
        **/
        /*if (sensors & INV_XYZ_GYRO )
        send_packet(PACKET_TYPE_GYRO, gyro);
        if (sensors & INV_XYZ_ACCEL)
        send_packet(PACKET_TYPE_ACCEL, accel); */
        /* Unlike gyro and accel, quaternions are written to the FIFO in the body frame, q30.
         * The orientation is set by the scalar passed to dmp_set_orientation during initialization.
        **/
        if(sensors&INV_WXYZ_QUAT)
        {
                q0 = quat[0] / q30;        //q30格式转换为浮点数
                q1 = quat[1] / q30;
                q2 = quat[2] / q30;
                q3 = quat[3] / q30;
                //计算得到俯仰角/横滚角/航向角
                *pitch = asin(-2 * q1 * q3 + 2 * q0* q2)* 57.3;        // pitch
                *roll  = atan2(2 * q2 * q3 + 2 * q0 * q1, -2 * q1 * q1 - 2 * q2* q2 + 1)* 57.3;        // roll
                *yaw   = atan2(2*(q1*q2 + q0*q3),q0*q0+q1*q1-q2*q2-q3*q3) * 57.3;        //yaw
        }else return 2;
        return 0;
}

使用特权

评论回复
26
和下土|  楼主 | 2022-5-28 20:10 | 只看该作者
6、实验现象

使用特权

评论回复
27
和下土|  楼主 | 2022-5-28 20:11 | 只看该作者

使用特权

评论回复
28
和下土|  楼主 | 2022-5-28 20:12 | 只看该作者
7、总结
对于MPU6050数据的处理,使用DMP库是一种比较简单的办法,如果理论扎实,可以自行读取原始数据,通过四元数解算获取欧拉角。下一次我们将会把陀螺仪得到的数据发送到上位机,下次主要分析上位机的通讯协议。

使用特权

评论回复
29
elsaflower| | 2022-7-8 10:29 | 只看该作者
有计步的功能吗   

使用特权

评论回复
30
beacherblack| | 2022-7-8 16:23 | 只看该作者
MPU6050的功能还是比较强大的。   

使用特权

评论回复
31
mickit| | 2022-7-9 12:55 | 只看该作者
可以拓展hmc5883吗   

使用特权

评论回复
32
mattlincoln| | 2022-7-9 13:27 | 只看该作者
DMP库处理MPU6050速度还可以。   

使用特权

评论回复
33
fengm| | 2022-7-9 14:20 | 只看该作者
可以使用ahrs吗   

使用特权

评论回复
34
phoenixwhite| | 2022-7-9 15:20 | 只看该作者
硬件iic吗   

使用特权

评论回复
35
janewood| | 2022-7-9 18:16 | 只看该作者
为什么不使用四元数计算呢   

使用特权

评论回复
36
youtome| | 2022-7-9 20:13 | 只看该作者
这个iic函数呢?   

使用特权

评论回复
37
happy_10| | 2022-7-10 14:00 | 只看该作者
有计步的功能吗   

使用特权

评论回复
38
xxrs| | 2022-7-10 14:02 | 只看该作者
MPU6050的功能还是比较强大的。   

使用特权

评论回复
39
stly| | 2022-7-10 14:04 | 只看该作者
可以拓展hmc5883吗   

使用特权

评论回复
40
llljh| | 2022-7-10 14:06 | 只看该作者
DMP库处理MPU6050速度还可以。   

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则