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);
}
如果文章对您有帮助,点赞支持👍,感谢🤝