一篇文章带你学会MPU6050六轴传感器的基本运用(基于STM32F103HAL库)看完必懂(附开源程序)

一:基础知识

1-1:I2C通信

1-1-1:I2C介绍

I2C Inter IC Bus )是由 Philips 公司开发的一种通用数据总线
两根通信线: SCL Serial Clock )、 SDA Serial Data
同步,半双工
带数据应答
支持总线挂载多设备(一主多从、多主多从)

1-1-2:硬件电路

所有 I2C 设备的 SCL 连在一起, SDA 连在一起
设备的 SCL SDA 均要配置成开漏输出模式
SCL SDA 各添加一个上拉电阻,阻值一般为 4.7KΩ 左右

1-1-3:I2C时序基本单元I2C时序基本单元I2C时序基本单元

起始条件: SCL 高电平期间, SDA 从高电平切换到低电平
 终止条件: SCL 高电平期间, SDA 从低电平切换到高电平

           

发送一个字节: SCL 低电平期间,主机将数据位依次放到 SDA 线上(高位先行),然后释放 SCL ,从机将在 SCL 高电平期间读取数据位,所以 SCL 高电平期间 SDA 不允许有数据变化,依次循环上述过程 8 次,即可发送一个字节

接收一个字节: SCL 低电平期间,从机将数据位依次放到 SDA 线上(高位先行),然后释放 SCL ,主机将在 SCL 高电平期间读取数据位,所以 SCL 高电平期间 SDA 不允许有数据变化,依次循环上述过程 8 次,即可接收一个字节(主机在接收之前,需要释放 SDA

发送应答:主机在接收完一个字节之后,在下一个时钟发送一位数据,数据 0 表示应答,数据 1 表示非应答
接收应答:主机在发送完一个字节之后,在下一个时钟接收一位数据,判断从机是否应答,数据 0 表示应答,数据 1 表示非应答(主机在接收之前,需要释放 SDA

1-1-4:I2C时序

指定地址写
对于指定设备( Slave Address ),在指定地址( Reg Address )下,写入指定数据( Data

当前地址读
对于指定设备( Slave Address ),在当前地址指针指示的地址下,读取从机数据( Data
指定地址读
对于指定设备( Slave Address ),在指定地址( Reg Address )下,读取从机数据( Data

1-2:MPU6050介绍

1-2-1:MPU6050简介

MPU6050 是一个 6 轴姿态传感器,可以测量芯片自身 X Y Z 轴的加速度、角速度参数,通过数据融合,可进一步得到姿态角,常应用于平衡车、飞行器等需要检测自身姿态的场景
3 轴加速度计( Accelerometer ):测量 X Y Z 轴的加速度
3 轴陀螺仪传感器( Gyroscope ):测量 X Y Z 轴的角速度

1-2-2:MPU6050参数

16 ADC 采集传感器的模拟信号,量化范围: -32768~32767
加速度计满量程选择: ±2 ±4 ±8 ±16 g
陀螺仪满量程选择: ±250 ±500 ±1000 ±2000 °/sec
可配置的数字低通滤波器
可配置的时钟源
可配置的采样分频

1-2-3:硬件电路

引脚定义

XDA XCL 用于外接磁力计将6轴传感器扩展到9轴

1-2-4:结构框图

二:程序代码编写
 

2-1:Cube MX配置

默认开启I2C1和USART1即可,USART用于后期通过串口进行调试和查看数据

2-2:代码编写

2-2-1:初始化I2C接口

根据手册的第9章接口部分描述:
MPU6050作为从机与系统通信的最大速率为400KHz,且从机地址为b110100(x由ADO引脚决定,接地时为0,接VCC为1)

2-2-2:操作寄存器

以下截至寄存器组手册:
定义MPU6050内部地址为(传感器采样率,加速度和陀螺仪的量程我们取典型值):
#define	MPU6050_SMPLRT_DIV		0x19  // 陀螺仪采样率,典型值:0x07(125Hz)
#define	MPU6050_CONFIG			0x1A  // 低通滤波频率,典型值:0x06(5Hz)
#define	MPU6050_GYRO_CONFIG		0x1B  // 陀螺仪自检及测量范围,典型值:0x18(不自检,2000deg/s)
#define	MPU6050_ACCEL_CONFIG	0x1C  // 加速计自检、测量范围及高通滤波频率,典型值:0x01(不自检,2G,5Hz)

#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 //电源管理,典型值:0x00(正常启用)
#define	MPU6050_PWR_MGMT_2		0x6C
#define	MPU6050_WHO_AM_I		0x75 //IIC地址寄存器(默认数值0x68,只读)

2-2-2-1:写寄存器

代码如下:
/**********************************************************************
 * 函数名称: MPU6050_WriteRegister
 * 功能描述: 写MPU6050寄存器
 * 输入参数: reg-寄存器地址, data-要写入的数据
 * 输出参数: 无
 * 返 回 值: 0 - 成功, 其他值 - 失败

 ***********************************************************************/
static int MPU6050_WriteRegister(uint8_t reg, uint8_t data)
{
    uint8_t tmpbuf[2];

    tmpbuf[0] = reg;
    tmpbuf[1] = data;
    
    return HAL_I2C_Master_Transmit(g_pHI2C_MPU6050, MPU6050_I2C_ADDR, tmpbuf, 2, MPU6050_TIMEOUT);
}

2-2-2-2:读寄存器
代码如下:
/**********************************************************************
 * 函数名称: MPU6050_ReadRegister
 * 功能描述: 读MPU6050寄存器
 * 输入参数: reg-寄存器地址
 * 输出参数: pdata-用来保存读出的数据
 * 返 回 值: 0 - 成功, 其他值 - 失败

 ***********************************************************************/
int MPU6050_ReadRegister(uint8_t reg, uint8_t *pdata)
{
	return HAL_I2C_Mem_Read(g_pHI2C_MPU6050, MPU6050_I2C_ADDR, reg, 1, pdata, 1, MPU6050_TIMEOUT);
}
2-2-2-3:设备唤醒&复位
综上,初始化代码如下:
/**********************************************************************
 * 函数名称: MPU6050_Init
 * 功能描述: MPU6050初始化函数,
 * 输入参数: 无
 * 输出参数: 无
 * 返 回 值: 0 - 成功, 其他值 - 失败

 ***********************************************************************/
int MPU6050_Init(void)
{
	MPU6050_WriteRegister(MPU6050_PWR_MGMT_1, 0x00);	//解除休眠状态
	MPU6050_WriteRegister(MPU6050_PWR_MGMT_2, 0x00);
	MPU6050_WriteRegister(MPU6050_SMPLRT_DIV, 0x09);
	MPU6050_WriteRegister(MPU6050_CONFIG, 0x06);
	MPU6050_WriteRegister(MPU6050_GYRO_CONFIG, 0x18);
	MPU6050_WriteRegister(MPU6050_ACCEL_CONFIG, 0x18);
    return 0;
}

2-2-3:从寄存器中读取原始数据

其中:

只需要通过I2C读取这些连续的寄存器,进行简单的换算就可以得到原始的数据值

代码如下:

/**********************************************************************
 * 函数名称: MPU6050_ReadData
 * 功能描述: 读取MPU6050数据
 * 输入参数: 无
 * 输出参数: pAccX/pAccY/pAccZ         - 用来保存X/Y/Z轴的加速度
 *            pGyroX/pGyroY/pGyroZ - 用来保存X/Y/Z轴的角速度
 * 返 回 值: 0 - 成功, 其他值 - 失败

 ***********************************************************************/
int MPU6050_ReadData(int16_t *pAccX, int16_t *pAccY, int16_t *pAccZ, int16_t *pGyroX, int16_t *pGyroY, int16_t *pGyroZ)
{
	uint8_t datal, datah;
    int err = 0;
	
	err |= MPU6050_ReadRegister(MPU6050_ACCEL_XOUT_H, &datah);
	err |= MPU6050_ReadRegister(MPU6050_ACCEL_XOUT_L, &datal);
	if(pAccX)
        *pAccX = (datah << 8) | datal;
	
	err |= MPU6050_ReadRegister(MPU6050_ACCEL_YOUT_H, &datah);
	err |= MPU6050_ReadRegister(MPU6050_ACCEL_YOUT_L, &datal);
	if(pAccY)
        *pAccY = (datah << 8) | datal;
	
	err |= MPU6050_ReadRegister(MPU6050_ACCEL_ZOUT_H, &datah);
	err |= MPU6050_ReadRegister(MPU6050_ACCEL_ZOUT_L, &datal);
	if(pAccZ)
        *pAccZ = (datah << 8) | datal;


	err |= MPU6050_ReadRegister(MPU6050_GYRO_XOUT_H, &datah);
	err |= MPU6050_ReadRegister(MPU6050_GYRO_XOUT_L, &datal);
	if(pGyroX)
        *pGyroX = (datah << 8) | datal;

	
	err |= MPU6050_ReadRegister(MPU6050_GYRO_YOUT_H, &datah);
	err |= MPU6050_ReadRegister(MPU6050_GYRO_YOUT_L, &datal);
	if(pGyroY)
        *pGyroY = (datah << 8) | datal;
	
	err |= MPU6050_ReadRegister(MPU6050_GYRO_ZOUT_H, &datah);
	err |= MPU6050_ReadRegister(MPU6050_GYRO_ZOUT_L, &datal);
	if(pGyroZ)
        *pGyroZ = (datah << 8) | datal;

    return err;	
}

至此,一个简单的MPU6050程序就写好了

2-2-4:.h文件的编写


#ifndef MPU6050_H
#define MPU6050_H

#include <stdint.h>


int MPU6050_Init(void);


int MPU6050_GetID(void);


int MPU6050_ReadData(int16_t *pAccX, int16_t *pAccY, int16_t *pAccZ, int16_t *pGyroX, int16_t *pGyroY, int16_t *pGyroZ);



#endif 

2-2-5:示例程序

一下是一个简单的示例程序,通过晃动MPU6050,串口以1s的时间间隔打印对应得到的数据

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2024 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "i2c.h"
#include "usart.h"
#include "gpio.h"


/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "string.h"
#include "stdio.h"
#include <stdarg.h>
#include "MPU6050.h"
/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */

/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/

/* USER CODE BEGIN PV */

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */

static void UART_Printf(const char *format, ...)
{
	char tmp[128];
	
	va_list argptr;
	va_start(argptr, format);
	vsprintf((char* )tmp, format, argptr);
	va_end(argptr);
	
	HAL_UART_Transmit(&huart1, (const uint8_t *)&tmp, strlen(tmp), HAL_MAX_DELAY);
}

/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{

  /* USER CODE BEGIN 1 */
	

	

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_I2C1_Init();
  MX_USART1_UART_Init();
  /* USER CODE BEGIN 2 */

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  
  	UART_Printf("start!!!");
	
	int id;
    int16_t AccX, AccY, AccZ, GyroX, GyroY, GyroZ;
	MPU6050_Init();
	id = MPU6050_GetID();
	HAL_Delay(1000);
  while (1)
  {
	  
	  MPU6050_ReadData(&AccX, &AccY, &AccZ, &GyroX, &GyroY, &GyroZ);
	  
	  
    /* USER CODE END WHILE */
	   UART_Printf("ID:%d \r\n",id);
	   UART_Printf("X:%d     ",AccX);
	   UART_Printf("Y:%d     ",AccY);
	   UART_Printf("Z:%d     \r\n",AccZ);
	  
	   UART_Printf("Gx:%d    ",GyroX);
	   UART_Printf("Gy:%d    ",GyroY);
	   UART_Printf("Gz:%d    \r\n",GyroZ);
	  
	  UART_Printf("    \r\n");
	  
	  HAL_Delay(2000);
	  
    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }

  /** Initializes the CPU, AHB and APB buses clocks
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK)
  {
    Error_Handler();
  }
}

/* USER CODE BEGIN 4 */

/* USER CODE END 4 */

/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */
  __disable_irq();
  while (1)
  {
  }
  /* USER CODE END Error_Handler_Debug */
}

#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

三:程序开源

文件夹内附文章keil代码和Cube MX工程

CSDN链接:【免费】基于STM32F103HAL库的MPU6050程序资源-CSDN文库

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值