【ESP32 idf 硬件I2C驱动MPU6050获取六轴数值】

I2C

介绍

介绍部分可以看我写的【ESP32 idf 软件模拟I2C驱动MPU6050实现六轴加速度的获取】,这个是使用软件模拟的I2C时序从而实现的,这次是硬件idf实现。

在这里插入图片描述
步骤:

在这里插入图片描述
在这里插入图片描述

配置

在这里插入图片描述
在这里插入图片描述

代码:

    uint8_t res;
    i2c_config_t i2c_config_InitStructure;
    i2c_config_InitStructure.clk_flags = 0; // 采用默认时钟
    i2c_config_InitStructure.master.clk_speed = 50000; // 通信速度 分为标准速度100kbps和快速400kbps,这里用50kbps即可
    i2c_config_InitStructure.mode = I2C_MODE_MASTER; // 主机模式
    i2c_config_InitStructure.scl_io_num = MPU6050_SCL_Pin; // 通信引脚,scl
    i2c_config_InitStructure.scl_pullup_en = GPIO_PULLUP_ENABLE; // scl 上拉使能
    i2c_config_InitStructure.sda_io_num = MPU6050_SDA_Pin; // sda引脚
    i2c_config_InitStructure.sda_pullup_en = GPIO_PULLUP_ENABLE; // sda 上拉使能

    res = i2c_param_config(i2c_port, &i2c_config_InitStructure);//配置参数
    if (res == ESP_OK) {
        ESP_LOGI(TAG, "i2c_param_config success");
    } else {
        ESP_LOGE(TAG, "i2c_param_config failed with error: %d", res);
    }

安装驱动

在这里插入图片描述
代码

    res = i2c_driver_install(i2c_port, I2C_MODE_MASTER, 0, 0, 0); // 安装驱动
    if (res == ESP_OK) {
        ESP_LOGI(TAG, "i2c_driver_install success");
    } else {
        ESP_LOGE(TAG, "i2c_driver_install failed with error: %d", res);
    }

参数一选择I2C资源,和上面配置的保持一致。

参数二选择主从模式。

如果是主机的话,后三个的参数都可以不需要,塞个0即可。

通信

在这里插入图片描述
在这里插入图片描述

创建&删除命令链接容器

在这里插入图片描述
删除命令容器可以减少资源浪费。

起始时序

在这里插入图片描述

写数据

写数据有以下两种方式,当然了,都是主模式使用的。
区别在于第一个函数是写一个Byte,而第二个函数可以写多个Byte。
在这里插入图片描述

读数据

在这里插入图片描述

结束时序

在这里插入图片描述

开始命令

既然上面的容器配置好了,必然需要开启该容器
在这里插入图片描述

mpu6050 硬件i2c驱动代码&调试

代码

MPU6050.c

/*
 * @Author: i want to 舞动乾坤
 * @Date: 2024-07-26 08:52:56
 * @LastEditors: i want to 舞动乾坤
 * @LastEditTime: 2024-07-26 16:42:29
 * @FilePath: \i2c_hardware_driver_mpu6050\main\MPU6050.c
 * @Description: 
 * 
 * Copyright (c) 2024 by i want to 舞动乾坤, All Rights Reserved. 
 */

#include <stdint.h>
#include "MPU6050_REG.h"
#include <driver/i2c.h>
#include <esp_log.h>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>

#define MPU6050_Address 0x68 // MPU6050 的 7 位地址
#define MPU6050_SCL_Pin GPIO_NUM_22
#define MPU6050_SDA_Pin GPIO_NUM_21
#define i2c_port I2C_NUM_0

static const char* TAG = "MPU6050";

/**
 * @description: MPU6050写寄存器
 * @param {uint8_t} RegAddress 寄存器地址,范围:参考MPU6050手册的寄存器描述
 * @param {uint8_t} Data 要写入寄存器的数据,范围:0x00~0xFF
 * @tip:设备地址通常是一个 7 位地址。当在软件中使用该地址时,通常需要将其左移一位(即乘以 2)以适应 I2C 总线传输格式。具体来说:
		I2C 总线上的设备地址总共是 8 位:
		前 7 位是设备的地址。
		第 8 位(最低位)是读/写位(R/W),用于指示这次操作是读还是写。
		0 表示写操作(I2C_MASTER_WRITE)。
		1 表示读操作(I2C_MASTER_READ)。
		所以,当你指定设备地址时,需要将其左移一位,并将读/写位添加到最低位。例如,对于一个 7 位设备地址 0x68:
		写操作:地址为 0x68 << 1 | I2C_MASTER_WRITE,即 0xD0。
		读操作:地址为 0x68 << 1 | I2C_MASTER_READ,即 0xD1。
		这是为什么需要左移一位的原因。
 * @return {*}无
 */
void MPU6050_WriteReg(uint8_t RegAddress, uint8_t Data)
{
    uint8_t res;
    i2c_cmd_handle_t cmd = i2c_cmd_link_create(); // 创建链接,装载容器
    i2c_master_start(cmd); // 产生起始信号
    i2c_master_write_byte(cmd, (MPU6050_Address << 1) | I2C_MASTER_WRITE, true); // 发送从机地址,并产生应答
    i2c_master_write_byte(cmd, RegAddress, true); // 发送从机数据寄存器的地址,并产生应答
    i2c_master_write_byte(cmd, Data, true); // 写入数据 并产生应答
    i2c_master_stop(cmd); // 产生停止信号
    res = i2c_master_cmd_begin(i2c_port, cmd, 100 / portTICK_PERIOD_MS); // 启动容器,开始工作
    i2c_cmd_link_delete(cmd); // 删除链接容器,避免占用资源

    if (res == ESP_OK) {
        ESP_LOGI(TAG, "MPU6050_WriteReg success - RegAddress: 0x%02X, Data: 0x%02X", RegAddress, Data);
    } else {
        ESP_LOGE(TAG, "MPU6050_WriteReg failed with error: %d - RegAddress: 0x%02X, Data: 0x%02X", res, RegAddress, Data);
    }
}

/**
 * @description: 读寄存器的数据
 * 
 * @param {uint8_t} RegAddress  寄存器地址,范围:参考MPU6050手册的寄存器描述
 * @return {*}读取寄存器的数据,范围:0x00~0xFF
 */
uint8_t MPU6050_ReadReg(uint8_t RegAddress)
{
    uint8_t Data = 0;
    uint8_t res;



	i2c_cmd_handle_t cmd = i2c_cmd_link_create(); // 创建链接,装载容器
	i2c_master_start(cmd); // 产生起始信号
	i2c_master_write_byte(cmd, (MPU6050_Address << 1) | I2C_MASTER_WRITE, true); // 发送从机地址,并产生应答
	i2c_master_write_byte(cmd, RegAddress, true); // 发送从机数据寄存器的地址,并产生应答

	// 开始在该寄存器下读数据
	i2c_master_start(cmd); // 产生起始信号
	i2c_master_write_byte(cmd, (MPU6050_Address << 1) | I2C_MASTER_READ, true); // 发送从机地址,读写位为1,表示即将读取,并产生应答
	i2c_master_read_byte(cmd, &Data, I2C_MASTER_LAST_NACK); // 读一个字节的数据至Data内,并且非应答
	i2c_master_stop(cmd); // 发送停止信号
	res = i2c_master_cmd_begin(i2c_port, cmd, 100 / portTICK_PERIOD_MS); // 启动容器,开始工作
	i2c_cmd_link_delete(cmd); // 删除链接,保证资源不会被一直占用

	if (res == ESP_OK) {
		ESP_LOGI(TAG, "MPU6050_ReadReg success - RegAddress: 0x%02X, Data: 0x%02X", RegAddress, Data);
	
	} else {
		ESP_LOGE(TAG, "MPU6050_ReadReg failed with error: %d - RegAddress: 0x%02X, retrying...", res, RegAddress);
		vTaskDelay(10 / portTICK_PERIOD_MS); // 延迟10ms后重试
	}
    

    return Data;
}

/**
 * @description: MPU5050初始化
 * @return {*}无
 */
void MPU6050_Init(void)
{
    uint8_t res;
    i2c_config_t i2c_config_InitStructure;
    i2c_config_InitStructure.clk_flags = 0; // 采用默认时钟
    i2c_config_InitStructure.master.clk_speed = 50000; // 通信速度 分为标准速度100kbps和快速400kbps,这里用标准速度即可
    i2c_config_InitStructure.mode = I2C_MODE_MASTER; // 主机模式
    i2c_config_InitStructure.scl_io_num = MPU6050_SCL_Pin; // 通信引脚,scl
    i2c_config_InitStructure.scl_pullup_en = GPIO_PULLUP_ENABLE; // scl 上拉使能
    i2c_config_InitStructure.sda_io_num = MPU6050_SDA_Pin; // sda引脚
    i2c_config_InitStructure.sda_pullup_en = GPIO_PULLUP_ENABLE; // sda 上拉使能

    res = i2c_param_config(i2c_port, &i2c_config_InitStructure);//配置参数
    if (res == ESP_OK) {
        ESP_LOGI(TAG, "i2c_param_config success");
    } else {
        ESP_LOGE(TAG, "i2c_param_config failed with error: %d", res);
    }

    res = i2c_driver_install(i2c_port, I2C_MODE_MASTER, 0, 0, 0); // 安装驱动
    if (res == ESP_OK) {
        ESP_LOGI(TAG, "i2c_driver_install success");
    } else {
        ESP_LOGE(TAG, "i2c_driver_install failed with error: %d", res);
    }

    MPU6050_WriteReg(MPU6050_PWR_MGMT_1, 0x01); // 唤醒mpu6050
    MPU6050_WriteReg(MPU6050_PWR_MGMT_2, 0x00);
    MPU6050_WriteReg(MPU6050_SMPLRT_DIV, 0x09); // 10分频
    MPU6050_WriteReg(MPU6050_CONFIG, 0x06); // 数字低通滤波器
    MPU6050_WriteReg(MPU6050_GYRO_CONFIG, 0x18); // 陀螺仪寄存器
    MPU6050_WriteReg(MPU6050_ACCEL_CONFIG, 0x18); // 加速度寄存器 最大量程
}



/**
  * 函    数:MPU6050获取ID号
  * 参    数:无
  * 返 回 值:MPU6050的ID号
  */
uint8_t MPU6050_GetID(void)
{
	return MPU6050_ReadReg(MPU6050_WHO_AM_I);

}



/**
  * 函    数:MPU6050获取数据
  * 参    数:AccX AccY AccZ 加速度计X、Y、Z轴的数据,使用输出参数的形式返回,范围:-32768~32767
  * 参    数:GyroX GyroY GyroZ 陀螺仪X、Y、Z轴的数据,使用输出参数的形式返回,范围:-32768~32767
  * 返 回 值:无
  * 具体选择转的角速度是多少 是通过比例公式计算出来的  读取的数据/32768  =  x /满量程  求x
  */
void MPU6050_GetData(int16_t *AccX, int16_t *AccY, int16_t *AccZ, 
						int16_t *GyroX, int16_t *GyroY, int16_t *GyroZ)
{
	uint8_t DataH,DataL;
	//读取加速度x轴寄存器的高八位
	DataH=MPU6050_ReadReg(MPU6050_ACCEL_XOUT_H);
	//读取加速度x轴寄存器的低八位
	DataL=MPU6050_ReadReg(MPU6050_ACCEL_XOUT_L);
	*AccX=(DataH<<8) | DataL;//读取
	
	//读取加速度y轴寄存器的高八位
	DataH=MPU6050_ReadReg(MPU6050_ACCEL_YOUT_H);
	//读取加速度y轴寄存器的低八位
	DataL=MPU6050_ReadReg(MPU6050_ACCEL_YOUT_L);
	*AccY=(DataH<<8) | DataL;  //返回出去
	
	
	//读取加速度z轴寄存器的高八位
	DataH=MPU6050_ReadReg(MPU6050_ACCEL_ZOUT_H);
	//读取加速度z轴寄存器的低八位       
	DataL=MPU6050_ReadReg(MPU6050_ACCEL_ZOUT_L);
	*AccZ=(DataH<<8) | DataL;  //返回出去
	
	
		
	//读取加速度z轴寄存器的高八位
	DataH=MPU6050_ReadReg(MPU6050_ACCEL_ZOUT_H);
	//读取加速度z轴寄存器的低八位       
	DataL=MPU6050_ReadReg(MPU6050_ACCEL_ZOUT_L);
	*AccZ=(DataH<<8) | DataL;  //返回出去
	
	
	DataH = MPU6050_ReadReg(MPU6050_GYRO_XOUT_H);		//读取陀螺仪X轴的高8位数据
	DataL = MPU6050_ReadReg(MPU6050_GYRO_XOUT_L);		//读取陀螺仪X轴的低8位数据
	*GyroX = (DataH << 8) | DataL;						//数据拼接,通过输出参数返回
	
	DataH = MPU6050_ReadReg(MPU6050_GYRO_YOUT_H);		//读取陀螺仪Y轴的高8位数据
	DataL = MPU6050_ReadReg(MPU6050_GYRO_YOUT_L);		//读取陀螺仪Y轴的低8位数据
	*GyroY = (DataH << 8) | DataL;						//数据拼接,通过输出参数返回
	
	DataH = MPU6050_ReadReg(MPU6050_GYRO_ZOUT_H);		//读取陀螺仪Z轴的高8位数据
	DataL = MPU6050_ReadReg(MPU6050_GYRO_ZOUT_L);		//读取陀螺仪Z轴的低8位数据
	*GyroZ = (DataH << 8) | DataL;						//数据拼接,通过输出参数返回
}

MPU6050.h

#ifndef __MPU6050_H__
#define __MPU6050_H__
void MPU6050_Init(void);
uint8_t MPU6050_ReadReg(uint8_t RegAddress);
void MPU6050_WriteReg(uint8_t RegAddress,uint8_t Data);
void MPU6050_GetData(int16_t *AccX, int16_t *AccY, int16_t *AccZ, 
						int16_t *GyroX, int16_t *GyroY, int16_t *GyroZ);
uint8_t MPU6050_GetID(void);

#endif


MPU6050_REG.h

#ifndef __MPU6050_REG_H__
#define __MPU6050_REG_H__
//存放MPU6050常用的寄存器地址
#define	MPU6050_SMPLRT_DIV		0x19   //分频值,值越小越快
#define	MPU6050_CONFIG			0x1A
#define	MPU6050_GYRO_CONFIG		0x1B
#define	MPU6050_ACCEL_CONFIG	0x1C

#define	MPU6050_ACCEL_XOUT_H	0x3B
#define	MPU6050_ACCEL_XOUT_L	0x3C
#define	MPU6050_ACCEL_YOUT_H	0x3D
#define	MPU6050_ACCEL_YOUT_L	0x3E
#define	MPU6050_ACCEL_ZOUT_H	0x3F
#define	MPU6050_ACCEL_ZOUT_L	0x40
#define	MPU6050_TEMP_OUT_H		0x41
#define	MPU6050_TEMP_OUT_L		0x42
#define	MPU6050_GYRO_XOUT_H		0x43
#define	MPU6050_GYRO_XOUT_L		0x44
#define	MPU6050_GYRO_YOUT_H		0x45
#define	MPU6050_GYRO_YOUT_L		0x46
#define	MPU6050_GYRO_ZOUT_H		0x47
#define	MPU6050_GYRO_ZOUT_L		0x48

#define	MPU6050_PWR_MGMT_1		0x6B
#define	MPU6050_PWR_MGMT_2		0x6C
#define	MPU6050_WHO_AM_I		0x75

#endif

main.c

/*
 * @Author: i want to 舞动乾坤
 * @Date: 2024-07-25 21:29:11
 * @LastEditors: i want to 舞动乾坤
 * @LastEditTime: 2024-07-26 09:26:14
 * @FilePath: \i2c_hardware_driver_mpu6050\main\main.c
 * @Description: 
 * 
 * Copyright (c) 2024 by i want to 舞动乾坤, All Rights Reserved. 
 */
#include <stdio.h>
#include "MPU6050.h"
#include <esp_log.h>
#include <freeRtos/FreeRTOS.h>
#include <freeRtos/task.h>
uint8_t ID;								//定义用于存放ID号的变量
int16_t AX, AY, AZ, GX, GY, GZ;			//定义用于存放各个数据的变量
void app_main(void)
{
    MPU6050_Init();
    ID=MPU6050_GetID();//获取设备ID
    ESP_LOGI("MPU6050 ID","#%x\n",ID);
    while(1)
	{
		MPU6050_GetData(&AX, &AY, &AZ, &GX, &GY, &GZ);//把六个变量的地址传递过去
        //显示六元组数据
        ESP_LOGI("AX value is","%d\n",AX);
        ESP_LOGI("AY value is","%d\n",AY);
        ESP_LOGI("AZ value is","%d\n",AZ);
        ESP_LOGI("GX value is","%d\n",GX);
        ESP_LOGI("GY value is","%d\n",GY);
        ESP_LOGI("GZ value is","%d\n",GZ);
        vTaskDelay(1000/portTICK_PERIOD_MS);//1000ms获取一次
	}
}

调试

在这里插入图片描述
参考大佬文章:【快速上手ESP32(基于ESP-IDF&VSCode)】

### 使用 ESP32-S3 驱动 MPU6050 传感器 对于使用 ESP32-S3 来驱动 MPU6050 传感器,硬件连接方式遵循 I²C 协议标准配置[^2]。具体来说: - **电源连接**:VCC 引脚应与 ESP32-S3 模块的 3.3V 输出相接以提供电力支持;GND 引脚需同 ESP32-S3 地线相连确保电路稳定工作。 - **I²C 数据线连接**:SCL 和 SDA 是 MPU6050 上用于通信的主要引脚。这些应该分别对应到 ESP32-S3 开发板上的 GPIO 管脚,默认情况下分别是 GPIO 22 (SCL) 和 GPIO 21 (SDA)。 为了实现上述功能,在软件方面推荐采用 Arduino IDE 平台进行编程开发。下面给出一段简单的代码示例来初始化并读取来自 MPU6050 的数据: ```cpp #include <Wire.h> #include "I2Cdev.h" #include "MPU6050_6Axis_MotionApps20.h" // 设备地址定义 #define MPU6050_ADDRESS 0x68 MPU6050 mpu; void setup() { Serial.begin(115200); Wire.begin(); Wire.setClock(400000); // 初始化 MPU6050 mpu.initialize(); if (!mpu.testConnection()) { Serial.println("MPU6050 connection failed"); while (true) {} } else { Serial.println("MPU6050 connected successfully!"); } // 加载 DMP 设置 devStatus = mpu.dmpInitialize(); } void loop() { // 获取新的传感器数据包大小 int packetSize = mpu.dmpGetFIFOPacketSize(); // 如果有足够的 FIFO 缓冲区空间,则尝试获取新数据 if (fifoCount >= packetSize) { mpu.getFIFOBytes(fifoBuffer, packetSize); // 解析原始加速度计和陀螺仪数据 mpu.dmpGetQuaternion(&q, fifoBuffer); mpu.dmpGetGravity(&gravity, &q); mpu.dmpGetYawPitchRoll(ypr, &q, &gravity); // 打印角度信息 Serial.print("yaw: "); Serial.print(ypr[0] * 180/M_PI); Serial.print(", pitch: "); Serial.print(ypr[1] * 180/M_PI); Serial.print(", roll: "); Serial.println(ypr[2] * 180/M_PI); } } ``` 这段程序实现了基本的数据采集流程,包括设置串口通讯波特率、启动 IIC 总线以及完成 MPU6050 芯片初始化操作等步骤。之后进入主循环部分不断从设备中提取最新的姿态角信息并通过串行端口打印出来供进一步处理分析之用。 需要注意的是,尽管 ESP32-S3 提供了相对充裕的内部 SRAM 容量(约 512KB),但在运行复杂应用时仍可能面临资源紧张的情况,因此建议优化算法结构减少不必要的开销[^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

i want to舞动乾坤

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值