前段时间在做平衡车,需要移植MPU6050程序。但是在网上找了挺多相关例子的,但是有时候一步步跟着做,结果还是一堆errors 或者读不出数据来,最后自己花了些时间,终于移植好了,前来分享一下。

先分享我的工程,和需要移植的MPU6050的程序

完整工程 + MPU6050移植程序

提取码:3ycr

效果演示

接下来进入正题:

一、首先在CubeMX中创建工程

1. 先正常配置RCC、SYS和时钟树。

2. 我这里选择PB6和PB7读MPU6050用、打开了串口1、并且我打开了4个脚给OLED用。

3. 然后生成工程好了。

二、程序移植

1. 我们把下载到的MPU6050程序添加到工程中,加入.c文件,并且把头文件路径也添加进来。

2. #include "头文件"  

代码放这里 

#include "mpu6050.h"//MPU6050驱动库
#include "inv_mpu.h"//陀螺仪驱动库
#include "inv_mpu_dmp_motion_driver.h" //DMP姿态解读库读库

#include "XMF_OLED_STM32Cube.h" //OLED头文件
#include "stdio.h"		//使用printf用

此时编译会发现报很多错 

三、修改程序 

 1. 把这下面几个文件,用main.h 代替 sys.h 和 stm32f10x.h 

 2. 然后再main.h文件下加入下面这些

 代码放这里

typedef unsigned int u32;
typedef unsigned short u16;
typedef unsigned char u8;

//位带操作,实现51类似的GPIO控制功能
//具体实现思想,参考<<CM3权威指南>>第五章(87页~92页).
//IO口操作宏定义
#define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x2000000+((addr &0xFFFFF)<<5)+(bitnum<<2)) 
#define MEM_ADDR(addr)  *((volatile unsigned long  *)(addr)) 
#define BIT_ADDR(addr, bitnum)   MEM_ADDR(BITBAND(addr, bitnum)) 
//IO口地址映射
#define GPIOB_ODR_Addr    (GPIOB_BASE+12) //0x40010C0C 
#define GPIOB_IDR_Addr    (GPIOB_BASE+8) //0x40010C08 

//IO口操作,只对单一的IO口!
//确保n的值小于16!
#define PBout(n)   BIT_ADDR(GPIOB_ODR_Addr,n)  //输出 
#define PBin(n)    BIT_ADDR(GPIOB_IDR_Addr,n)  //输入 

3. 自己创建delay.c 和 delay.h 文件 加入工程,包含头文件路径.分别在里面加入下面这些代码

delay.h

#ifndef __DELAY_H
#define __DELAY_H 	

#include "main.h"
	
void delay_ms(u16 nms);
void delay_us(u32 nus);

#endif

delay.c

#include "delay.h"
	    								   
void delay_us(u32 nus)
{		
	uint32_t us_tick=SystemCoreClock / 1000000UL;
	uint32_t start,now,JianGe,reload;
	start=SysTick->VAL;              //把最开始获得的计数值作为基准值
	reload = SysTick->LOAD;
	do{
	 now=SysTick->VAL;				//获取当前值
		JianGe = start > now ? start - now : reload + start - now;
	}while(JianGe<nus*us_tick);			 //判断是否到达间隔

}

void delay_ms(u16 nms)
{	 		  	  
	HAL_Delay(nms);	
} 

4. 把mpuiic.c里面的下图内容注释掉

5.接下来编译就可以通过啦

 四、在main.c下面加入串口重定向,以及 MPU6050的一些变量 ,再加入读数据的函数就大功告成啦 !

代码放这里

#pragma import(__use_no_semihosting)             
//标准库需要的支持函数    
struct __FILE 
{ 
	int handle; 
}; 

FILE __stdout;       
//定义_sys_exit()以避免使用半主机模式    
void _sys_exit(int x) 
{ 
	x = x; 
} 
//重定义fputc函数 
int fputc(int ch, FILE *f)
{      
	while((USART1->SR&0X40)==0);//循环发送,直到发送完毕   
    USART1->DR = (u8) ch;      
	return ch;
}

float pitch,roll,yaw; 		//欧拉角:俯仰角,滚转角,偏航角
short aacx,aacy,aacz;		//加速度传感器原始数据  加速度
short gyrox,gyroy,gyroz;	//陀螺仪原始数据  角速度
short temp;					//MPU温度
uint8_t str_buff[64];
uint8_t str_buff1[64]="俯仰角:";		//pitch
uint8_t str_buff2[64]="偏航角:";		//yaw
uint8_t str_buff3[64]="翻滚角:";		//roll
uint8_t str_buff4[64]="温度值:";

struct MPU6050				//MPU6050结构体
{
	u8 flag;				//采集成功标志位
	u8 speed;				//上报速度
}mpu6050;					//唯一结构体变量

 读数据的一些函数 放再这下面  有MPU_Read 和 DATA_Report 两个函数

 代码放这里

void MPU_Read(void)
{
	
	if(mpu_dmp_get_data(&pitch,&roll,&yaw)==0)//dmp处理得到数据,对返回值进行判断
	{ 
//		temp=MPU_Get_Temperature();	              //得到温度值
		MPU_Get_Accelerometer(&aacx,&aacy,&aacz);	//得到加速度传感器数据
		MPU_Get_Gyroscope(&gyrox,&gyroy,&gyroz);	//得到陀螺仪数据
		mpu6050.speed++;                          //上报速度自加
		if(mpu6050.speed == 4)						//上报速度阈值设置
		{
			mpu6050.flag = 1;						//采集成功标志位设置为有效
			mpu6050.speed = 0;						//上报速度归零
		}	
	}
	else 											//采集不成功										
	{
		mpu6050.flag = 0;							//采集成功标志位设置为无效
	}	
}
/**
  * @brief  MPU6050数据上报
  * @param  无
  * @retval 无
  */
void DATA_Report(void)
{
	if(mpu6050.flag == 1)						//采集成功时
	{ 
		if(temp<0)								//对数据正负判断,判断为负时
		{
			temp=-temp;							//对负数据取反
		}
		else                                    //判断为正时
		{
		}
//		sprintf((char *)str_buff,"%d.%d",temp/100,temp%10);
//		OLED_ShowString(60,0,str_buff);
//		printf("temp:%d.%d --- ",temp/100,temp%10); //通过串口1输出温度
		
		temp=pitch*10;							 //赋temp为pitch
		if(temp<0)								//对数据正负判断,判断为负时
		{
			temp=-temp;						    //对负数据取反		
		}
		else                                    //判断为正时 
		{
		}
		sprintf((char *)str_buff,"%d.%d",(temp)/10,(temp)%10);
		OLED_ShowString(60,0,str_buff);
//		OLED_ShowString(65,6,str_buff);
//		printf("pitch:%d.%d --- ",temp/10,temp%10); //通过串口1输出pitch	
		
		temp=roll*10;                            //赋temp为roll
		if(temp<0)								//对数据正负判断,判断为负时
		{
			temp=-temp;						    //对负数据取反	
		}
		else                                    //判断为正时
		{
		}
		sprintf((char *)str_buff,"%d.%d",temp/10,temp%10);
		OLED_ShowString(60,4,str_buff);
//		printf("roll:%d.%d --- ",temp/10,temp%10);//通过串口1输出roll
		
		temp=yaw*10;                           //赋temp为yaw
	if(temp<0)								//对数据正负判断,判断为负时
		{
			temp=-temp;						    //对负数据取反
//			OLED_ShowString(100,6,"-");
		}
		else                                    //判断为正时
		{	//OLED_ShowString(100,6,"+");
		}
		sprintf((char *)str_buff,"%d.%d",temp/10,temp%10);
		OLED_ShowString(60,2,str_buff);
//		sprintf((char *)str_buff,"%f",yaw);
//		OLED_ShowString(60,0,str_buff);
//		printf("yaw:%d.%d\r\n",temp/10,temp%10);//通过串口1输出yaw	
//		printf("gyrox:%d,gyroy:%d,gyroz:%d,aacx:%d,aacy:%d,aacz:%d\r\n",gyrox,gyroy,gyroz,aacx,aacy,aacz);//上报角速度数据,角加速度数据
		mpu6050.flag = 0;									//采集成功标志位设置为无效
	}
	else ;														//防卡死
}

五、最后把这两个函数放在while(1)里调用就可以读出数据啦 !

 如果想改SDA 和 SCL 的引脚 ,修改这里

第一次写博客,有些写得不好的地方请大家指正  谢谢大家  0.0

物联沃分享整理
物联沃-IOTWORD物联网 » F1-HAL库快速移植MPU6050

发表评论