假期战略更新第二集——MPU6050六轴传感器模块在stm32平台的使用一(今天不学习,明天变垃圾)

Laraine ·
更新时间:2024-09-20
· 900 次阅读

这个也是上学期一直困扰我的一个问题,上学期想要巩固一下自己PWM和PID算法的基础,就搞了一个STM32控制的平衡车来玩,算法数学模型啥的都弄好之后,就出现了一个大问题,本人用的是stm32cubeMX来建立的工程项目,所以在IIC的部分就出现了一些问题,我看了写资料,总结了一下经验,下面就先讲讲我的主要经验:

1.MPU6050模块是什么?
MPU6050模块是一个常用的六轴传感器模块,主要目的是获取以传感器为基点的欧拉角(偏航角、俯仰角、滚转角),可以理解为以传感器为中点,初始X正半轴与当前传感器前方所指的一个向量在XY平面的夹角,初始X正半轴与当前传感器在XZ平面的夹角,初始Y正半轴与当前传感器在YZ平面的夹角。这个想仔细理解的玩家朋友可以看看MPU6050的手册。该模块用过IIC总线和STM32进行通信。

2.MPU6050用来干嘛?
在文章开头我说我买了个stm32的平衡车,可以理解为硬件已经完全搭建好了,说到平衡车那就是普通的两个轮子那种,两个轮子不转,车肯定就站不稳,要车站稳的话就肯定要知道车的当前状态和什么情况是稳,什么情况是不稳,所以就用到了MPU6050的俯仰角。

3.MPU6050怎么用?
东西怎么用,还是要看芯片文档,现在就稍微总结一下MPU6050怎么用的,首先是通信方式,芯片把当前数据测量出来之后,就需要通过IIC总线发送给MCU进行处理,这里我用的是STM32F767作为处理芯片,在之前的使用中,我通过使能stm32cube的IIC来移植github上某大神已经写好的MPU6050驱动,发现卡在fifo的频率设置上,频率设置不能超过40,但是这个满足不了小车的稳定,使用上还存在各种问题,所以干脆就用了模拟IIC,使用下来效果不错,所以在MPU6050的问题上我就直接使用模拟IIC了,如果有大神可以用硬件IIC实现的话请不吝赐教。
通信方式解决之后就要知道怎么获取三个角了,首先是MPU6050模块自带了DMP姿态解算,通过MPU官方库的程序读取fifo中的四元数组quat后,将格式转为浮点型,通过除以官方给出的q30格式long转化为float的除数后进行对应运算来得到当前的三个角。
主要使用方法就是在模拟IIC总线调整到可以使用之后,移植官方的DMP库
,官方的MPU6050驱动之后在主函数进行MPU6050以及DMP初始化之后即可通过mpu_dmp_get_data来读取当前三个角的度数。

下面我把我使用的模拟iic的代码贴出来,使用的时候只需要更改c文件和h文件的gpio引脚即可

iicb.c

#include "iicb.h" static void delay_us(int s)//微秒延时函数,试出来的 { volatile int i = 7*s; while (i) i--; } //初始化IIC void IIC_InitB(void) { GPIO_InitTypeDef GPIO_Initure; __HAL_RCC_GPIOB_CLK_ENABLE(); GPIO_Initure.Pin=GPIO_PIN_6|GPIO_PIN_7; GPIO_Initure.Mode=GPIO_MODE_OUTPUT_PP; GPIO_Initure.Pull=GPIO_PULLUP; GPIO_Initure.Speed=GPIO_SPEED_FAST; HAL_GPIO_Init(GPIOB,&GPIO_Initure); IIC_SDAB(1); IIC_SCLB(1); } //IIC起始信号 void IIC_StartB(void) { SDA_OUTB(); IIC_SDAB(1); IIC_SCLB(1); delay_us(4); IIC_SDAB(0); delay_us(4); IIC_SCLB(0); } //IIC停止信号 void IIC_StopB(void) { SDA_OUTB();//sda线输出 IIC_SCLB(0); IIC_SDAB(0);//STOP:when CLK is high DATA change form low to high delay_us(4); IIC_SCLB(1); IIC_SDAB(1);//发送I2C总线结束信号 delay_us(4); } //等待应答信号到来 1.接收失败,2.成功 uint8_t IIC_Wait_AckB(void) { uint8_t ErrTime=0; SDA_INB(); //SDA设置为输入 IIC_SDAB(1);delay_us(1); IIC_SCLB(1);delay_us(1); while(READ_SDAB) { ErrTime++; if(ErrTime>250) { IIC_StopB(); return 1; } } IIC_SCLB(0); return 0; } //Ack应答信号 void IIC_AckB(void) { IIC_SCLB(0); SDA_OUTB(); IIC_SDAB(0); delay_us(2); IIC_SCLB(1); delay_us(2); IIC_SCLB(0); } //Ack拒绝应答 void IIC_NAckB(void) { IIC_SCLB(0); SDA_OUTB(); IIC_SDAB(1); delay_us(2); IIC_SCLB(1); delay_us(2); IIC_SCLB(0); } //IIC发送一个字节,从机有应答返回1,无应答返回0 void IIC_Send_ByteB(uint8_t txb) { uint8_t t; SDA_OUTB(); IIC_SCLB(0);//拉低时钟开始数据传输 for(t=0;t>7); txb<<=1; delay_us(2); IIC_SCLB(1); delay_us(2); IIC_SCLB(0); delay_us(2); } } //读1个字节 ack=1时,发送Ack,ack=0,发送NAck uint8_t IIC_Read_ByteB(unsigned char ack) { unsigned char i,receive=0; SDA_INB();//SDA设置为输入 for(i=0;i<8;i++ ) { IIC_SCLB(0); delay_us(2); IIC_SCLB(1); receive<<=1; if(READ_SDAB)receive++; delay_us(1); } if (!ack) IIC_NAckB();//发送NAck else IIC_AckB(); //发送Ack return receive; }

iicb.h

#ifndef __IICB_H #define __IICB_H #include "main.h" //IO方向设置 #define SDA_INB() {GPIOB->MODER&=~(3<MODER|=0<MODER&=~(3<MODER|=1<<(7*2);} //PB7输出模式 //IO操作 #define IIC_SCLB(n) (n?HAL_GPIO_WritePin(GPIOB,GPIO_PIN_6,GPIO_PIN_SET):HAL_GPIO_WritePin(GPIOB,GPIO_PIN_6,GPIO_PIN_RESET)) //SCL #define IIC_SDAB(n) (n?HAL_GPIO_WritePin(GPIOB,GPIO_PIN_7,GPIO_PIN_SET):HAL_GPIO_WritePin(GPIOB,GPIO_PIN_7,GPIO_PIN_RESET)) //SDA #define READ_SDAB HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_7) //输入SDA //IIC所有操作函数 void IIC_InitB(void); //初始化IIC的IO口 void IIC_StartB(void); //IIC开始信号 void IIC_StopB(void); //IIC停止信号 void IIC_Send_ByteB(uint8_t txb); //IIC发送一个字节 uint8_t IIC_Read_ByteB(unsigned char ack); //IIC读取一个字节 uint8_t IIC_Wait_AckB(void); //IIC等待ACK信号 void IIC_AckB(void); //IIC发送ACK信号 void IIC_NAckB(void); //IIC不发送ACK信号 void IIC_Write_One_ByteB(uint8_t daddr,uint8_t addr,uint8_t data); uint8_t IIC_Read_One_ByteB(uint8_t daddr,uint8_t addr); #endif

移植完iic之后记得测试一下再进行下面的操作,具体测试可以用逻辑分析仪搞一下。
IIC测试完成之后就可以将MPU6050的驱动代码拿来用了,用的时候记得把MPU_Write_Byte类似的需要IIC驱动的函数处理一下,使用之前测试好的IIC发送对应的MPU处理函数。
使用模拟IIC的MPU驱动在网上也可以找到,大家就可以自己找找看。
之后在main函数完成MPU6050初始化和DMP的初始化之后就能直接使用mpu_dmp_get_data函数来获取三个角了,下面是我的主函数,写的很简单,仅供参考(代码是使用stm32cube生成的,没有使能硬件iic);

/* USER CODE BEGIN Header */ /** ****************************************************************************** * @file : main.c * @brief : Main program body ****************************************************************************** * @attention * *

© Copyright (c) 2020 STMicroelectronics. * All rights reserved.

* * This software component is licensed by ST under BSD 3-Clause license, * the "License"; You may not use this file except in compliance with the * License. You may obtain a copy of the License at: * opensource.org/licenses/BSD-3-Clause * ****************************************************************************** */ /* USER CODE END Header */ /* Includes ------------------------------------------------------------------*/ #include "main.h" #include "usart.h" #include "gpio.h" /* Private includes ----------------------------------------------------------*/ /* USER CODE BEGIN Includes */ #include "stdio.h" #include "mpu6050B.h" #include "inv_mpuB.h" #include "inv_mpu_dmp_motion_driverB.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 */ float Pitch=0; float Roll=0; float Yaw=0; int mpu_work_flag=0; /* 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 */ /* USER CODE END 0 */ /** * @brief The application entry point. * @retval int */ int main(void) { /* USER CODE BEGIN 1 */ int t=0; /* 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_USART1_UART_Init(); /* USER CODE BEGIN 2 */ printf("Gas\r\n"); printf("%d\r\n",MPU6050_InitB()); printf("%d\r\n",mpu_dmp_initB()); /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ if(!mpu_dmp_get_dataB(&Pitch,&Roll,&Yaw)) printf("%d,%f,%f,%f\r\n",t,Pitch,Roll,Yaw); t++; HAL_Delay(200); HAL_GPIO_TogglePin(GPIOB, LED0_Pin); } /* USER CODE END 3 */ } /** * @brief System Clock Configuration * @retval None */ void SystemClock_Config(void) { RCC_OscInitTypeDef RCC_OscInitStruct = {0}; RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0}; /** Configure the main internal regulator output voltage */ __HAL_RCC_PWR_CLK_ENABLE(); __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE3); /** Initializes the CPU, AHB and APB busses clocks */ RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE; RCC_OscInitStruct.HSEState = RCC_HSE_ON; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; RCC_OscInitStruct.PLL.PLLM = 25; RCC_OscInitStruct.PLL.PLLN = 288; RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2; RCC_OscInitStruct.PLL.PLLQ = 2; if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { Error_Handler(); } /** Initializes the CPU, AHB and APB busses 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_DIV2; 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(); } PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_USART1; PeriphClkInitStruct.Usart1ClockSelection = RCC_USART1CLKSOURCE_PCLK2; if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != 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 */ /* 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, tex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */ /* USER CODE END 6 */ } #endif /* USE_FULL_ASSERT */ /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

接下来是结果演示,我用了serialchart来把MPU6050采集到的三个角通过串口发送的数据画成图象表示出来了。
serialchart
我均匀转动三个角之后得到了上面的图,红绿蓝三个颜色分别代表三个不同角的角度,由图可以发现三个颜色分别明显的转动了两个周期,可知实验成功。


作者:ASWaterbenben



stm32 模块 更新 学习 传感器

需要 登录 后方可回复, 如果你还没有账号请 注册新账号
相关文章