STM32F407软件模拟I2C实现MPU6050通讯(CUBEIDE)

STM32F407软件模拟I2C实现MPU6050通讯(CUBEIDE)


文章目录

  • STM32F407软件模拟I2C实现MPU6050通讯(CUBEIDE)
  • 模拟I2C读写的实现
    • mpu6050_iic.c
    • mpu6050_iic.h
    • 代码分析
  • 复位,读取温度,角度等函数封装
    • mpu6050.c
    • mpu6050.h
    • 代码分析
  • DMP移植
    • 1.修改头文件路径为自己的头文件路径
    • 2.修改I2C读写函数为自己mcu平台的读写函数
    • 3.修改延时函数为自己平台的延时函数
  • 使用实例


代码工程
https://download.csdn.net/download/weixin_52849254/87886797

模拟I2C读写的实现

mpu6050_iic.c

/**
 ****************************************************************************************************
 * @file        mpu6050_iic.c
 * @version     V1.0
 * @date        2022-06-21

 *
 ****************************************************************************************************
 */

#include "mpu6050_iic.h"
#include "main.h"

/**
 * @brief       IIC接口延时函数,用于控制IIC读写速度
 * @param       无
 * @retval      无
 */
static inline void mpu6050_iic_delay(void)
{
    delay_us(2);
}

/**
 * @brief       产生IIC起始信号
 * @param       无
 * @retval      无
 */
void mpu6050_iic_start(void)
{
    MPU6050_IIC_SDA(1);
    MPU6050_IIC_SCL(1);
    mpu6050_iic_delay();
    MPU6050_IIC_SDA(0);
    mpu6050_iic_delay();
    MPU6050_IIC_SCL(0);
    mpu6050_iic_delay();
}

/**
 * @brief       产生IIC停止信号
 * @param       无
 * @retval      无
 */
void mpu6050_iic_stop(void)
{
    MPU6050_IIC_SDA(0);
    mpu6050_iic_delay();
    MPU6050_IIC_SCL(1);
    mpu6050_iic_delay();
    MPU6050_IIC_SDA(1);
    mpu6050_iic_delay();
}

/**
 * @brief       等待IIC应答信号
 * @param       无
 * @retval      0: 应答信号接收成功
 *              1: 应答信号接收失败
 */
uint8_t mpu6050_iic_wait_ack(void)
{
    uint8_t waittime = 0;
    uint8_t rack = 0;
    
    MPU6050_IIC_SDA(1);
    mpu6050_iic_delay();
    MPU6050_IIC_SCL(1);
    mpu6050_iic_delay();
    
    while (MPU6050_IIC_READ_SDA())
    {
        waittime++;
        
        if (waittime > 250)
        {
            mpu6050_iic_stop();
            rack = 1;
            break;
        }
    }
    
    MPU6050_IIC_SCL(0);
    mpu6050_iic_delay();
    
    return rack;
}

/**
 * @brief       产生ACK应答信号
 * @param       无
 * @retval      无
 */
void mpu6050_iic_ack(void)
{
    MPU6050_IIC_SDA(0);
    mpu6050_iic_delay();
    MPU6050_IIC_SCL(1);
    mpu6050_iic_delay();
    MPU6050_IIC_SCL(0);
    mpu6050_iic_delay();
    MPU6050_IIC_SDA(1);
    mpu6050_iic_delay();
}

/**
 * @brief       不产生ACK应答信号
 * @param       无
 * @retval      无
 */
void mpu6050_iic_nack(void)
{
    MPU6050_IIC_SDA(1);
    mpu6050_iic_delay();
    MPU6050_IIC_SCL(1);
    mpu6050_iic_delay();
    MPU6050_IIC_SCL(0);
    mpu6050_iic_delay();
}

/**
 * @brief       IIC发送一个字节
 * @param       dat: 要发送的数据
 * @retval      无
 */
void mpu6050_iic_send_byte(uint8_t dat)
{
    uint8_t t;
    
    for (t=0; t<8; t++)
    {
        MPU6050_IIC_SDA((dat & 0x80) >> 7);
        mpu6050_iic_delay();
        MPU6050_IIC_SCL(1);
        mpu6050_iic_delay();
        MPU6050_IIC_SCL(0);
        dat <<= 1;
    }
    MPU6050_IIC_SDA(1);
}

/**
 * @brief       IIC接收一个字节
 * @param       ack: ack=1时,发送ack; ack=0时,发送nack
 * @retval      接收到的数据
 */
uint8_t mpu6050_iic_read_byte(uint8_t ack)
{
    uint8_t i;
    uint8_t dat = 0;
    
    for (i = 0; i < 8; i++ )
    {
        dat <<= 1;
        MPU6050_IIC_SCL(1);
        mpu6050_iic_delay();
        
        if (MPU6050_IIC_READ_SDA())
        {
            dat++;
        }
        
        MPU6050_IIC_SCL(0);
        mpu6050_iic_delay();
    }
    
    if (ack == 0)
    {
        mpu6050_iic_nack();
    }
    else
    {
        mpu6050_iic_ack();
    }

    return dat;
}

/**
 * @brief       初始化IIC接口
 * @param       无
 * @retval      无
 */
void mpu6050_iic_init(void)
{
    GPIO_InitTypeDef gpio_init_struct = {0};
    
    /* 使能SCL、SDA引脚GPIO的时钟 */
    MPU6050_IIC_SCL_GPIO_CLK_ENABLE();
    MPU6050_IIC_SDA_GPIO_CLK_ENABLE();
    
    /* 初始化SCL引脚 */
    gpio_init_struct.Pin    = MPU6050_IIC_SCL_GPIO_PIN;  /* SCL引脚 */
    gpio_init_struct.Mode   = GPIO_MODE_OUTPUT_PP;          /* 推挽输出 */
    gpio_init_struct.Pull   = GPIO_PULLUP;                  /* 上拉 */
    gpio_init_struct.Speed  = GPIO_SPEED_FREQ_HIGH;         /* 高速 */
    HAL_GPIO_Init(MPU6050_IIC_SCL_GPIO_PORT, &gpio_init_struct);
    
    /* 初始化SDA引脚 */
    gpio_init_struct.Pin    = MPU6050_IIC_SDA_GPIO_PIN;  /* SDA引脚 */
    gpio_init_struct.Mode   = GPIO_MODE_OUTPUT_OD;          /* 开漏输出 */
    HAL_GPIO_Init(MPU6050_IIC_SDA_GPIO_PORT, &gpio_init_struct);
    
    mpu6050_iic_stop();
}

mpu6050_iic.h

#ifndef __MPU6050_IIC_H
#define __MPU6050_IIC_H

#include "main.h"

/* 引脚定义 */
#define MPU6050_IIC_SCL_GPIO_PORT            GPIOB
#define MPU6050_IIC_SCL_GPIO_PIN             GPIO_PIN_8
#define MPU6050_IIC_SCL_GPIO_CLK_ENABLE()    do{ __HAL_RCC_GPIOB_CLK_ENABLE(); }while(0)
#define MPU6050_IIC_SDA_GPIO_PORT            GPIOB
#define MPU6050_IIC_SDA_GPIO_PIN             GPIO_PIN_9
#define MPU6050_IIC_SDA_GPIO_CLK_ENABLE()    do{ __HAL_RCC_GPIOB_CLK_ENABLE(); }while(0)

/* IO操作 */
#define MPU6050_IIC_SCL(x)                   do{ x ?                                                                                             \
                                                    HAL_GPIO_WritePin(MPU6050_IIC_SCL_GPIO_PORT, MPU6050_IIC_SCL_GPIO_PIN, GPIO_PIN_SET) :    \
                                                    HAL_GPIO_WritePin(MPU6050_IIC_SCL_GPIO_PORT, MPU6050_IIC_SCL_GPIO_PIN, GPIO_PIN_RESET);   \
                                                }while(0)

#define MPU6050_IIC_SDA(x)                   do{ x ?                                                                                             \
                                                    HAL_GPIO_WritePin(MPU6050_IIC_SDA_GPIO_PORT, MPU6050_IIC_SDA_GPIO_PIN, GPIO_PIN_SET) :    \
                                                    HAL_GPIO_WritePin(MPU6050_IIC_SDA_GPIO_PORT, MPU6050_IIC_SDA_GPIO_PIN, GPIO_PIN_RESET);   \
                                                }while(0)

#define MPU6050_IIC_READ_SDA()               HAL_GPIO_ReadPin(MPU6050_IIC_SDA_GPIO_PORT, MPU6050_IIC_SDA_GPIO_PIN)

/* 操作函数 */
void mpu6050_iic_start(void);                /* 产生IIC起始信号 */
void mpu6050_iic_stop(void);                 /* 产生IIC停止信号 */
uint8_t mpu6050_iic_wait_ack(void);          /* 等待IIC应答信号 */
void mpu6050_iic_ack(void);                  /* 产生ACK应答信号 */
void mpu6050_iic_nack(void);                 /* 不产生ACK应答信号 */
void mpu6050_iic_send_byte(uint8_t dat);     /* IIC发送一个字节 */
uint8_t mpu6050_iic_read_byte(uint8_t ack);  /* IIC接收一个字节 */
void mpu6050_iic_init(void);                 /* 初始化IIC接口 */

#endif

代码分析

这段代码是用于驱动MPU6050模块的IIC接口的代码。主要功能包括产生起始信号、停止信号、等待应答信号、产生应答信号、发送字节和接收字节等操作。
具体代码功能如下:
mpu6050_iic_delay():用于控制IIC读写速度的延时函数。
mpu6050_iic_start():产生IIC起始信号。
mpu6050_iic_stop():产生IIC停止信号。
mpu6050_iic_wait_ack():等待IIC应答信号,返回值表示应答信号是否接收成功。
mpu6050_iic_ack():产生ACK应答信号。
mpu6050_iic_nack():不产生ACK应答信号。
mpu6050_iic_send_byte():发送一个字节。
mpu6050_iic_read_byte():接收一个字节,参数ack表示是否发送ACK应答信号。
mpu6050_iic_init():初始化IIC接口,配置SCL和SDA引脚的GPIO模式、上拉和输出类型。
这些函数一起完成了对MPU6050模块的IIC接口进行初始化和操作的功能。这些函数可以根据具体的硬件配置和需求进行修改和适应。

复位,读取温度,角度等函数封装

mpu6050.c

#include "mpu6050.h"
#include "mpu6050_iic.h"
#include "usart.h"
#include "main.h"

/**
 * @brief       MPU6050硬件初始化
 * @param       无
 * @retval      无
 */
static void mpu6050_hw_init(void)
{
    GPIO_InitTypeDef gpio_init_struct = {0};
    
    /* 使能AD0引脚GPIO的时钟 */
    MPU6050_AD0_GPIO_CLK_ENABLE();
    
    /* 初始化AD0引脚 */
    gpio_init_struct.Pin    = MPU6050_AD0_GPIO_PIN;  /* AD0引脚 */
    gpio_init_struct.Mode   = GPIO_MODE_OUTPUT_PP;      /* 推挽输出 */
    gpio_init_struct.Pull   = GPIO_PULLUP;              /* 上拉 */
    gpio_init_struct.Speed  = GPIO_SPEED_FREQ_HIGH;     /* 高速 */
    HAL_GPIO_Init(MPU6050_AD0_GPIO_PORT, &gpio_init_struct);
    
    /* 控制MPU6050的AD0引脚为低电平
     * 设置其IIC的从机地址为0x68
     */
    MPU6050_AD0(0);
}

/**
 * @brief       往MPU6050的指定寄存器连续写入指定数据
 * @param       addr: MPU6050的IIC通讯地址
 *              reg : MPU6050寄存器地址
 *              len : 写入的长度
 *              dat : 写入的数据
 * @retval      MPU6050_EOK : 函数执行成功
 *              MPU6050_EACK: IIC通讯ACK错误,函数执行失败
 */
uint8_t mpu6050_write(uint8_t addr,uint8_t reg, uint8_t len, uint8_t *dat)
{
    uint8_t i;
    
    mpu6050_iic_start();
    mpu6050_iic_send_byte((addr << 1) | 0);
    if (mpu6050_iic_wait_ack() == 1)
    {
        mpu6050_iic_stop();
        return MPU6050_EACK;
    }
    mpu6050_iic_send_byte(reg);
    if (mpu6050_iic_wait_ack() == 1)
    {
        mpu6050_iic_stop();
        return MPU6050_EACK;
    }
    for (i=0; i<len; i++)
    {
        mpu6050_iic_send_byte(dat[i]);
        if (mpu6050_iic_wait_ack() == 1)
        {
            mpu6050_iic_stop();
            return MPU6050_EACK;
        }
    }
    mpu6050_iic_stop();
    return MPU6050_EOK;
}

/**
 * @brief       往MPU6050的指定寄存器写入一字节数据
 * @param       addr: MPU6050的IIC通讯地址
 *              reg : MPU6050寄存器地址
 *              dat : 写入的数据
 * @retval      MPU6050_EOK : 函数执行成功
 *              MPU6050_EACK: IIC通讯ACK错误,函数执行失败
 */
uint8_t mpu6050_write_byte(uint8_t addr, uint8_t reg, uint8_t dat)
{
    return mpu6050_write(addr, reg, 1, &dat);
}

/**
 * @brief       连续读取MPU6050指定寄存器的值
 * @param       addr: MPU6050的IIC通讯地址
 *              reg : MPU6050寄存器地址
 *              len: 读取的长度
 *              dat: 存放读取到的数据的地址
 * @retval      MPU6050_EOK : 函数执行成功
 *              MPU6050_EACK: IIC通讯ACK错误,函数执行失败
 */
uint8_t mpu6050_read(uint8_t addr, uint8_t reg, uint8_t len, uint8_t *dat)
{
    mpu6050_iic_start();
    mpu6050_iic_send_byte((addr << 1) | 0);
    if (mpu6050_iic_wait_ack() == 1)
    {
        mpu6050_iic_stop();
        return MPU6050_EACK;
    }
    mpu6050_iic_send_byte(reg);
    if (mpu6050_iic_wait_ack() == 1)
    {
        mpu6050_iic_stop();
        return MPU6050_EACK;
    }
    mpu6050_iic_start();
    mpu6050_iic_send_byte((addr << 1) | 1);
    if (mpu6050_iic_wait_ack() == 1)
    {
        mpu6050_iic_stop();
        return MPU6050_EACK;
    }
    while (len)
    {
        *dat = mpu6050_iic_read_byte((len > 1) ? 1 : 0);
        len--;
        dat++;
    }
    mpu6050_iic_stop();
    return MPU6050_EOK;
}

/**
 * @brief       读取MPU6050指定寄存器的值
 * @param       addr: MPU6050的IIC通讯地址
 *              reg : MPU6050寄存器地址
 *              dat: 读取到的寄存器的值
 * @retval      MPU6050_EOK : 函数执行成功
 *              MPU6050_EACK: IIC通讯ACK错误,函数执行失败
 */
uint8_t mpu6050_read_byte(uint8_t addr, uint8_t reg, uint8_t *dat)
{
    return mpu6050_read(addr, reg, 1, dat);
}

/**
 * @brief       MPU6050软件复位
 * @param       无
 * @retval      无
 */
void mpu6050_sw_reset(void)
{
    mpu6050_write_byte(MPU6050_IIC_ADDR, MPU_PWR_MGMT1_REG, 0x80);
    delay_ms(100);
    mpu6050_write_byte(MPU6050_IIC_ADDR, MPU_PWR_MGMT1_REG, 0x00);
}

/**
 * @brief       MPU6050设置陀螺仪传感器量程范围
 * @param       frs: 0 --> ±250dps
 *                   1 --> ±500dps
 *                   2 --> ±1000dps
 *                   3 --> ±2000dps
 * @retval      MPU6050_EOK : 函数执行成功
 *              MPU6050_EACK: IIC通讯ACK错误,函数执行失败
 */
uint8_t mpu6050_set_gyro_fsr(uint8_t fsr)
{
    return mpu6050_write_byte(MPU6050_IIC_ADDR, MPU_GYRO_CFG_REG, fsr << 3);
}

/**
 * @brief       MPU6050设置加速度传感器量程范围
 * @param       frs: 0 --> ±2g
 *                   1 --> ±4g
 *                   2 --> ±8g
 *                   3 --> ±16g
 * @retval      MPU6050_EOK : 函数执行成功
 *              MPU6050_EACK: IIC通讯ACK错误,函数执行失败
 */
uint8_t mpu6050_set_accel_fsr(uint8_t fsr)
{
    return mpu6050_write_byte(MPU6050_IIC_ADDR, MPU_ACCEL_CFG_REG, fsr << 3);
}

/**
 * @brief       MPU6050设置数字低通滤波器频率
 * @param       lpf: 数字低通滤波器的频率(Hz)
 * @retval      MPU6050_EOK : 函数执行成功
 *              MPU6050_EACK: IIC通讯ACK错误,函数执行失败
 */
uint8_t mpu6050_set_lpf(uint16_t lpf)
{
    uint8_t dat;
    
    if (lpf >= 188)
    {
        dat = 1;
    }
    else if (lpf >= 98)
    {
        dat = 2;
    }
    else if (lpf >= 42)
    {
        dat = 3;
    }
    else if (lpf >= 20)
    {
        dat = 4;
    }
    else if (lpf >= 10)
    {
        dat = 5;
    }
    else
    {
        dat = 6;
    }
    
    return mpu6050_write_byte(MPU6050_IIC_ADDR, MPU_CFG_REG, dat);
}

/**
 * @brief       MPU6050设置采样率
 * @param       rate: 采样率(4~1000Hz)
 * @retval      MPU6050_EOK : 函数执行成功
 *              MPU6050_EACK: IIC通讯ACK错误,函数执行失败
 */
uint8_t mpu6050_set_rate(uint16_t rate)
{
    uint8_t ret;
    uint8_t dat;
    
    if (rate > 1000)
    {
        rate = 1000;
    }
    
    if (rate < 4)
    {
        rate = 4;
    }
    
    dat = 1000 / rate - 1;
    ret = mpu6050_write_byte(MPU6050_IIC_ADDR, MPU_SAMPLE_RATE_REG, dat);
    if (ret != MPU6050_EOK)
    {
        return ret;
    }
    
    ret = mpu6050_set_lpf(rate >> 1);
    if (ret != MPU6050_EOK)
    {
        return ret;
    }
    
    return MPU6050_EOK;
}

/**
 * @brief       MPU6050获取温度值
 * @param       temperature: 获取到的温度值(扩大了100倍)
 * @retval      MPU6050_EOK : 函数执行成功
 *              MPU6050_EACK: IIC通讯ACK错误,函数执行失败
 */
uint8_t mpu6050_get_temperature(int16_t *temp)
{
    uint8_t dat[2];
    uint8_t ret;
    int16_t raw = 0;
    
    ret = mpu6050_read(MPU6050_IIC_ADDR, MPU_TEMP_OUTH_REG, 2, dat);
    if (ret == MPU6050_EOK)
    {
        raw = ((uint16_t)dat[0] << 8) | dat[1];
        *temp = (int16_t)((36.53f + ((float)raw / 340)) * 100);
    }
    
    return ret;
}

/**
 * @brief       MPU6050获取陀螺仪值
 * @param       gx,gy,gz: 陀螺仪x、y、z轴的原始度数(带符号)
 * @retval      MPU6050_EOK : 函数执行成功
 *              MPU6050_EACK: IIC通讯ACK错误,函数执行失败
 */
uint8_t mpu6050_get_gyroscope(int16_t *gx, int16_t *gy, int16_t *gz)
{
    uint8_t dat[6];
    uint8_t ret;
    
    ret =  mpu6050_read(MPU6050_IIC_ADDR, MPU_GYRO_XOUTH_REG, 6, dat);
    if (ret == MPU6050_EOK)
    {
        *gx = ((uint16_t)dat[0] << 8) | dat[1];
        *gy = ((uint16_t)dat[2] << 8) | dat[3];
        *gz = ((uint16_t)dat[4] << 8) | dat[5];
    }
    
    return ret;
}

/**
 * @brief       MPU6050获取加速度值
 * @param       ax,ay,az: 加速度x、y、z轴的原始度数(带符号)
 * @retval      MPU6050_EOK : 函数执行成功
 *              MPU6050_EACK: IIC通讯ACK错误,函数执行失败
 */
uint8_t mpu6050_get_accelerometer(int16_t *ax, int16_t *ay, int16_t *az)
{
    uint8_t dat[6];
    uint8_t ret;
    
    ret =  mpu6050_read(MPU6050_IIC_ADDR, MPU_ACCEL_XOUTH_REG, 6, dat);
    if (ret == MPU6050_EOK)
    {
        *ax = ((uint16_t)dat[0] << 8) | dat[1];
        *ay = ((uint16_t)dat[2] << 8) | dat[3];
        *az = ((uint16_t)dat[4] << 8) | dat[5];
    }
    
    return ret;
}

/**
 * @brief       MPU6050初始化
 * @param       无
 * @retval      MPU6050_EOK: 函数执行成功
 *              MPU6050_EID: 获取ID错误,函数执行失败
 */
uint8_t mpu6050_init(void)
{
    uint8_t id;
    
    mpu6050_hw_init();                                                   /* MPU6050硬件初始化 */
    mpu6050_iic_init();                                                  /* 初始化IIC接口 */
    mpu6050_sw_reset();                                                  /* ATK-MS050软件复位 */
    mpu6050_set_gyro_fsr(3);                                             /* 陀螺仪传感器,±2000dps */
    mpu6050_set_accel_fsr(0);                                            /* 加速度传感器,±2g */
    mpu6050_set_rate(50);                                                /* 采样率,50Hz */
    mpu6050_write_byte(MPU6050_IIC_ADDR, MPU_INT_EN_REG, 0X00);       /* 关闭所有中断 */
    mpu6050_write_byte(MPU6050_IIC_ADDR, MPU_USER_CTRL_REG, 0X00);    /* 关闭IIC主模式 */
    mpu6050_write_byte(MPU6050_IIC_ADDR, MPU_FIFO_EN_REG, 0X00);      /* 关闭FIFO */
    mpu6050_write_byte(MPU6050_IIC_ADDR, MPU_INTBP_CFG_REG, 0X80);    /* INT引脚低电平有效 */
    mpu6050_read_byte(MPU6050_IIC_ADDR, MPU_DEVICE_ID_REG, &id);      /* 读取设备ID */
    if (id != MPU6050_IIC_ADDR)
    {
        return MPU6050_EID;
    }
    mpu6050_write_byte(MPU6050_IIC_ADDR, MPU_PWR_MGMT1_REG, 0x01);    /* 设置CLKSEL,PLL X轴为参考 */
    mpu6050_write_byte(MPU6050_IIC_ADDR, MPU_PWR_MGMT2_REG, 0x00);    /* 加速度与陀螺仪都工作 */
    mpu6050_set_rate(50);                                                /* 采样率,50Hz */
    
    return MPU6050_EOK;
}

mpu6050.h

#ifndef __MPU6050_H
#define __MPU6050_H

#include "main.h"

/* 引脚定义 */
#define MPU6050_AD0_GPIO_PORT            GPIOC
#define MPU6050_AD0_GPIO_PIN             GPIO_PIN_0
#define MPU6050_AD0_GPIO_CLK_ENABLE()    do{ __HAL_RCC_GPIOC_CLK_ENABLE(); \
                                            }while(0)

/* IO操作 */
#define MPU6050_AD0(x)                   do{ x ?                                                                                     \
                                                HAL_GPIO_WritePin(MPU6050_AD0_GPIO_PORT, MPU6050_AD0_GPIO_PIN, GPIO_PIN_SET) :    \
                                                HAL_GPIO_WritePin(MPU6050_AD0_GPIO_PORT, MPU6050_AD0_GPIO_PIN, GPIO_PIN_RESET);   \
                                            }while(0)

/* ATK-MS6050的IIC通讯从机地址
 * 如果ATK-MS6050的AD0引脚被拉低,则其IIC通讯的地址为0x68
 * 如果ATK-MS6050的AD0引脚被拉高,则其IIC通讯的地址为0x69
 */
#define MPU6050_IIC_ADDR     0x68

/* MPU6050寄存器地址定义 */
#define MPU_ACCEL_OFFS_REG      0X06    // accel_offs寄存器,可读取版本号,寄存器手册未提到
#define MPU_PROD_ID_REG         0X0C    // prod id寄存器,在寄存器手册未提到
#define MPU_SELF_TESTX_REG      0X0D    // 自检寄存器X
#define MPU_SELF_TESTY_REG      0X0E    // 自检寄存器Y
#define MPU_SELF_TESTZ_REG      0X0F    // 自检寄存器Z
#define MPU_SELF_TESTA_REG      0X10    // 自检寄存器A
#define MPU_SAMPLE_RATE_REG     0X19    // 采样频率分频器
#define MPU_CFG_REG             0X1A    // 配置寄存器
#define MPU_GYRO_CFG_REG        0X1B    // 陀螺仪配置寄存器
#define MPU_ACCEL_CFG_REG       0X1C    // 加速度计配置寄存器
#define MPU_MOTION_DET_REG      0X1F    // 运动检测阀值设置寄存器
#define MPU_FIFO_EN_REG         0X23    // FIFO使能寄存器
#define MPU_I2CMST_CTRL_REG     0X24    // IIC主机控制寄存器
#define MPU_I2CSLV0_ADDR_REG    0X25    // IIC从机0器件地址寄存器
#define MPU_I2CSLV0_REG         0X26    // IIC从机0数据地址寄存器
#define MPU_I2CSLV0_CTRL_REG    0X27    // IIC从机0控制寄存器
#define MPU_I2CSLV1_ADDR_REG    0X28    // IIC从机1器件地址寄存器
#define MPU_I2CSLV1_REG         0X29    // IIC从机1数据地址寄存器
#define MPU_I2CSLV1_CTRL_REG    0X2A    // IIC从机1控制寄存器
#define MPU_I2CSLV2_ADDR_REG    0X2B    // IIC从机2器件地址寄存器
#define MPU_I2CSLV2_REG         0X2C    // IIC从机2数据地址寄存器
#define MPU_I2CSLV2_CTRL_REG    0X2D    // IIC从机2控制寄存器
#define MPU_I2CSLV3_ADDR_REG    0X2E    // IIC从机3器件地址寄存器
#define MPU_I2CSLV3_REG         0X2F    // IIC从机3数据地址寄存器
#define MPU_I2CSLV3_CTRL_REG    0X30    // IIC从机3控制寄存器
#define MPU_I2CSLV4_ADDR_REG    0X31    // IIC从机4器件地址寄存器
#define MPU_I2CSLV4_REG         0X32    // IIC从机4数据地址寄存器
#define MPU_I2CSLV4_DO_REG      0X33    // IIC从机4写数据寄存器
#define MPU_I2CSLV4_CTRL_REG    0X34    // IIC从机4控制寄存器
#define MPU_I2CSLV4_DI_REG      0X35    // IIC从机4读数据寄存器
#define MPU_I2CMST_STA_REG      0X36    // IIC主机状态寄存器
#define MPU_INTBP_CFG_REG       0X37    // 中断/旁路设置寄存器
#define MPU_INT_EN_REG          0X38    // 中断使能寄存器
#define MPU_INT_STA_REG         0X3A    // 中断状态寄存器
#define MPU_ACCEL_XOUTH_REG     0X3B    // 加速度值,X轴高8位寄存器
#define MPU_ACCEL_XOUTL_REG     0X3C    // 加速度值,X轴低8位寄存器
#define MPU_ACCEL_YOUTH_REG     0X3D    // 加速度值,Y轴高8位寄存器
#define MPU_ACCEL_YOUTL_REG     0X3E    // 加速度值,Y轴低8位寄存器
#define MPU_ACCEL_ZOUTH_REG     0X3F    // 加速度值,Z轴高8位寄存器
#define MPU_ACCEL_ZOUTL_REG     0X40    // 加速度值,Z轴低8位寄存器
#define MPU_TEMP_OUTH_REG       0X41    // 温度值高八位寄存器
#define MPU_TEMP_OUTL_REG       0X42    // 温度值低8位寄存器
#define MPU_GYRO_XOUTH_REG      0X43    // 陀螺仪值,X轴高8位寄存器
#define MPU_GYRO_XOUTL_REG      0X44    // 陀螺仪值,X轴低8位寄存器
#define MPU_GYRO_YOUTH_REG      0X45    // 陀螺仪值,Y轴高8位寄存器
#define MPU_GYRO_YOUTL_REG      0X46    // 陀螺仪值,Y轴低8位寄存器
#define MPU_GYRO_ZOUTH_REG      0X47    // 陀螺仪值,Z轴高8位寄存器
#define MPU_GYRO_ZOUTL_REG      0X48    // 陀螺仪值,Z轴低8位寄存器
#define MPU_I2CSLV0_DO_REG      0X63    // IIC从机0数据寄存器
#define MPU_I2CSLV1_DO_REG      0X64    // IIC从机1数据寄存器
#define MPU_I2CSLV2_DO_REG      0X65    // IIC从机2数据寄存器
#define MPU_I2CSLV3_DO_REG      0X66    // IIC从机3数据寄存器
#define MPU_I2CMST_DELAY_REG    0X67    // IIC主机延时管理寄存器
#define MPU_SIGPATH_RST_REG     0X68    // 信号通道复位寄存器
#define MPU_MDETECT_CTRL_REG    0X69    // 运动检测控制寄存器
#define MPU_USER_CTRL_REG       0X6A    // 用户控制寄存器
#define MPU_PWR_MGMT1_REG       0X6B    // 电源管理寄存器1
#define MPU_PWR_MGMT2_REG       0X6C    // 电源管理寄存器2
#define MPU_FIFO_CNTH_REG       0X72    // FIFO计数寄存器高八位
#define MPU_FIFO_CNTL_REG       0X73    // FIFO计数寄存器低八位
#define MPU_FIFO_RW_REG         0X74    // FIFO读写寄存器
#define MPU_DEVICE_ID_REG       0X75    // 器件ID寄存器

/* 函数错误代码 */
#define MPU6050_EOK      0   /* 没有错误 */
#define MPU6050_EID      1   /* ID错误 */
#define MPU6050_EACK     2   /* IIC通讯ACK错误 */

/* 操作函数 */
uint8_t mpu6050_write(uint8_t addr, uint8_t reg, uint8_t len, uint8_t *dat); /* 往ATK-MS6050的指定寄存器连续写入指定数据 */
uint8_t mpu6050_write_byte(uint8_t addr, uint8_t reg, uint8_t dat);          /* 往ATK-MS6050的指定寄存器写入一字节数据 */
uint8_t mpu6050_read(uint8_t addr, uint8_t reg, uint8_t len, uint8_t *dat);  /* 连续读取ATK-MS6050指定寄存器的值 */
uint8_t mpu6050_read_byte(uint8_t addr, uint8_t reg, uint8_t *dat);          /* 读取ATK-MS6050指定寄存器的值 */
void mpu6050_sw_reset(void);                                                 /* ATK-MS6050软件复位 */
uint8_t mpu6050_set_gyro_fsr(uint8_t fsr);                                   /* ATK-MS6050设置陀螺仪传感器量程范围 */
uint8_t mpu6050_set_accel_fsr(uint8_t fsr);                                  /* ATK-MS6050设置加速度传感器量程范围 */
uint8_t mpu6050_set_lpf(uint16_t lpf);                                       /* ATK-MS6050设置数字低通滤波器频率 */
uint8_t mpu6050_set_rate(uint16_t rate);                                     /* ATK-MS6050设置采样率 */
uint8_t mpu6050_get_temperature(int16_t *temp);                              /* ATK-MS6050获取温度值 */
uint8_t mpu6050_get_gyroscope(int16_t *gx, int16_t *gy, int16_t *gz);        /* ATK-MS6050获取陀螺仪值 */
uint8_t mpu6050_get_accelerometer(int16_t *ax, int16_t *ay, int16_t *az);    /* ATK-MS6050获取加速度值 */
uint8_t mpu6050_init(void);                                                  /* ATK-MS6050初始化 */

#endif

代码分析

用于初始化和与MPU6050进行通信。MPU6050是一个六轴传感器,包含三轴陀螺仪和三轴加速度计,可以用于测量物体的姿态和运动。以下是代码的主要功能:
定义了一些宏和函数原型,包括硬件初始化函数、IIC通信函数、写入和读取寄存器函数等。

mpu6050_hw_init函数用于初始化MPU6050相关的硬件引脚。
mpu6050_write函数用于向MPU6050的指定寄存器连续写入数据。
mpu6050_write_byte函数用于向MPU6050的指定寄存器写入单个字节的数据。
mpu6050_read函数用于连续读取MPU6050指定寄存器的数据。
mpu6050_read_byte函数用于读取MPU6050指定寄存器的单个字节数据。
mpu6050_sw_reset函数用于对MPU6050进行软件复位。
mpu6050_set_gyro_fsr函数用于设置陀螺仪传感器的量程范围。
mpu6050_set_accel_fsr函数用于设置加速度传感器的量程范围。
mpu6050_set_lpf函数用于设置MPU6050的数字低通滤波器频率。
mpu6050_set_rate函数用于设置MPU6050的采样率。
mpu6050_get_temperature函数用于获取MPU6050的温度值。
mpu6050_get_gyroscope函数用于获取MPU6050的陀螺仪值。
mpu6050_get_accelerometer函数用于获取MPU6050的加速度值。
mpu6050_init函数用于初始化MPU6050,并返回函数执行状态。
在使用这段代码时,需要根据具体的硬件和应用场景进行适配和调整。

DMP移植

先获取到移植所需的文件,我使用的文件来自正点原子陀螺仪资料,见文件添加进工程,再进行自己mcu的适配修改
在这里插入图片描述

1.修改头文件路径为自己的头文件路径

inv_mpu.c
在这里插入图片描述

修改
在这里插入图片描述

inv_mpu_dmp_motion_driver.c
在这里插入图片描述

修改
在这里插入图片描述

2.修改I2C读写函数为自己mcu平台的读写函数

inv_mpu.c
在这里插入图片描述

修改为
在这里插入图片描述

3.修改延时函数为自己平台的延时函数

inv_mpu.c
在这里插入图片描述

修改为
在这里插入图片描述

inv_mpu_dmp_motion_driver.c
在这里插入图片描述

修改
在这里插入图片描述

使用实例

 /*
   *         模拟I2C实现MPU6050通讯
   */
   uint8_t ret;
   float pit, rol, yaw;
   int16_t acc_x, acc_y, acc_z;
   int16_t gyr_x, gyr_y, gyr_z;
   int16_t temp;

   /* 初始化MPU6050 */
   ret = mpu6050_init();
   if (ret != 0)
   {
       printf("MPU6050 init failed!\r\n");

   }
   ret = 1;
   /* 初始化MPU6050 DMP */
   while(ret){
       ret = mpu6050_dmp_init();
       if (ret != 0)
       {
           printf("MPU6050 DMP init failed!\r\n");

       }
   }



   while (1)
   {

               /* 串口调试助手的串口通讯波特率为115200 */



       /* 获取MPU6050 DMP处理后的数据 */
       ret  = mpu6050_dmp_get_data(&pit, &rol, &yaw);
       /* 获取MPU6050加速度值 */
       ret += mpu6050_get_accelerometer(&acc_x, &acc_y, &acc_z);
       /* 获取MPU6050陀螺仪值 */
       ret += mpu6050_get_gyroscope(&gyr_x, &gyr_y, &gyr_z);
       /* 获取MPU6050温度值 */
       ret += mpu6050_get_temperature(&temp);

               /* 上传相关数据信息至串口调试助手 */
               printf("pit: %.2f, rol: %.2f, yaw: %.2f,\r\n ", pit, rol, yaw);
               printf("acc_x: %d, acc_y: %d, acc_z: %d,\r\n ", acc_x, acc_y, acc_z);
               printf("gyr_x: %d, gyr_y: %d, gyr_z: %d,\r\n ", gyr_x, gyr_y, gyr_z);
               printf("temp: %d\r\n", temp);
               HAL_Delay(500);

   }

如果文章对您有帮助,点赞支持👍,感谢🤝

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/28062.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

QT学习07:五种按钮控件

文章首发于我的个人博客&#xff1a;欢迎大佬们来逛逛 文章目录 抽象类&#xff1a;QAbstractButtonQPushButtonQToolButtonQCommandLinkButtonQRadioButtonQCheckBoxQButtonGroup 抽象类&#xff1a;QAbstractButton 是所有按钮类的祖先。 QAbstractButton的信号&#xff1a…

深入理解CSS字符转义行为

深入理解CSS字符转义行为 深入理解CSS字符转义行为 前言为什么要转义&#xff1f;CSS 转义什么是合法css的表达式 左半部分右半部分 练习参考链接 前言 在日常的开发中&#xff0c;我们经常写css。比如常见的按钮: <button class"btn"></button>&am…

【MySQL】 IS NOT NULL 和 != NULL 的区别?

背景 最近在开发小伙伴的需求&#xff0c;遇到了一个数据库统计的问题&#xff0c; is not null 结果正确 &#xff01;null 结果就不对&#xff0c;然后就激发了获取真理的想法&#xff0c;那必须的查查 咋回事嘞&#xff1f; 开整 在用MySQL的过程中&#xff0c;你是否存…

大学物理(上)-期末知识点结合习题复习(4)——质点运动学-动能定理 力做功 保守力与非保守力 势能 机械能守恒定律 完全弹性碰撞

目录 1.力做功 恒力作用下的功 变力的功 2.动能定理 3.保守力与非保守力 4.势能 引力的功与弹力的功 引力势能与弹性势能 5.保守力做功与势能的关系 6.机械能守恒定律 7.完全弹性碰撞 题1 题目描述 题解 题2 题目描述 题解 1.力做功 物体在力作用下移动做功…

AWS CodeWhisperer 简单介绍

一、何为AWS CodeWhisperer Amazon CodeWhisperer能够理解以自然语言&#xff08;英语&#xff09;编写的注释&#xff0c;并能实时生成多条代码建议&#xff0c; 以此提高开发人员生产力。 二、主要功能 Amazon CodeWhisperer 的主要功能&#xff0c;包括代码生成、引用追踪…

36.SpringBoot实用篇—运维

目录 一、实用篇—运维。 &#xff08;1&#xff09;程序打包与运行&#xff08;Windows版&#xff09;。 &#xff08;2&#xff09;spring-boot-maven-plugin插件作用。 &#xff08;3&#xff09;程序打包与运行&#xff08;Linux版&#xff09;。 &#xff08;4&#…

chatgpt赋能python:Python中如何处理多个输入

Python中如何处理多个输入 在编写Python程序时&#xff0c;我们经常需要从用户那里获取多个输入来执行某些操作。本文将介绍Python中的各种方法来处理多个输入。 从终端获取多个输入 Python中最简单的方式是从终端获取多个输入。下面是一个基本的例子&#xff1a; input_st…

SpringSecurity实现前后端分离登录token认证详解

目录 1. SpringSecurity概述 1.1 权限框架 1.1.1 Apache Shiro 1.1.2 SpringSecurity 1.1.3 权限框架的选择 1.2 授权和认证 1.3 SpringSecurity的功能 2.SpringSecurity 实战 2.1 引入SpringSecurity 2.2 认证 2.2.1 登录校验流程 2.2.2 SpringSecurity完整流程 2.2.…

Splashtop 与 Pax8 合作为 MSP 提供简化的远程支持解决方案

2023年4月27日 科罗拉多州丹佛 Pax8 是一个行业领先的云商务市场&#xff0c;该公司今天宣布将通过 Pax8 市场在全球推出其全新运营供应商 Splashtop。Splashtop 的远程访问、支持以及端点监控和管理解决方案极具成本效益&#xff0c;而且功能强大&#xff0c;可以助力托管服务…

002、体系结构之TiDB Server

TiDB Server 1、TiDB总览1.1、TiDB Server架构1.2、TiDB Server 主要功能&#xff1a; 2、SQL语句处理语句的解析和编译SQL层协议层上下文解析层逻辑优化器物理优化器本地执行器分布式执行器 3、如何将表的数据转成kv形式4、在线DDL相关模块5、GC机制与相关模块6、TiDB Server …

你真的会写软件测试简历吗?为什么面试约不到,测试老鸟的建议...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 写好一份简历的三…

Frida技术—逆向开发的屠龙刀

简介 Frida是一种基于JavaScript的动态分析工具&#xff0c;可以用于逆向开发、应用程序的安全测试、反欺诈技术等领域。Frida主要用于在已安装的应用程序上运行自己的JavaScript代码&#xff0c;从而进行动态分析、调试、修改等操作&#xff0c;能够绕过应用程序的安全措施&a…

mac下部署和访问 Kubernetes 仪表板(Dashboard)

简介 Dashboard 是基于网页的 Kubernetes 用户界面。 你可以使用 Dashboard 将容器应用部署到 Kubernetes 集群中&#xff0c;也可以对容器应用排错&#xff0c;还能管理集群资源。 你可以使用 Dashboard 获取运行在集群中的应用的概览信息&#xff0c;也可以创建或者修改 Kub…

QT--配置Opencv

提示&#xff1a;本文为学习记录&#xff0c;若有疑问&#xff0c;请及时联系作者。 文章目录 前言一、下载已编译的opencv1..解压2..path路径 二、使用步骤1..pro文件2..h文件 总结 前言 只做第一个我&#xff0c;不做第二个谁。 一、下载已编译的opencv 适用于mingw编译器…

NoSQL数据库

NoSQL数据库 NoSQL简介NoSQL兴起的原因NoSQL与关系数据库的对比NoSQL的四大类型键值数据库列族数据库文档数据库图形数据库不同类型数据库比较分析RedisMongoDBCassandraNeo4j NoSQL三大基石CAPBASE最终一致性 NoSQL简介 “Not Only SQL”泛指非关系型的数据库&#xff0c;区别…

07_scrapy的应用——获取电影数据(通过excel保存静态页面scrapy爬虫数据的模板/通过数据库保存)

0、前言: 一般我们自己创建的一些python项目,我们都需要创建虚拟环境,其中会下载很多包,也叫做依赖。但是我们在给他人分享我们的项目时,不能把虚拟环境打包发送给别人,因为每个人电脑系统不同,我们可以把依赖导出为依赖清单,然后别人有了我们的依赖清单,就可以用一条…

项目使用tensorflow2会出错,下载并使用tensorflow1

背景&#xff1a;使用pycharm安装总显示安装失败&#xff0c;使用pip安装也不行&#xff0c;只能使用conda配置虚拟环境手动安装 1、下载安装anaconda 官网下载&#xff0c;双击安装。用anaconda就是想使用虚拟环境&#xff0c;万一没弄好直接删了重新搞就行。 2、创建虚拟环境…

Https加密超文本传输协议的运用

1.https的相关知识 1.1 https的简介 HTTPS &#xff08;全称&#xff1a;Hypertext Transfer Protocol Secure &#xff09;&#xff0c;是以安全为目标的 HTTP 通道&#xff0c;在HTTP的基础上通过传输加密和身份认证保证了传输过程的安全性 。HTTPS 在HTTP 的基础下加…

使用POI实现JAVA操作Excel

Apache POI POI提供API给JAVA程序对Microsoft Office格式档案读和写的功能 POI工具介绍 POI 是用Java编写的免费开源的跨平台的 Java API&#xff0c;Apache POI提供API给Java程式对Microsoft Office格式档案读和写的功能。主要是运用其中读取和输出excel的功能。 POI官网地…

常用设计模式(三)

接着之前的思路今天来介绍一下常用的设计模式有哪些 单例模式&#xff08;Singleton Pattern&#xff09; 又称为单体模式&#xff0c;保证一个类只有一个实例&#xff0c;并提供一个访问它的全局访问点。也就是说&#xff0c;第二次使用同一个类创建新对象的时候&#xff0c…