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

news2024/11/15 9:01:15

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);

   }

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

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

HTTPS 原理浅析及其在 Android 中的使用

1.HTTP协议的不足 HTTP1.x在传输数据时&#xff0c;所有传输的内容都是明文&#xff0c;客户端和服务器端都无法验证对方的身份&#xff0c;存在的问题如下&#xff1a; 通信使用明文(不加密)&#xff0c;内容可能会被窃听&#xff1b;不验证通信方的身份&#xff0c;有可能遭…

Hbase-- 03

4.原理加强 4.1数据存储 4.1.1行式存储 传统的行式数据库将一个个完整的数据行存储在数据页中 4.1.2列式存储 列式数据库是将同一个数据列的各个值存放在一起 传统行式数据库的特性如下&#xff1a; ①数据是按行存储的。 ②没有索引的查询使用大量I/O。比如一般的数据库表…

vue3 element-plus后台管理系统实现登录与记住密码功能

一、效果 二、代码部分 1、勾选记住密码布局代码 2、判断是否勾选&#xff0c;勾选则保存账号密码&#xff0c;否则不保存账号密码&#xff0c;由于是demo,故并没有做加密&#xff0c;如果是生成最好是对密码做加密处理。 3、页面挂载的时候需要背叛的是否保存密码&#xff0c;…

JDK8 ConcurrentHashMap 怎么放弃 Lock 使用 synchronized 了

synchronized 之前一直都是重量级锁&#xff0c;但是 JDK6 中官方是对他进行过升级&#xff0c;引入了偏向锁&#xff0c;轻量级锁&#xff0c;重量级锁&#xff0c;现在采用的是锁升级的方式去做的。针对synchronized 获取锁的方式&#xff0c;JVM 使用了锁升级的优化方式&…

十行代码,就能真正让你理解DMA(CPU的秘书)

下面的代码是单片机串口发送数据的程序. char a0xAA;//定义变量a,值为0xAA&#xff1b; TXREG a;//把数据由内存转移到串口外设&#xff1b;那我们定义的变量a的值存储在哪里了呢&#xff1f;可以看下单片机的逻辑框图。 变量其实都是存在一个叫SRAM的存储器中&#xff0c;它…

Playwright 和 Selenium 的区别是什么?

前言 最近有不少同学问到 Playwright 和 Selenium 的区别是什么&#xff1f;有同学可能之前学过 selenium 了&#xff0c;再学一个 playwright 感觉有些多余&#xff0c;可能之前有项目已经是 selenium 写的了&#xff0c;换成 playwright 需要时间成本&#xff0c;并且可能有…

【支付系统】核心支付流程

支付在产品中常见的用处为购买和充值.这两种功能操作大相径庭,其中购买相对充值多了很多步骤,它需要锁商品或者库存,还需要超时未支付取消订单等操作.在这篇文章中主要探讨支付部分,属于购买和充值公共部分. 下面是绘制的简易支付时序图 以上时序图并非完整,其实核心步骤就是, …

商城购买会员打折满减优惠券商品

文章目录 前言一、代码结构二、UML图三、代码实现3.1.domain3.2.enums3.3.strategy3.4.service3.5.config 四、单元测试五、模式应用六、问题及优化思路6.1.问题6.2.优化 总结 前言 使用策略模式、工厂方法模式、单例模式实现一些购买策略&#xff0c;需求&#xff1a;商城商品…

服装库存管理系统 Mybatis+Layui+MVC+JSP【完整功能介绍+实现详情+源码】

完整源码资料 地址直达&#xff1a;http://t.csdn.cn/RWsGw 前言 这是大二时候写的第一个Java项目&#xff0c;框架基本上都没有用到、而且用到的技术很老很老。只简单使用了一个Mybatis简化数据库的操作。前端框架用的还是Layui&#xff0c;贼难用。闲的无聊&#xff0c;对这…

缺少成本票怎么解决?首选自然人代开,方便又快捷!

《税筹顾问》专注于园区招商&#xff0c;您的贴身节税小能手&#xff0c;合理合规节税&#xff01; 成本票缺失导致的严重结果就是&#xff0c;缺少成本入账&#xff0c;导致利润虚高&#xff0c;企业所得税变高了&#xff0c;那么现有的解决方式很多&#xff0c;只是一些方法过…

图形学实验(完整文件见上传)

CRect rect; this->GetClientRect(rect); pDC->Ellipse(rect); // DDALineView.cpp : implementation of the CDDALineView class // #include “stdafx.h” #include “DDALine.h” #include “DDALineDoc.h” #include “DDALineView.h” #ifdef _DEBUG #define new…

Qt扫盲-QEvent 理论总结

QEvent 理论总结 一、概述二、事件类型1. Qt 已定义类型2. 开放用户定义类型 三、注册事件 一、概述 Qt的主事件循环(QCoreApplication::exec())从事件队列中获取原生窗口系统事件&#xff0c;将它们转换为QEvents&#xff0c;并将转换后的事件发送给QObjects。 一般来说&…

Multimodal fusion via cortical network inspired losses(第一次优质论文分享)

Multimodal fusion via cortical network inspired losses 论文介绍1. 论文研究的任务是什么&#xff1f;2. 论文关注/拟解决的问题是什么&#xff1f;3. 论文提出什么方法如何解决这个问题&#xff1f;4. 如何设计实验 来证明 所提方法确实解决了 拟解决的问题&#xff1f; 论…

Ada Tutorial(2)SPARK Examiner + SPARK Prover

文章目录 代码 Task1.adb代码 task3.adbtask4.adb 在Ada和SPARK中&#xff0c;SPARK_Mode是一个编译指示&#xff0c;它表示随后的代码将使用SPARK语言规则进行编译和分析。 在with SPARK_Mode > On的影响下&#xff0c;编译器会在编译过程中应用SPARK语言规则&#xff0c;它…

基于“声音”的量子计算机 | Science速递

光子盒研究院 现在&#xff0c;一个基于声音的量子计算机关键构件已被首次被证明是有效的。 构建量子计算机的一种流行方式是将信息编码到光粒子的量子状态中&#xff0c;然后将它们送过镜子和透镜等“迷宫”般的设备阵列来操纵这些信息。量子力学定律指出&#xff0c;量子粒子…

关于B/S结构系统的会话session机制

用户打开浏览器&#xff0c;进行一系列操作&#xff0c;然后最终将浏览器关闭&#xff0c;这整个过程叫做一次会话&#xff0c;会话对象叫session 用户在浏览器上点击了一次超链接或按钮等&#xff0c;称为一次请求&#xff0c;java对象是request session机制属于B/S结构的一部…

项目 引入 uView

只分享干货&#xff01; 第一点&#xff1a; npm install uview-ui//或yarn add uview-ui 第二点 import Vue from vue; import uView from uview-ui;Vue.use(uView);//或// main.js import uView from /node_modules/uview-ui Vue.use(uView) 第三点 import /node_module…

RK3568开发板 buildroot配置文件

在上一期技术分享中我们学会了如何在buildroot里选中我们自己想要的软件&#xff0c;如vsftpd、openssh等&#xff0c;那么有些客户可能会有疑问&#xff0c;安装完软件后需要配置相应的环境&#xff0c;应该怎么样默认的配置在系统中呢&#xff1f;其实这里的话已经为大家考虑…

python kafka 指定消费者名字

#!/usr/bin/env python # codingutf-8 """ kafka的消费者不是线程安全的&#xff0c;不能多线程启用 kafka不像其他的MQ&#xff0c;消费完数据&#xff0c;直接丢掉&#xff0c;而是会默认存储7天&#xff0c;存储7天后自动清除&#xff0c;故而可以从…

AI虚拟数字人在医学领域的四大应用场景

AI虚拟数字人技术是一种基于计算机图形学和人工智能技术的新型应用&#xff0c;可以模拟人类的外貌、语言、行为等特征&#xff0c;实现与人类的交互。在医疗领域中&#xff0c;AI虚拟数字人技术也有着广泛的应用前景。以下是几个可能的应用场景&#xff1a; 1.医学教育 AI虚拟…