MPU6050陀螺仪加速度计

本文章已经生成可运行项目,

MPU6050结构

陀螺仪和加速度计的信号路径示意图

 MPU6050内部常用的寄存器配置介绍

设备地址寄存器

功能:此寄存器用于验证设备的身份。

介绍:

        WHO_AM_I 的内容是 MPU-60X0 的 7 位 I2C 地址的高 6 位。MPU-60X0 的 I2C 地址的最低有效位由 AD0 引脚的值决定。AD0 引脚的值不会反映在此寄存器中。


作用:确认设备地址、验证通信是否正常

配置寄存器

功能:该寄存器配置外部帧同步(FSYNC)引脚采样和数字陀螺仪和加速度计的低通滤波器(DLPF)设置。


DLPF通过DLPF_CFG配置。根据DLPF_CFG的值对加速度计和陀螺仪进行滤波,如下表所示。

作用:设置低通滤波器、

采样率分配寄存器

功能:这个寄存器指定了用于生成MPU-60X0采样率的陀螺仪输出速率的分频器。



介绍:

        传感器寄存器输出,FIFO输出,DMP采样,运动检测,零运动检测和自由落体检测都是基于采样率。采样率由陀螺仪输出速率除以SMPLRT DIV产生:

采样率=陀螺仪输出速率/ (1 + SMPLRT_DIV)

        其中陀螺仪输出速率为8kHz时DLPF被禁用(DLPF CFG - 0或7),当陀螺仪输出速率1kHz时DLPF被启用。
注:加速度计输出速率为1kHz。也就是说当采样率大于1kHz时,同一个加速度计的采样可能会被输出到FIFO、DMP和传感器寄存器中。

作用:设置采样率

电源管理寄存器_1 

功能:该寄存器允许用户配置电源模式和时钟源。它还提供了重置整个设备的位,以及禁用温度传感器的位。


介绍:

        将SLEEP设置为1时,MPU-60X0可以进入低功耗睡眠模式。当CYCLE设置为1且SLEEP被禁用时,MPU-60X0将进入循环模式。在循环模式下,设备会在睡眠模式和唤醒模式之间循环,以LP_WAKE_CTRL(寄存器108)确定的速率从活动传感器中采集一次数据。要配置唤醒频率,请在电源管理2寄存器(寄存器108)中使用LP_WAKE_CTRL。

        可以选择内部8MHz振荡器、基于陀螺仪的时钟或外部源作为MPU-60X0的时钟源。当选择内部8 MHz振荡器或外部源作为时钟源时,MPU-60X0可以在陀螺仪禁用的情况下以低功耗模式运行。

        上电时,MPU-60X0的时钟源默认为内部振荡器。然而,强烈建议将设备配置为使用其中一个陀螺仪(或外部时钟源)作为时钟参考,以提高稳定性。时钟源可以根据下表进行选择。

        

 

 作用:硬件复位、时钟源配置、解除休眠

电源管理寄存器_2

功能:此寄存器允许用户配置仅加速度计低功耗模式下的唤醒频率。此寄存器还允许用户将加速度计和陀螺仪的各个轴置于待机模式。


唤醒频率表

待机唤醒功能要结合电源管理寄存器_1CYCLE(循环唤醒)位实现

作用:待机、低功耗

中断使能寄存器

功能:此寄存器使能中断源产生中断。


作用:配置中断源

FIFO使能寄存器

功能:此寄存器决定将哪些传感器测量值加载到FIFO缓冲区中。


介绍:

        存储在传感器数据寄存器(寄存器59至96)中的数据将被加载到FIFO缓冲区中,如果在此寄存器中将传感器的相应FIFO_EN位设置为1。当在此寄存器中启用传感器的FIFO_EN位时,来自传感器数据寄存器的数据将被加载到FIFO缓冲区中。传感器按照寄存器25中定义的采样率进行采样。有关传感器数据寄存器的更多信息,请参阅寄存器59至96。

        当外部从设备的相应FIFO_EN位(SLVx_FIFO_EN,其中x=0、1或2)设置为1时,存储在其相应数据寄存器(EXT_SENS_DATA寄存器,寄存器73至96)中的数据将按照采样率写入FIFO缓冲区。EXT_SENS_DATA寄存器与I2C从设备的关联由I2C_SLVx_CTRL寄存器(其中x=0、1或2;寄存器39、42和45)确定。有关EXT_SENS_DATA寄存器的信息,请参阅寄存器73至96。请注意,相应的FIFO_EN位(SLV3_FIFO_EN)位于I2C_MST_CTRL(寄存器36)中。还请注意,从设备4的行为与从设备0-3不同。有关从设备4使用的更多信息,请参阅寄存器49至53。

作用:DMP计算

 用户控制寄存器配置

作用:该寄存器允许用户启用和禁用FIFO缓冲区、I2C主模式以及主I2C接口。FIFO缓冲区、I2C主设备、传感器信号路径和传感器寄存器也可以通过该寄存器进行复位。


介绍:

        当I2C_MST_EN设置为1时,I2C主模式被启用。在此模式下,MPU-60X0作为I2C主设备,控制辅助I2C总线上的外部传感器从设备。当该位被清除为0时,辅助I2C总线线路(AUX_DA和AUX_CL)由主I2C总线(SDA和SCL)逻辑驱动。这是启用旁路模式的前提条件。有关旁路模式的更多信息,请参阅寄存器55。

        MPU-6000: 参数: FIFO_EN I2C_MST_EN 当I2C_IF_DIS设置为1时,主SPI接口将启用,以替代被禁用的主I2C接口。

        MPU-6050 : 始终将I2C_IF_DIS写为0。当复位位(FIFO_RESET、I2C_MST_RESET和SIG_COND_RESET)设置为1时,这些复位位将触发复位,然后清除为0。位7和位3保留。

功能:使能I2C主模式


知识拓展AI解释:

I2C主模式(I2C Master Mode)​:

        当I2C_MST_EN置1时,MPU-60X0会作为I2C主设备控制辅助I2C总线(AUX_DA和AUX_CL),此时它可以主动与外部从设备(如磁力计或其他传感器)通信。

这种模式下:MPU通过辅助I2C总线直接读取/写入外部传感器的数据,无需主处理器干预。主处理器只需通过主I2C接口与MPU通信,由MPU完成多传感器数据采集和同步。

典型应用场景​:需要扩展9轴数据(如连接磁力计)时,MPU作为主设备自动管理数据传输,减轻主处理器负担。

旁路模式(Bypass Mode):​

        当I2C_MST_EN置0时,辅助I2C总线(AUX_DA和AUX_CL)会与主I2C总线(SDA和SCL)直连,此时: 主处理器可直接通过主I2C接口访问外部传感器,MPU仅作为透明通道。

必要条件​:除了I2C_MST_EN置0,还需确保I2C_SLV0_EN等从机模式相关寄存器禁用

应用场景​:需要主处理器直接控制外部传感器时(如调试或特殊通信协议)

 ​寄存器关联与控制逻辑:

        ​USER_CTRL寄存器(地址0x6A)​​:I2C_MST_EN是该寄存器的bit5位,需通过写入该寄存器进行配置

多主机支持​:若同时启用MUL_MST_EN(多主机使能位),MPU可与其他I2C主设备共享总线,但需注意总线仲裁机制

陀螺仪配置寄存器

功能:该寄存器用于触发陀螺仪自检并配置陀螺仪的全量程范围。


陀螺仪输出的满量程表

作用:配置陀螺仪的满量程,陀螺仪自检

加速度计配置寄存器 

功能:该寄存器用于触发加速度计自检并配置加速度计的全量程范围。该寄存器还配置数字高通滤波器(DHPF)。


加速度计输出的满量程表

作用:加速度计自检、加速度满量程配置、高通滤波器配置

加速度测量寄存器、陀螺仪测量寄存器、温度测量寄存器 

功能:这些寄存器存储最新的测量数据


注意:温度测量寄存器,加速度计测量寄存器、陀螺仪测量寄存器和外部传感器数据寄存器,都由两组寄存器组成:一组是内部寄存器组,另一组是面向用户的读取寄存器组。

传感器内部寄存器组中的数据始终以采样率更新。同时,当串行接口空闲时,面向用户的读取寄存器组会复制内部寄存器组的数据值。这确保了传感器寄存器的突发读取将读取同一采样时刻的测量值。请注意,如果不使用突发读取,用户有责任通过检查数据就绪中断来确保一组单字节读取对应于同一采样时刻。


原始数据转换成实际物理量:原始数据*配置量程的灵敏度=实际物理量

例如: 陀螺仪配置量程范围为±2000°/s,则换算为

            原始数据*16.4LSB/°/s=实际物理量

            加速度换算同理

注意:mpu芯片不同的温度转换不同

作用:获取传感器的读取数据

 MPU6050通信协议

 设备地址:0x68 

 MPU6050可以采用SPI和IIC(本次适用IIC)

知识拓展:【一文吃透】常见通信协议(SPI、IIC、UART、CAN)[面试重点]

  写操作

 读操作

协议层代码:软件模拟IIC-HAL库

注意:协议层代码的延时时间尽量短,但是要符合协议层的电气规范,即提高IIC的频率,否则在使用DMP库时,初始化会非常久,如果过不使用DMP库,使用其他方法(互补滤波、卡尔曼滤波),可以忽略。

应用层代码:


/*
 * 函数名称:MPU6050_Init
 * 功能描述:MPU6050连续写数据
 * 输入参数:register_address:寄存器地址
 *          send_data:要写入的数据的首地址
 *          len:写入数据的长度
 * 返回值:  0:成功,其他:失败
 */
uint8_t MPU6050_WriteMultipleBytes(uint8_t slave_address,uint8_t register_address, uint8_t len,uint8_t *send_data)
{
    IIC_Start();
    IIC_Send_Byte((slave_address << 1) | 0);
    if (IIC_Wait_Ack() != SUCCESS)
        return 1;
    IIC_Send_Byte(register_address);
    if (IIC_Wait_Ack() != SUCCESS)
        return 2;

    for (uint8_t i = 0; i < len; i++)
    {
        IIC_Send_Byte(send_data[i]);
        if (IIC_Wait_Ack() != SUCCESS)
            return 3;
    }

    IIC_Stop();
    return 0;
}

/*
 * 函数名称:MPU6050_ReadByte
 * 功能描述:MPU6050写入一个字节数据
 * 输入参数:register_address:寄存器地址
 *          send_data:要写入的数据
 * 返回值:  0:成功,其他:失败
*/
uint8_t MPU6050_WriteByte(uint8_t register_address, uint8_t send_data)
{
    IIC_Start();

    IIC_Send_Byte((MPU6050_DEVICE_ADDRESS << 1) | 0);
    if (IIC_Wait_Ack() != SUCCESS)
        return 1;

    IIC_Send_Byte(register_address);
    if (IIC_Wait_Ack() != SUCCESS)
        return 2;

    IIC_Send_Byte(send_data);
    if (IIC_Wait_Ack() != SUCCESS)
        return 3;

    IIC_Stop();
    return 0;
}

/*
 * 函数名称:MPU6050_ReadByte
 * 功能描述:MPU6050读一个字节数据
 * 输入参数:register_address:寄存器地址
 *          receive_data:接收到的数据
 *          len:读取数据的长度
 * 返回值:  0:成功,其他:失败
*/

uint8_t MPU6050_ReadByte(uint8_t register_address, uint8_t *receive_data)
{
    IIC_Start();

    IIC_Send_Byte((MPU6050_DEVICE_ADDRESS << 1) | 0);
    if (IIC_Wait_Ack() != SUCCESS)
        return 1;

    IIC_Send_Byte(register_address); // 发送要读取的寄存器地址
    if (IIC_Wait_Ack() != SUCCESS)
        return 2;

    IIC_Start();

    IIC_Send_Byte((MPU6050_DEVICE_ADDRESS << 1) | 1);
    if (IIC_Wait_Ack() != SUCCESS)
        return 3;

    *receive_data = IIC_Read_Byte();
    IIC_Send_NAck();

    IIC_Stop();
    return 0;
}

/*
 * 函数名称:MPU6050_ReadMultipleBytes
 * 功能描述:MPU6050连续读数据
 * 输入参数:register_address:寄存器地址
 *          receive_buff:接收数据缓存区的首地址
 *          len:读取数据的长度
 * 返回值:  0:成功,其他:失败
*/
uint8_t MPU6050_ReadMultipleBytes(uint8_t slave_address,uint8_t register_address,uint8_t len,uint8_t *receive_buff)
{
    IIC_Start();
    IIC_Send_Byte((slave_address << 1) | 0);
    if (IIC_Wait_Ack() != SUCCESS)
        return 1;
    IIC_Send_Byte(register_address);
    if (IIC_Wait_Ack() != SUCCESS)
        return 2;

    IIC_Start();
    IIC_Send_Byte((slave_address << 1) | 1);
    if (IIC_Wait_Ack() != SUCCESS)
        return 3;

    for (uint8_t i = 0; i < len; i++)
    {
        receive_buff[i] = IIC_Read_Byte();
        if (i < len - 1)
        {
            IIC_Send_Ack();
        }
        else
        {
            IIC_Send_NAck();
        }
    }
    IIC_Stop();
    return 0;
}

 MPU6050初始化步骤

1、硬件复位设备(防止残留数据干扰,注意:需要等待100ms复位)

2、解除休眠吗模式(复位后设备处于休眠状态)

3、设置加速计的量程

4、设置陀螺仪的量程

5、设置采样率

6、设置时钟源

7、启用加速度与陀螺仪都工作

关闭非必要功能

关闭所有中断(防止传输数据时,中断干扰)

关闭I2C主模式(如果没有外接磁力计可以关掉)

关闭FIFO(不使用DMP一般用不到)

uint8_t MPU6050_Init(void)
{
    uint8_t ID;

    IIC_Init();                            // 初始化IIC总线
    MPU6050_WriteByte(PWR_MGMT_1, 0x80);   // 复位MPU6050
    HAL_Delay(100);                        // 等待MPU6050复位
    MPU6050_WriteByte(PWR_MGMT_1, 0x00);   // 唤醒MPU6050
    MPU6050_SetAccelerometer_FullScaleRange(0); // 加速度传感器满量程范围±2g
    MPU6050_SetGyroscope_FullScaleRange(3); // 陀螺仪满量程范围±2000dps

    MPU6050_WriteByte(INT_ENABLE, 0X00); // 关闭所有中断
    MPU6050_WriteByte(USER_CTRL, 0X00);  // I2C主模式关闭
    MPU6050_WriteByte(FIFO_EN, 0X00);    // 关闭FIFO

    MPU6050_ReadByte(WHO_AM_I, &ID);    //读取器件ID
    if (ID == MPU6050_DEVICE_ADDRESS) // 器件ID正确
    {
        MPU6050_WriteByte(PWR_MGMT_1, 0X01); // 设置CLKSEL,PLL X轴为参考
        MPU6050_WriteByte(PWR_MGMT_2, 0X00); // 加速度与陀螺仪都工作
        MPU6050_Set_SamplingRate(200);       // 设置采样率为200Hz //每次读取数据间隔为5ms
    }
    else return 1;

    return 0;
}

使用到的方法


/*
 *函数名称:MPu6050_Set_LPF
 *功能描述:设置MPU6050的数字低通滤波器
 *输入参数:lpf:数字低通滤波频率(Hz)
 *返回值:  0:成功,其他:失败
 */
uint8_t MPU6050_Set_LPF(uint16_t lpf)
{
    uint8_t 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 MPU6050_WriteByte(CONFIG, data); // 设置数字低通滤波器
}
/*
 *函数名称:MPU6050_Set_SamplingRate
 *功能描述:设置MPU6050的采样率
 *输入参数:rate:采样率(Hz)
 *返回值:  0:成功,其他:失败
 */
uint8_t MPU6050_SetSamplingRate(uint16_t rate)
{
    if (rate > 1000)
        rate = 1000; // 最大值
    if (rate < 4)
        rate = 4; // 最小值 为什么是4因为:2的8次方-1,所以分频系数范围为 0-255 即采样率最小为1000/256=3.9Hz 取整为4Hz
    MPU6050_WriteByte(SMPLRT_DIV, 1000 / rate - 1); // 设置采样率
    return MPU6050_Set_LPF(rate / 2);    // 自动设置LPF为采样率的一半
}


/*
 * 函数名称:MPU6050_SetGyroscope_FullScaleRange
 * 功能描述:设置MPU6050陀螺仪的满量程范围
 * 输入参数:range:陀螺仪的满量程范围  (±250dps、±500dps、±1000dps、±2000dps) = (0、1、2、3)
 * 返回值:  0:成功,其他:失败
 */
uint8_t MPU6050_SetGyroscope_FullScaleRange(uint8_t range)
{
    return MPU6050_WriteByte(GYRO_CONFIG, range << 3); // 设置陀螺仪满量程范围
}


/*
 * 函数名称: MPU6050_SetAccelerometer_FullScaleRange
 * 功能描述:设置MPU6050加速度传感器的满量程范围
 * 输入参数:range:加速度传感器的满量程范围 (±2g、±4g、±8g、±16g) = (0、1、2、3)
 * 返回值:  0:成功,其他:失败
 */
uint8_t MPU6050_SetAccelerometer_FullScaleRange(uint8_t range)
{
    return MPU6050_WriteByte(ACCEL_CONFIG, range << 3); // 设置加速度传感器满量程范围
}

拓展:滤波器的滤波最好取采样率的一半(根据图表选择最近的滤波参数)

疑问:为什么量程范围选±2g和±2000dbs

解释:量程范围的选定,需要的是陀螺仪和加速度计再实际情况中,一瞬间所可能达到的值小于选定范围。 

MPU6050陀螺仪和加速度计数据以温度的解析

1、读取寄存器原始数据

/*
 *函数名称:MPU6050_GetTemperature_raw
 *功能描述:MPU6050获取温度原始数据
 *输入参数:temperature:温度数据
 *返回值:  0:成功,其他:失败
 */
uint8_t MPU6050_GetTemperature_raw(short *temperature)
{

    uint8_t temperature_data_buff[2];
    uint8_t result = MPU6050_ReadMultipleBytes(MPU6050_DEVICE_ADDRESS,TEMP_OUT_H,6 ,temperature_data_buff);
    if (result == 0)
    {
       *temperature= ((uint16_t)temperature_data_buff[0] << 8) | temperature_data_buff[1];
    }
    return result;
}
/*
 * 函数名称:MPU6050_GetGyroscope_Raw
 * 功能描述:MPU6050获取陀螺仪原始数据
 * 输入参数:gx:x轴陀螺仪原始数据
 *          gy:y轴陀螺仪原始数据
 *          gz:z轴陀螺仪原始数据
 * 返回值:  0:成功,其他:失败
 */
uint8_t MPU6050_GetGyroscope_Raw(short *gx, short *gy, short *gz)
{
    uint8_t gyroscope_data_buff[6];
    uint8_t result = MPU6050_ReadMultipleBytes(MPU6050_DEVICE_ADDRESS,GYRO_XOUT_H,6,gyroscope_data_buff);
    if (result == 0)
    {
        *gx = ((uint16_t)gyroscope_data_buff[0] << 8) | gyroscope_data_buff[1];
        *gy = ((uint16_t)gyroscope_data_buff[2] << 8) | gyroscope_data_buff[3];
        *gz = ((uint16_t)gyroscope_data_buff[4] << 8) | gyroscope_data_buff[5];
    }
        return result;
}

/*
 *函数名称:MPU6050_GetAccelerometer_Raw
 *功能描述:MPU6050获取加速度计原始数据
 *输入参数:ax:x轴加速度计原始数据
 *          ay:y轴加速度计原始数据
 *          az:z轴加速度计原始数据
 * 返回值:  0:成功,其他:失败
 */
uint8_t MPU6050_GetAccelerometer_Raw(short *ax, short *ay,short *az)
{
    
    uint8_t accelerometer_data_buff[6];
    uint8_t result = MPU6050_ReadMultipleBytes(MPU6050_DEVICE_ADDRESS,ACCEL_XOUT_H, 6 ,accelerometer_data_buff);
    if (result == 0)
    {
        *ax = ((uint16_t)accelerometer_data_buff[0] << 8) | accelerometer_data_buff[1];
        *ay = ((uint16_t)accelerometer_data_buff[2] << 8) | accelerometer_data_buff[3];
        *az = ((uint16_t)accelerometer_data_buff[4] << 8) | accelerometer_data_buff[5];
    }
    return result;
}

2、解析原始数据换算物理量


#define ACCEL_RANGE 0 //加速度计范围
#define GYRO_RANGE  3 //陀螺仪范围

typedef struct
{
    short ax_raw, ay_raw, az_raw, gx_raw, gy_raw, gz_raw;
    float ax, ay, az, gx, gy, gz;
    float gyro_pitch, gyro_roll, gyro_yaw;
    float acce_pitch, acce_roll, acce_yaw;
    float temperature;
    float pitch, roll, yaw;
} MPU6050_DataStruct;
//注意读取的要根据采样率来读取
void MPU6050_UpData(MPU6050_DataStruct * mpu6050_data)
{
    float acce_sens,gyro_sens;
    MPU6050_GetGyroscope_Raw(&mpu6050_data->gx_raw, &mpu6050_data->gy_raw, &mpu6050_data->gz_raw);
    MPU6050_GetAccelerometer_Raw(&mpu6050_data->ax_raw, &mpu6050_data->ay_raw, &mpu6050_data->az_raw);
    MPU6050_GetTemperature_raw(&mpu6050_data->temperature);
    switch (ACCEL_RANGE)
    {
        case 0: acce_sens = 16384.0f; break;// 32768/2
        case 1: acce_sens = 8192.0f; break;
        case 2: acce_sens = 4096.0f; break;
        case 3: acce_sens = 2048.0f; break;
    }
    switch (GYRO_RANGE)
    {
        case 0: gyro_sens = 131.0f; break;// 32768/250
        case 1: gyro_sens = 65.5f; break;
        case 2: gyro_sens = 32.8f; break;
        case 3: gyro_sens = 16.4f; break;
    }
    //单位g
    mpu6050_data->ax = mpu6050_data->ax_raw / acce_sens;
    mpu6050_data->ay = mpu6050_data->ay_raw / acce_sens;
    mpu6050_data->az = mpu6050_data->az_raw / acce_sens;

    //单位°/s
    mpu6050_data->gx = mpu6050_data->gx_raw / gyro_sens;
    mpu6050_data->gy = mpu6050_data->gy_raw / gyro_sens;
    mpu6050_data->gz = mpu6050_data->gz_raw / gyro_sens;

    mpu6050_data->temperature = mpu6050_data->temperature / 340.0f + 36.53f;
}

解析数据的换算根据数据手册提供方法进行换算

欧拉角的获取

俯仰角pitch

翻滚角roll

偏航角yaw

陀螺仪加速度计角度获取

/*
 *函数名称:MPU6050_GetEulerAngle
 *功能描述:获取欧拉角
 *输入参数:mpu6050_data:MPU6050数据结构体指针
 *返回值:  无
 */

void MPU6050_GetEulerAngle(MPU6050_DataStruct *mpu6050_data)
{
    float dt = 0.005f;       // 1/200hz

    // 根据角速度计算角度
    mpu6050_data->gyro_pitch += mpu6050_data->gx * dt;
    mpu6050_data->gyro_roll += mpu6050_data->gy * dt;
    mpu6050_data->gyro_yaw += mpu6050_data->gz * dt; // 单位°

    mpu6050_data->acce_pitch = atan2(mpu6050_data->ay,mpu6050_data->az) * 57.2958f;// 弧度转角度 180/pi
    mpu6050_data->acce_roll = atan2(mpu6050_data->ax, mpu6050_data->az) * 57.2958f;
    mpu6050_data->acce_yaw = 0;
}

加速度计获取的欧拉角由于构造原因容易受噪声(振动)影响,高频性能差,低频性能稳定。

陀螺仪获取的欧拉角由于采用积分换算,会累积误差,时间一长会数据与实际值误差大,不可信,存在零漂,但是比较平滑

滤波算法

由于陀螺仪和加速度计获取的到的角度优点不同,我们可以综合加速度计和陀螺仪得到的欧拉角,进行一些控制的滤波和校准

MPU6050常见的滤波算法

1、DMP滤波算法(官方有DMP库,最简单)

2、互补滤波算法 (没有磁力计最好还是别用)          

飞控算法-姿态解算之互补滤波

互补滤波原理

3、卡尔曼滤波(需要数学功底)

因为刚开始使用互补滤波,不过效果不太理想,再加上我解算的欧拉角也不太准确(翻转90°最大得到84°),掉坑里太久了,不能太耗时间,就简单做个笔记,有空在研究,了解以下它的底层驱动就行了,最后发现还是官方的DMP库香。

DMP

完整代码

mpu6050.h

#ifndef _MPU6050_H_
#define _MPU6050_H_

#include "iic_hal.h"

#define MPU6050_DEVICE_ADDRESS 0x68 // b1101 000x

#define AUX_VDDIO 0X01 // 辅助电源电压寄存器

#define SMPLRT_DIV 0X19 // 采样频率分频器寄存器
#define CONFIG 0X1A // 配置寄存器
#define GYRO_CONFIG 0X1B // 陀螺仪配置寄存器
#define ACCEL_CONFIG 0X1C // 加速度计配置寄存器

#define FF_THR 0X1D // 自由落体阈值寄存器
#define FF_COUNT 0X20 // 自由落体计数寄存器
#define FF_CONFIG 0X21 // 自由落体配置寄存器
#define MOT_THR 0X1F // 运动阈值寄存器
#define MOT_DUR 0X20 // 运动持续时间寄存器
#define ZRMOT_THR 0X22 // 零运动阈值寄存器
#define ZRMOT_DUR 0X23 // 零运动持续时间寄存器
#define FIFO_EN 0X23 // FIFO使能寄存器
#define I2C_MST_CTRL 0X24 // I2C主机控制寄存器
#define I2C_SLV0_ADDR 0X25 // I2C从设备0地址寄存器
#define I2C_SLV0_REG 0X26 // I2C从设备0数据寄存器
#define I2C_SLV0_CTRL 0X27 // I2C从设备0控制寄存器
#define I2C_SLV1_ADDR 0X28 // I2C从设备1地址寄存器
#define I2C_SLV1_REG 0X29 // I2C从设备1数据寄存器
#define I2C_SLV1_CTRL 0X2A // I2C从设备1控制寄存器
#define I2C_SLV2_ADDR 0X2B // I2C从设备2地址寄存器
#define I2C_SLV2_REG 0X2C // I2C从设备2数据寄存器
#define I2C_SLV2_CTRL 0X2D // I2C从设备2控制寄存器
#define I2C_SLV3_ADDR 0X2E // I2C从设备3地址寄存器
#define I2C_SLV3_REG 0X2F // I2C从设备3数据寄存器
#define I2C_SLV3_CTRL 0X30 // I2C从设备3控制寄存器
#define I2C_SLV4_ADDR 0X31 // I2C从设备4地址寄存器
#define I2C_SLV4_REG 0X32 // I2C从设备4数据寄存器
#define I2C_SLV4_DO 0X33 // I2C从设备4输出数据寄存器
#define I2C_SLV4_CTRL 0X34 // I2C从设备4控制寄存器
#define I2C_SLV4_DI 0X35 // I2C从设备4输入数据寄存器
#define I2C_MST_STATUS 0X36 // I2C主机状态寄存器
#define INT_PIN_CFG 0X37 // 中断引脚配置寄存器

#define INT_ENABLE 0X38 // 中断使能寄存器
#define DMP_INT_STATUS 0X39 // DMP中断状态寄存器
#define INT_STATUS 0X3A // 中断状态寄存器

#define ACCEL_XOUT_H 0X3B // 加速度计X轴高字节寄存器
#define ACCEL_XOUT_L 0X3C // 加速度计X轴低字节寄存器
#define ACCEL_YOUT_H 0X3D // 加速度计Y轴高字节寄存器
#define ACCEL_YOUT_L 0X3E // 加速度计Y轴低字节寄存器
#define ACCEL_ZOUT_H 0X3F // 加速度计Z轴高字节寄存器
#define ACCEL_ZOUT_L 0X40 // 加速度计Z轴低字节寄存器
#define TEMP_OUT_H 0X41 // 温度高字节寄存器
#define TEMP_OUT_L 0X42 // 温度低字节寄存器
#define GYRO_XOUT_H 0X43 // 陀螺仪X轴高字节寄存器
#define GYRO_XOUT_L 0X44 // 陀螺仪X轴低字节寄存器
#define GYRO_YOUT_H 0X45 // 陀螺仪Y轴高字节寄存器
#define GYRO_YOUT_L 0X46 // 陀螺仪Y轴低字节寄存器
#define GYRO_ZOUT_H 0X47 // 陀螺仪Z轴高字节寄存器
#define GYRO_ZOUT_L 0X48 // 陀螺仪Z轴低字节寄存器

#define EXT_SENS_DATA_00 0X49 // 外部传感器数据00寄存器
#define EXT_SENS_DATA_01 0X4A // 外部传感器数据01寄存器
#define EXT_SENS_DATA_02 0X4B // 外部传感器数据02寄存器
#define EXT_SENS_DATA_03 0X4C // 外部传感器数据03寄存器
#define EXT_SENS_DATA_04 0X4D // 外部传感器数据04寄存器
#define EXT_SENS_DATA_05 0X4E // 外部传感器数据05寄存器
#define EXT_SENS_DATA_06 0X4F // 外部传感器数据06寄存器
#define EXT_SENS_DATA_07 0X50 // 外部传感器数据07寄存器
#define EXT_SENS_DATA_08 0X51 // 外部传感器数据08寄存器
#define EXT_SENS_DATA_09 0X52 // 外部传感器数据09寄存器
#define EXT_SENS_DATA_10 0X53 // 外部传感器数据10寄存器
#define EXT_SENS_DATA_11 0X54 // 外部传感器数据11寄存器
#define EXT_SENS_DATA_12 0X55 // 外部传感器数据12寄存器
#define EXT_SENS_DATA_13 0X56 // 外部传感器数据13寄存器
#define EXT_SENS_DATA_14 0X57 // 外部传感器数据14寄存器
#define EXT_SENS_DATA_15 0X58 // 外部传感器数据15寄存器
#define EXT_SENS_DATA_16 0X59 // 外部传感器数据16寄存器
#define EXT_SENS_DATA_17 0X5A // 外部传感器数据17寄存器
#define EXT_SENS_DATA_18 0X5B // 外部传感器数据18寄存器
#define EXT_SENS_DATA_19 0X5C // 外部传感器数据19寄存器
#define EXT_SENS_DATA_20 0X5D // 外部传感器数据20寄存器
#define EXT_SENS_DATA_21 0X5E // 外部传感器数据21寄存器
#define EXT_SENS_DATA_22 0X5F // 外部传感器数据22寄存器
#define EXT_SENS_DATA_23 0X60 // 外部传感器数据23寄存器

#define MOT_DETECT_STATUS 0X61 // 运动检测状态寄存器
#define I2C_SLV0_DO 0X63 // I2C从设备0输出数据寄存器
#define I2C_SLV1_DO 0X64 // I2C从设备1输出数据寄存器
#define I2C_SLV2_DO 0X65 // I2C从设备2输出数据寄存器
#define I2C_SLV3_DO 0X66 // I2C从设备3输出数据寄存器
#define I2C_MST_DELAY_CTRL 0X67 // I2C主机延迟控制寄存器
#define SIGNAL_PATH_RESET 0X68 // 信号路径重置寄存器
#define MOT_DETECT_CTRL 0X69 // 运动检测控制寄存器
#define USER_CTRL 0X6A // 用户控制寄存器

#define PWR_MGMT_1 0X6B // 电源管理1寄存器
#define PWR_MGMT_2 0X6C // 电源管理2寄存器

#define FIFO_COUNT_H 0X72 // FIFO计数高字节寄存器
#define FIFO_COUNT_L 0X73 // FIFO计数低字节寄存器
#define FIFO_R_W 0X74 // FIFO读写寄存器

#define WHO_AM_I 0X75 // 谁是我寄存器,用于设备识别

uint8_t MPU6050_WriteMultipleBytes(uint8_t slave_address, uint8_t register_address, uint8_t len, uint8_t *send_data);
uint8_t MPU6050_ReadMultipleBytes(uint8_t slave_address, uint8_t register_address, uint8_t len, uint8_t *receive_buff);

uint8_t MPU6050_WriteByte(uint8_t register_address, uint8_t send_data);
uint8_t MPU6050_ReadByte(uint8_t register_address, uint8_t *receive_data);

void MPU6050_Init(void);

uint8_t MPU6050_Set_LPF(uint16_t lpf);
uint8_t MPU6050_SetSamplingRate(uint16_t rate);
uint8_t MPU6050_SetGyroscope_FullScaleRange(uint8_t range)
uint8_t MPU6050_SetAccelerometer_FullScaleRange(uint8_t range);

uint8_t MPU6050_GetTemperature_raw(short *temperature);
uint8_t MPU6050_GetGyroscope_Raw(short *gx, short *gy, short *gz);
uint8_t MPU6050_GetAccelerometer_Raw(short *ax, short *ay, short *az);




#endif

mpu6050.c

#include "mpu6050.h"
#include "stdio.h"
#include "math.h"

#define ACCEL_RANGE 0 // 加速度计范围
#define GYRO_RANGE 3  // 陀螺仪范围

#define MY_FILTER 0

/*
 * 函数名称:MPU6050_Init
 * 功能描述:MPU6050连续写数据
 * 输入参数:register_address:寄存器地址
 *          send_data:要写入的数据的首地址
 *          len:写入数据的长度
 * 返回值:  0:成功,其他:失败
 */
uint8_t MPU6050_WriteMultipleBytes(uint8_t slave_address, uint8_t register_address, uint8_t len, uint8_t *send_data)
{
    IIC_Start();
    IIC_Send_Byte((slave_address << 1) | 0);
    if (IIC_Wait_Ack() != SUCCESS)
        return 1;
    IIC_Send_Byte(register_address);
    if (IIC_Wait_Ack() != SUCCESS)
        return 2;

    for (uint8_t i = 0; i < len; i++)
    {
        IIC_Send_Byte(send_data[i]);
        if (IIC_Wait_Ack() != SUCCESS)
            return 3;
    }

    IIC_Stop();
    return 0;
}

/*
 * 函数名称:MPU6050_ReadByte
 * 功能描述:MPU6050写入一个字节数据
 * 输入参数:register_address:寄存器地址
 *          send_data:要写入的数据
 * 返回值:  0:成功,其他:失败
 */
uint8_t MPU6050_WriteByte(uint8_t register_address, uint8_t send_data)
{
    IIC_Start();

    IIC_Send_Byte((MPU6050_DEVICE_ADDRESS << 1) | 0);
    if (IIC_Wait_Ack() != SUCCESS)
        return 1;

    IIC_Send_Byte(register_address);
    if (IIC_Wait_Ack() != SUCCESS)
        return 2;

    IIC_Send_Byte(send_data);
    if (IIC_Wait_Ack() != SUCCESS)
        return 3;

    IIC_Stop();
    return 0;
}

/*
 * 函数名称:MPU6050_ReadByte
 * 功能描述:MPU6050读一个字节数据
 * 输入参数:register_address:寄存器地址
 *          receive_data:接收到的数据
 *          len:读取数据的长度
 * 返回值:  0:成功,其他:失败
 */

uint8_t MPU6050_ReadByte(uint8_t register_address, uint8_t *receive_data)
{
    IIC_Start();

    IIC_Send_Byte((MPU6050_DEVICE_ADDRESS << 1) | 0);
    if (IIC_Wait_Ack() != SUCCESS)
        return 1;

    IIC_Send_Byte(register_address); // 发送要读取的寄存器地址
    if (IIC_Wait_Ack() != SUCCESS)
        return 2;

    IIC_Start();

    IIC_Send_Byte((MPU6050_DEVICE_ADDRESS << 1) | 1);
    if (IIC_Wait_Ack() != SUCCESS)
        return 3;

    *receive_data = IIC_Read_Byte();
    IIC_Send_NAck();

    IIC_Stop();
    return 0;
}

/*
 * 函数名称:MPU6050_ReadMultipleBytes
 * 功能描述:MPU6050连续读数据
 * 输入参数:register_address:寄存器地址
 *          receive_buff:接收数据缓存区的首地址
 *          len:读取数据的长度
 * 返回值:  0:成功,其他:失败
 */
uint8_t MPU6050_ReadMultipleBytes(uint8_t slave_address, uint8_t register_address, uint8_t len, uint8_t *receive_buff)
{
    IIC_Start();
    IIC_Send_Byte((slave_address << 1) | 0);
    if (IIC_Wait_Ack() != SUCCESS)
        return 1;
    IIC_Send_Byte(register_address);
    if (IIC_Wait_Ack() != SUCCESS)
        return 2;

    IIC_Start();
    IIC_Send_Byte((slave_address << 1) | 1);
    if (IIC_Wait_Ack() != SUCCESS)
        return 3;

    for (uint8_t i = 0; i < len; i++)
    {
        receive_buff[i] = IIC_Read_Byte();
        if (i < len - 1)
        {
            IIC_Send_Ack();
        }
        else
        {
            IIC_Send_NAck();
        }
    }
    IIC_Stop();
    return 0;
}


/*
 *函数名称:MPu6050_Set_LPF
 *功能描述:设置MPU6050的数字低通滤波器
 *输入参数:lpf:数字低通滤波频率(Hz)
 *返回值:  0:成功,其他:失败
 */
uint8_t MPU6050_Set_LPF(uint16_t lpf)
{
    uint8_t 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 MPU6050_WriteByte(CONFIG, data); // 设置数字低通滤波器
	
}

/*
 *函数名称:MPU6050_Set_SamplingRate
 *功能描述:设置MPU6050的采样率
 *输入参数:rate:采样率(Hz)
 *返回值:  0:成功,其他:失败
 */
uint8_t MPU6050_SetSamplingRate(uint16_t rate)
{
    if (rate > 1000)
        rate = 1000; // 最大值
    if (rate < 4)
        rate = 4;                                   // 最小值 为什么是4因为:2的8次方-1,所以分频系数范围为 0-255 即采样率最小为1000/256=3.9Hz 取整为4Hz
    MPU6050_WriteByte(SMPLRT_DIV, 1000 / rate - 1); // 设置采样率
    return MPU6050_Set_LPF(rate / 2);               // 自动设置LPF为采样率的一半
}




/*
 * 函数名称:MPU6050_SetGyroscope_FullScaleRange
 * 功能描述:设置MPU6050陀螺仪的满量程范围
 * 输入参数:range:陀螺仪的满量程范围  (±250dps、±500dps、±1000dps、±2000dps) = (0、1、2、3)
 * 返回值:  0:成功,其他:失败
 */
uint8_t MPU6050_SetGyroscope_FullScaleRange(uint8_t range)
{
    return MPU6050_WriteByte(GYRO_CONFIG, range << 3); // 设置陀螺仪满量程范围
}

/*
 * 函数名称: MPU6050_SetAccelerometer_FullScaleRange
 * 功能描述:设置MPU6050加速度传感器的满量程范围
 * 输入参数:range:加速度传感器的满量程范围 (±2g、±4g、±8g、±16g) = (0、1、2、3)
 * 返回值:  0:成功,其他:失败
 */
uint8_t MPU6050_SetAccelerometer_FullScaleRange(uint8_t range)
{
    return MPU6050_WriteByte(ACCEL_CONFIG, range << 3); // 设置加速度传感器满量程范围
}

/*
 *函数名称:MPU6050_GetTemperature_raw
 *功能描述:MPU6050获取温度原始数据
 *输入参数:temperature:温度数据
 *返回值:  0:成功,其他:失败
 */
uint8_t MPU6050_GetTemperature_raw(short *temperature)
{

    uint8_t temperature_data_buff[2];
    uint8_t result = MPU6050_ReadMultipleBytes(MPU6050_DEVICE_ADDRESS, TEMP_OUT_H, 2, temperature_data_buff);
    if (result == 0)
    {
        *temperature = ((uint16_t)temperature_data_buff[0] << 8) | temperature_data_buff[1];
    }
    return result;
}
/*
 * 函数名称:MPU6050_GetGyroscope_Raw
 * 功能描述:MPU6050获取陀螺仪原始数据
 * 输入参数:gx:x轴陀螺仪原始数据
 *          gy:y轴陀螺仪原始数据
 *          gz:z轴陀螺仪原始数据
 * 返回值:  0:成功,其他:失败
 */
uint8_t MPU6050_GetGyroscope_Raw(short *gx, short *gy, short *gz)
{
    uint8_t gyroscope_data_buff[6];
    uint8_t result = MPU6050_ReadMultipleBytes(MPU6050_DEVICE_ADDRESS, GYRO_XOUT_H, 6, gyroscope_data_buff);
    if (result == 0)
    {
        *gx = ((uint16_t)gyroscope_data_buff[0] << 8) | gyroscope_data_buff[1];
        *gy = ((uint16_t)gyroscope_data_buff[2] << 8) | gyroscope_data_buff[3];
        *gz = ((uint16_t)gyroscope_data_buff[4] << 8) | gyroscope_data_buff[5];
    }
    return result;
}

/*
 *函数名称:MPU6050_GetAccelerometer_Raw
 *功能描述:MPU6050获取加速度计原始数据
 *输入参数:ax:x轴加速度计原始数据
 *          ay:y轴加速度计原始数据
 *          az:z轴加速度计原始数据
 * 返回值:  0:成功,其他:失败
 */
uint8_t MPU6050_GetAccelerometer_Raw(short *ax, short *ay, short *az)
{

    uint8_t accelerometer_data_buff[6];
    uint8_t result = MPU6050_ReadMultipleBytes(MPU6050_DEVICE_ADDRESS, ACCEL_XOUT_H, 6, accelerometer_data_buff);
    if (result == 0)
    {
        *ax = ((uint16_t)accelerometer_data_buff[0] << 8) | accelerometer_data_buff[1];
        *ay = ((uint16_t)accelerometer_data_buff[2] << 8) | accelerometer_data_buff[3];
        *az = ((uint16_t)accelerometer_data_buff[4] << 8) | accelerometer_data_buff[5];
    }
    return result;
}



/*
 *函数名称:MPU6050_Init
 *功能描述:初始化MPU6050
 *输入参数:无
 *返回值:  0:成功,其他:失败
 */
uint8_t MPU6050_Init(void)
{
    uint8_t ID;

    IIC_Init();                                           // 初始化IIC总线
    MPU6050_WriteByte(PWR_MGMT_1, 0x80);                  // 复位MPU6050
    HAL_Delay(100);                                       // 等待MPU6050复位
    MPU6050_WriteByte(PWR_MGMT_1, 0x00);                  // 唤醒MPU6050
    MPU6050_SetAccelerometer_FullScaleRange(ACCEL_RANGE); // 加速度传感器满量程范围±2g
    MPU6050_SetGyroscope_FullScaleRange(GYRO_RANGE);      // 陀螺仪满量程范围±2000dps

    MPU6050_WriteByte(INT_ENABLE, 0X00); // 关闭所有中断
    MPU6050_WriteByte(USER_CTRL, 0X00);  // I2C主模式关闭
    MPU6050_WriteByte(FIFO_EN, 0X00);    // 关闭FIFO

    MPU6050_ReadByte(WHO_AM_I, &ID);  // 读取器件ID
    if (ID == MPU6050_DEVICE_ADDRESS) // 器件ID正确
    {
        MPU6050_WriteByte(PWR_MGMT_1, 0X01); // 设置CLKSEL,PLL X轴为参考
        MPU6050_WriteByte(PWR_MGMT_2, 0X00); // 加速度与陀螺仪都工作
        MPU6050_SetSamplingRate(200);        // 设置采样率为200Hz //每次读取数据间隔为5ms
    }
    else
        return 1;

    return 0;
}

本文章已经生成可运行项目
### Arduino 平台上使用 MPU6050 陀螺仪加速度计的代码及实现方法 以下内容详细介绍了如何在 Arduino 平台上使用 MPU6050 加速度计陀螺仪传感器,包括硬件连接、代码示例以及相关注意事项。 #### 硬件连接 MPU6050 是一款集成了三轴加速度计和三轴陀螺仪的模块,通常通过 I2C 协议与 Arduino 进行通信。以下是常见的硬件连接方式[^1]: - **VCC**:连接到 Arduino 的 3.3V 引脚(注意不要连接到 5V,因为 MPU6050 的工作电压为 3.3V)。 - **GND**:连接到 Arduino 的 GND 引脚。 - **SDA**:连接到 Arduino 的 A4 引脚(用于 I2C 数据传输)。 - **SCL**:连接到 Arduino 的 A5 引脚(用于 I2C 时钟信号)。 - **AD0**:通常接地(GND),此时 MPU6050 的 I2C 地址为 `0x68`;如果接高电平,则地址为 `0x69`[^2]。 #### 示例代码 以下是一个完整的 Arduino 示例代码,用于读取 MPU6050 的加速度和角速度数据[^1]。 ```cpp #include <Wire.h> #include <I2Cdev.h> #include <MPU6050.h> // 初始化 MPU6050 对象 MPU6050 mpu; // 定义变量存储加速度和角速度数据 int16_t ax, ay, az; int16_t gx, gy, gz; void setup() { Serial.begin(9600); // 初始化串口通信 Wire.begin(); // 初始化 I2C 通信 // 检测 MPU6050 是否连接成功 if (!mpu.testConnection()) { Serial.println("MPU6050 连接失败"); while (1) {} } // 初始化 MPU6050 mpu.initialize(); mpu.setFullScaleGyroRange(MPU6050_GYRO_FS_2000); // 设置陀螺仪量程为 ±2000 度/秒 mpu.setFullScaleAccelRange(MPU6050_ACCEL_FS_16); // 设置加速度计量程为 ±16g } void loop() { // 读取加速度和角速度数据 mpu.getMotion6(&ax, &ay, &az, &gx, &gy, &gz); // 打印数据到串口监视器 Serial.print("加速度: "); Serial.print(ax); Serial.print(", "); Serial.print(ay); Serial.print(", "); Serial.println(az); Serial.print("角速度: "); Serial.print(gx); Serial.print(", "); Serial.print(gy); Serial.print(", "); Serial.println(gz); delay(100); // 延时 100 毫秒 } ``` #### 实现方法详解 上述代码中使用了 `I2Cdev` 和 `MPU6050` 库来简化对 MPU6050 的操作。以下是关键点的解释: - **库的安装**:需要先下载并安装 `I2Cdev` 和 `MPU6050` 库。可以通过 Arduino IDE 的库管理器搜索并安装这些库。 - **初始化**:`mpu.initialize()` 方法用于初始化 MPU6050,并设置默认参数。 - **设置量程**:通过 `setFullScaleGyroRange` 和 `setFullScaleAccelRange` 方法分别设置陀螺仪加速度计的量程[^1]。 - **读取数据**:`getMotion6` 方法可以同时读取加速度和角速度数据,并将结果存储在指定的变量中。 #### 注意事项 1. 确保 MPU6050 的供电电压为 3.3V,避免因电压过高导致模块损坏[^1]。 2. 如果使用不同的开发板(如 ESP8266 或 ESP32),需确认 I2C 引脚的对应关系。 3. 在实际应用中,可能需要对原始数据进行滤波或校准以提高精度[^1]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值