打印
[应用相关]

STM32之MPU6050获取欧拉角

[复制链接]
手机看帖
扫描二维码
随时随地手机跟帖
41
发顺丰更大nc|  楼主 | 2023-12-28 16:25 | 只看该作者 |只看大图 回帖奖励 |倒序浏览
添加文件delay.h#include "main.h"

void delay_us(uint32_t n);

void delay_ms(uint32_t n);

void get_ms(unsigned long *time);

使用特权

评论回复
42
发顺丰更大nc|  楼主 | 2023-12-28 16:26 | 只看该作者
添加文件my_i2c.c
#include "gpio.h"
#include "delay.h"
#include "my_i2c.h"

#define scl_pin GPIO_PIN_6
#define sda_pin GPIO_PIN_7

#define scl_gpio GPIOB
#define sda_gpio GPIOB

#define SCL_HIGH HAL_GPIO_WritePin(scl_gpio, scl_pin, GPIO_PIN_SET)
#define SCL_LOW HAL_GPIO_WritePin(scl_gpio, scl_pin, GPIO_PIN_RESET)

#define SDA_HIGH HAL_GPIO_WritePin(scl_gpio, sda_pin, GPIO_PIN_SET)
#define SDA_LOW HAL_GPIO_WritePin(sda_gpio, sda_pin, GPIO_PIN_RESET)
#define SDA_READ HAL_GPIO_ReadPin(sda_gpio, sda_pin)


static void i2c_delay_us()
{
        delay_us(2);  //延时2微秒
}

void IIC_gpio_init()
{
        // 打开时钟
  __HAL_RCC_GPIOB_CLK_ENABLE();

        GPIO_InitTypeDef GPIO_InitStruct = {0};
       
        /* 初始化SCL引脚 */
    GPIO_InitStruct.Pin    = scl_pin;  /* SCL引脚 */
    GPIO_InitStruct.Mode   = GPIO_MODE_OUTPUT_PP;          /* 推挽输出 */
    GPIO_InitStruct.Pull   = GPIO_PULLUP;                  /* 上拉 */
    GPIO_InitStruct.Speed  = GPIO_SPEED_FREQ_HIGH;         /* 高速 */
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
   
    /* 初始化SDA引脚 */
    GPIO_InitStruct.Pin    = sda_pin;  /* SDA引脚 */
    GPIO_InitStruct.Mode   = GPIO_MODE_OUTPUT_OD;          /* 开漏输出 */
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
       
        IIC_stop();
}


/* 起始信号 */
void IIC_start()
{
    SCL_HIGH;
    SDA_HIGH;
    i2c_delay_us();
    SDA_LOW;
    i2c_delay_us();
    SCL_LOW;
    i2c_delay_us();
}

/* 终止信号 */
void IIC_stop()
{
    SDA_LOW;
    i2c_delay_us();
    SCL_HIGH;
    i2c_delay_us();
    SDA_HIGH;
    i2c_delay_us();
}

/* 检测应答信号:ACK返回0,NACK返回1 */
uint8_t IIC_wait_ack()
{
    SDA_HIGH;    /* 释放数据线 */
    i2c_delay_us();
    SCL_HIGH; /* 从机返回ACK */
    i2c_delay_us();

               
    if (SDA_READ == GPIO_PIN_SET)  /* 读取SDA的电平 */
    {
        /* 如果是高电平则为NACK */
        IIC_stop();
        return 1;
    }

    SCL_LOW; /* 结束应答信号的检测 */
    i2c_delay_us();
    return 0;
}

/* 应答信号 */
void IIC_ack()
{
    SDA_LOW;
    i2c_delay_us();
    SCL_HIGH;
    i2c_delay_us();
    SCL_LOW;
    i2c_delay_us();
    SDA_HIGH;
    i2c_delay_us();
}

/* 非应答信号 */
void IIC_nack()
{
    SDA_HIGH;
    i2c_delay_us();
    SCL_HIGH;
    i2c_delay_us();
    SCL_LOW;
    i2c_delay_us();
}

/* 发送一个字节数据 */
void IIC_send_byte(uint8_t data)
{
    for (uint8_t i = 0; i < 8; i++)
    {
        /* 从最高位开始发送 */
        if ((data & 0x80) >> 7)
        {
            SDA_HIGH;
        }
        else
        {
            SDA_LOW;
        }
        i2c_delay_us();
        SCL_HIGH;
        i2c_delay_us();
        SCL_LOW;
        data <<= 1; /* 将下一位移至最高位 */
    }
    SCL_HIGH; /* 发送完成,释放数据线*/
}


/* 读取一个字节数据 */
uint8_t IIC_read_byte(uint8_t ack)
{
        uint8_t receive = 0;
        for (uint8_t i = 0; i < 8; i++)
        {
                /* 发送数据时,从高位先发送 */
                receive = receive << 1; /* 先收到的数据要左移 */
                SCL_HIGH;
                i2c_delay_us();
                if (SDA_READ)
                {
                        receive++;
                }
                SCL_LOW;
                i2c_delay_us();
        }
        if (!ack)
        {
                IIC_nack();
        }
        else
        {
                IIC_ack();
        }
        return receive;
}

使用特权

评论回复
43
发顺丰更大nc|  楼主 | 2023-12-28 16:27 | 只看该作者
添加文件my_i2c.h
#include "main.h"

static void i2c_delay_us(void);

void IIC_gpio_init(void);

/* 起始信号 */
void IIC_start(void);


/* 终止信号 */
void IIC_stop(void);


/* 检测应答信号:ACK返回0,NACK返回1 */
uint8_t IIC_wait_ack(void);


/* 应答信号 */
void IIC_ack(void);


/* 非应答信号 */
void IIC_nack(void);


/* 发送一个字节数据 */
void IIC_send_byte(uint8_t data);



/* 读取一个字节数据 */
uint8_t IIC_read_byte(uint8_t ack);

使用特权

评论回复
44
发顺丰更大nc|  楼主 | 2023-12-28 16:38 | 只看该作者
main.c文件编写/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2023 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 "usart.h"
#include "gpio.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */

#include <stdio.h>
#include "mpu6050.h"
#include "delay.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 */

/* 加速度原始数据 */
int16_t accelerated_speed_x = 0;
int16_t accelerated_speed_y = 0;
int16_t accelerated_speed_z = 0;

/* 陀螺仪原始数据 */
int16_t gyroscope_x = 0;
int16_t gyroscope_y = 0;
int16_t gyroscope_z = 0;

/* 温度传感器原始数据 */
float temperature = 0;

/* 三轴加速度 */
float ax = 0;
float ay = 0;
float az = 0;

/* 三轴陀螺仪 */
float gx = 0;
float gy = 0;
float gz = 0;


/* 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_USART3_UART_Init();
  /* USER CODE BEGIN 2 */

        mpu6050_init();
       

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
               
                /* 获取mpu6050原始数据 */
                mpu6050_read_accelerated_speed(&accelerated_speed_x,&accelerated_speed_y,&accelerated_speed_z);
                mpu6050_read_gyroscope(&gyroscope_x,&gyroscope_y,&gyroscope_z);
                temperature = mpu6050_read_temperature();
               
                /*
                printf("ax:%d\r\nay:%d\r\naz:%d\r\n",accelerated_speed_x,accelerated_speed_y,accelerated_speed_z);
                printf("gx:%d\r\ngy:%d\r\ngz:%d\r\n",gyroscope_x,gyroscope_y,gyroscope_z);
                printf("temperature:%f\r\n",temperature);
                */
               
               
                ax = accelerated_speed_x/16384.0;
                ay = accelerated_speed_y/16384.0;
                az = accelerated_speed_z/16384.0;
               
                gx = gyroscope_x/16.4;
                gy = gyroscope_y/16.4;
                gz = gyroscope_z/16.4;
               
                printf("ax:%f\r\nay:%f\r\naz:%f\r\n",ax,ay,az);
                printf("gx:%f\r\ngy:%f\r\ngz:%f\r\n",gx,gy,gz);
                printf("temperature:%f\r\n",temperature);
               
               
                delay_ms(100);
               
                usart1_receive_data_handle();
               
  }
  /* 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_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
  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_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != 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 */

使用特权

评论回复
45
发顺丰更大nc|  楼主 | 2023-12-28 16:38 | 只看该作者
DMP介绍
嵌入式数字运动处理器(Digital Motion Processor)位于 mpu6050 内部,可从主机处理器中卸载运动处理算法的运算。 DMP从加速度计,陀螺仪以及其他第三方传感器(如磁力计)获取数据,并处理数据。结果数据可以从DMP的寄存器中读取,或者可以在FIFO中缓冲。 DMP可以访问其中的一个MPU的外部引脚,可用于产生中断。

使用特权

评论回复
46
发顺丰更大nc|  楼主 | 2023-12-28 16:38 | 只看该作者
使用DMP的目的
DMP的目的是卸载主机处理器的时序要求和处理能力。通常,运动处理算法应该以高速运行,通常在200Hz左右,以提供低延迟的精确结果。即使应用程序以更低的速率更新,这也是必需的。例如,一个低功率的用户界面可能会以5Hz的速度更新,但运动处理仍然应该以200Hz运行。 DMP可以作为一种工具使用,以最大限度地降低功耗,简化定时,简化软件架构,并在主机处理器上节省宝贵的MIPS,以便在应用中使用。
.

使用特权

评论回复
47
发顺丰更大nc|  楼主 | 2023-12-28 16:39 | 只看该作者
使用DMP将MPU6050的原始数据转换成欧拉角
在前面代码中,已经介绍了如何获取 mpu6050 的加速度计和陀螺仪的原始数据,但是这些原始数据并不是姿态数据。姿态数据也就是欧拉角:俯仰角(pitch)、横滚角(roll)、航向角(yaw),通过欧拉角就能够非常直观地了解当前三轴的姿态。想要得到欧拉角数据,就需要对原始数据进行姿态融合解算,姿态结算涉及较多的数学计算,如果我们直接利用原始数据进行姿态解算,不仅要求开发者有较丰富的知识储备和一定的数学能力,同时对 MCU 的运算性能也有较高的要求。而 mpu6050 自带的 DMP(数字运动处理器)就能够很好的解决这一些列的问题,配合 InvenSense 提供的 DMP 驱动库,就能够很方便地将 MPU-6050 输出的原始数据直接转换为四元数输出,在得到四元数之后,就能够通过少量的运算,计算出欧拉角,从而得到姿态数据。

使用特权

评论回复
48
发顺丰更大nc|  楼主 | 2023-12-28 16:39 | 只看该作者
移植DMP库
nvenSense公司 提供的 DMP 驱动库是基于 MSP430 的,因此要在 STM32 上使用该 DMP 驱动库,还需要进行一定的移植。
我们可以参考这篇文章进行移植DMP库。STM32平台下官方DMP库6.12超详细移植教程
正点原子同样提供了移植好了的DMP库,轮子能用就行,我们可以基于该正点原子的DMP库进行修改。

使用特权

评论回复
49
发顺丰更大nc|  楼主 | 2023-12-28 16:39 | 只看该作者
STM32F103系列移植正点原子DMP库
1. 将DMP库搬运到自己的工程目录底下。

使用特权

评论回复
50
发顺丰更大nc|  楼主 | 2023-12-28 16:39 | 只看该作者
2. 将DMP库添加到工程中
这一步是添加DMP库相关的.c文件

使用特权

评论回复
51
发顺丰更大nc|  楼主 | 2023-12-28 16:39 | 只看该作者
这一步是添加DMP库相关的.h文件

使用特权

评论回复
52
发顺丰更大nc|  楼主 | 2023-12-28 16:40 | 只看该作者
3. 修改inv_npu.c文件

修改头文件。
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include "inv_mpu.h"
#include "inv_mpu_dmp_motion_driver.h"
#include "mpu6050.h"
#include "delay.h"
#include "usart.h"

使用特权

评论回复
53
发顺丰更大nc|  楼主 | 2023-12-28 16:40 | 只看该作者

使用特权

评论回复
54
发顺丰更大nc|  楼主 | 2023-12-28 16:40 | 只看该作者
修改后

使用特权

评论回复
55
发顺丰更大nc|  楼主 | 2023-12-28 16:40 | 只看该作者
修改部分宏定义。#define MPU6050
#define MOTION_DRIVER_TARGET_MSP430

#define i2c_write   mpu6050_write_len                       
#define i2c_read    mpu6050_read_len                        
#define delay_ms    delay_ms                              
#define get_ms      get_ms     

#define log_e    printf
#define log_i    printf

使用特权

评论回复
56
发顺丰更大nc|  楼主 | 2023-12-28 16:40 | 只看该作者

使用特权

评论回复
57
发顺丰更大nc|  楼主 | 2023-12-28 16:40 | 只看该作者
修改后

使用特权

评论回复
58
发顺丰更大nc|  楼主 | 2023-12-28 16:42 | 只看该作者
修改hw结构体的addr值,如果在(mpu6050_write_len、mpu6050_read_len)mpu6050连续写和mpu6050连续读函数里没有左移mpu6050的7位I2C地址就填0xD0,如果左移了就填0x68。(可选)

使用特权

评论回复
59
发顺丰更大nc|  楼主 | 2023-12-28 16:42 | 只看该作者

使用特权

评论回复
60
发顺丰更大nc|  楼主 | 2023-12-28 16:42 | 只看该作者
修改后

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则