MPU6050的dmp代码移植的过程--转

让自己别忘了大学里学的东西,那么就把它记录下下来,效率会比忘记然后重新再去找资料再重头学高的多


一开始自己死命的去网上找现成的代码,但是发现大多都是打着dmp的幌子,给的是得出原始数据的代码,或者确实是dmp的代码,但是太复杂,自己看不懂,所以果断放弃,直接去网上找dmp移植的教程,结果文字教材也是差不多的效果,不过忽然在百度上发现了一个视频教材,”与非网”上的”小马哥STM32课程系列直播-如何两个月做出自己的暴力空心杯小四轴”里面有几讲是关于mpu6050的教程的,所以就点进去看了,他的内容还挺方便的 直接教你怎么去移植修改dmp的官方代码到stm32的文件中,但是并不是很详细的讲解官方给的代码的具体含义,对我这种不给我一个字一个字翻译很难理解的人来说是相当痛苦,然后还有一些不足的就是那个视频的进度条拖动很困难,不能精确回看定位到某个点,而且视频声音有点小,还有就是看视频的时候要全程投入,一旦错过某个修改的细节,你的代码就凉凉了,而且你不是很懂代码的含义,就不知道怎么修改,然后又得重看长达5,6个小时的视频,简直痛苦,当时我看了整整两遍,然而仍然不知道代码错在哪里,所以果断放弃,不过好的是,视频给了我一个贼清晰的框架和流程,那么我接下来只要慢慢的一点去研究代码内容就ok了。

》》》》”小马哥STM32课程系列直播-如何两个月做出自己的暴力空心杯小四轴”-链接:
http://www.moore8.com/courses/1406

记录一下MPU6050的dmp代码移植的过程

  1. 准备四个东西
    1. mpu6050硬件
    2. mpu6050寄存器手册,
    3. stm32f10x单片机
    4. dmp固件库(我的是5.1版的)
      PS:固件库只需要提取下面7个文件即可,其他文件没啥用

“inv_mpu_dmp_motion_driver.h”
“inv_mpu_dmp_motion_driver.c”
“inv_mpu.h”
“inv_mpu.c”
“dmpmap.h”
“dmpKey.h”(前6个在同一个目录下) 和“motion_driver_test.c“

把前6个文件通过keil导入文件的方式,导入的keil中。第7个文件不是代码文件,而是适用于msp430的main函数文件,我们把第七个文件当作参照,来自己写一份关于stm32的main文件即可.c的路径
放入工程中

  1. 观察它文件内容的结构
    1. 整体文件分析
      1. 在”inv_mpu.c” “inv_mpu_dmp_motion_driver.c”这两个文件里面全是大片大片的英文,但是仔细看,你会发现,这么多的英文,其实结构很清晰,都是单个的模块的函数内容定义的集合以及一些条件预定义而已,并不是什么杂乱无章的东西,。打开“motion_driver_test.c“,你也会发现也是大量的函数定义以及条件预定义和一个main函数,而这个main函数是针对MSP430的一个代码,刚好是用于读取实时的欧拉角代码,首先我们对main函数进行分析,我们知道一个main函数一般分为两部分,各个内外设的初始化,和while循环内的无限操作函数,对于我们的要求也是也一样,我们无非也就是需要两个代码,mpu6050的初始化,以及无限的读出欧拉角,刚好和main函数对应上了,所以开始分析代码,因为main上自带英文注释,咱先把它通过谷歌翻译在”inv_mpu.c” “inv_mpu_dmp_motion_driver.c”这两个文件里面全是大片大片的英文,但是仔细看,你会发现,这么多的英文,其实结构很清晰,都是单个的模块的函数内容定义的集合以及一些条件预定义而已,并不是什么杂乱无章的东西,。打开“motion_driver_test.c“,你也会发现也是大量的函数定义以及条件预定义和一个main函数,而这个main函数是针对MSP430的一个代码,刚好是用于读取实时的欧拉角代码,首先我们对main函数进行分析,我们知道一个main函数一般分为两部分,各个内外设的初始化,和while循环内的无限操作函数,对于我们的要求也是也一样,我们无非也就是需要两个代码,mpu6050的初始化,以及无限的读出欧拉角,刚好和main函数对应上了,所以开始分析代码,因为main上自带英文注释,咱先把它通过谷歌翻译
    2. main文件分析
      1. 初始化:{
        1. 初始化MSP430芯片
        2. 初始化mpu6050
        3. 检测返回值,如果返回值>0,重启MSP430
        4. 开启陀螺仪和加速计
        5. 加载mpu6050内部的陀螺仪和加速计的FIFO-根据内部参数配置
        6. 设置mpu6050内部采样率
        7. 返回刚刚配置的内部的一系列的值
        8. 数组置数函数-c语言特有,将hal数组内的所有值都置为0
        9. Hal.sesors=ACCEL_ON | GYRO_ON,标志-加速计和陀螺仪都开了
        10. 上报四元数
        11. 加载DMP功能
        12. 将陀螺仪和加速度方向矩阵推入DMP
        13. 手势回调函数-和我们的意图无关手势回调函数-和我们的意图无关
        14. 安卓回调函数-和我们的意图无关
        15. 选择dmp要加载的功能-和这些传入参数的值有关
        16. 加载已选功能
        17. 设置FIFO缓存的速率
        18. 开启DMP
        19. hal.dmp_on = 1 标志-DMP开启
        20. 开启MPS430的中断
        }
      2. While(1){
        1. USB相关函数-和上位机有关,和我们的意图无关-
        2. 获得时间戳=当时的时间,和我们的意图无关-
        3. 运动中断函数,和我们的意图无关-
        4. 控制MSP430芯片休眠函数,和我们的意图无关-
        5. 查询DMP开了没和是否有数据更新了(两个都要满足)-
          1. 向DMP的fifo读取并且计算四元数
          2. 再检测FIFO内是否还存在有剩余的数据-如果没有,数据更新标志位清零
          3. 返回四元数
            }
  2. 翻译”inv_mpu.c”和“motion_driver_test.c“的函数大概内容
    1. “inv_mpu.c”
  1. static int set_int_enable(unsigned char enable) 模块中断使能函数
  2. int mpu_reg_dump(void) 测试打印函数
  3. int mpu_read_reg(unsigned char reg, unsigned char *data) 3.向芯片读寄存器值,除了MEMERY和FIFO
  4. int mpu_init(void) MPU6050的初始化
  5. int mpu_lp_accel_mode(unsigned char rate) 进入低功耗模式
  6. int mpu_get_gyro_reg(short *data, unsigned long *timestamp) 获取新的原始陀螺仪数据
  7. int mpu_get_accel_reg(short *data, unsigned long *timestamp获取新的原始加速度数据
  8. int mpu_get_temperature(long *data, unsigned long *timestamp) 获取新的温度数据
  9. int mpu_set_accel_bias(const long *accel_bias) 偏差配置函数
  10. int mpu_reset_fifo(void) 重置FIFO函数
  11. int mpu_get_gyro_fsr(unsigned short *fsr) 获得陀螺仪全尺寸范围函数
  12. int mpu_set_gyro_fsr(unsigned short fsr) 设置陀螺仪全尺寸范围函数
  13. int mpu_get_accel_fsr(unsigned char *fsr) 获得加速度全尺寸范围函数
  14. int mpu_set_accel_fsr(unsigned char fsr) 配置加速度全尺寸范围函数
  15. int mpu_get_lpf(unsigned short *lpf) .获得DLPF范围函数
  16. int mpu_set_lpf(unsigned short lpf) 配置DLPF范围函数
  17. int mpu_get_sample_rate(unsigned short *rate) 获得采样频率范围函数
  18. int mpu_set_sample_rate(unsigned short rate) 配置采样频率范围函数
  19. int mpu_get_compass_sample_rate(unsigned short *rate) 获得罗盘采样频率范围函数
  20. int mpu_set_compass_sample_rate(unsigned short rate) 配置罗盘采样频率范围函数
  21. int mpu_get_gyro_sens(float *sens) 获得陀螺仪灵敏度比例因子函数
  22. int mpu_get_accel_sens(unsigned short *sens) 获得加速计灵敏度比例因子函数
  23. int mpu_get_fifo_config(unsigned char *sensors) 获得开启的FIFO通道函数
  24. int mpu_configure_fifo(unsigned char sensors) 配置开启FIFO通道函数
  25. int mpu_get_power_state(unsigned char *power_on) 获得芯片工作状态
  26. int mpu_set_sensors(unsigned char sensors) 配置传感器的时钟和工作状态函数
  27. int mpu_get_int_status(short *status).获得中断状态函数
  28. int mpu_read_fifo(short *gyro, short *accel, unsigned long *timestamp,unsigned char *sensors, unsigned char *more) 获得FIFO数据函数
  29. int mpu_read_fifo_stream(unsigned short length, unsigned char *data,unsigned char *more) 获得FIFO数据长度函数
  30. int mpu_set_bypass(unsigned char bypass_on) 设置旁路模式函数
  31. int mpu_set_int_level(unsigned char active_low) 设置中断优先级函数
  32. int mpu_set_int_latched(unsigned char enable) 设置中断锁存函数-
  33. 设置自检函数
  34. static int get_st_biases(long *gyro, long *accel, unsigned char hw_test) 获取所有的偏差值函数
  35. int mpu_run_self_test(long *gyro, long *accel) 行自检值函数
  36. int mpu_write_mem(unsigned short mem_addr, unsigned short length,unsigned char *data) 向DMP写记忆函数
  37. int mpu_read_mem(unsigned short mem_addr, unsigned short length,unsigned char *data) 向DMP读记忆函数
  38. int mpu_load_firmware(unsigned short length, const unsigned char *firmware,unsigned short start_addr, unsigned short sample_rate) 加载并验证DMP映像函数
  39. int mpu_set_dmp_state(unsigned char enable) DMP状态控制函数
  40. int mpu_get_dmp_state(unsigned char *enabled) DMP状态读取函数
  1. “motion_driver_test.c“

1.*
2. static __inline unsigned short inv_row_2_scale(const signed char row) 矩阵转换方向标量函数
3. static void setup_gyro(void) 陀螺仪配置函数
4.

5.*
6. void STM32F103_Reset(void) 外部控制芯片复位函数,我们是stm32,所以重写
7. static __inline void run_self_test(void) 自检函数,用于坐标原点标定
8.*
9. static void gyro_data_ready_cb(void) 数据获得后的状态回调函数

  1. ”inv_mpu.c”和“inv_mpu_dmp_motion_driver.c“的文件格式的修改第一页

第二页
第三页第四页第五页第六页

  1. 根据“motion_driver_test.c“创建兼容STM32F10X的代码
    1. DMP初始化函数:
u8 DMP_Init(void)
 {
		int result;
		unsigned char accel_fsr;
		unsigned short gyro_rate, gyro_fsr;
		unsigned long timestamp;
	 result = mpu_init();                                   //1.6050初始化,成功=0,失败=1
 	 
	 if (result)                         
		 {		
			 STM32F103_Reset();                                 //2.如果失败,重新复位stm32
			 
			 return 8;
		 }
 
		if(mpu_set_sensors(INV_XYZ_GYRO | INV_XYZ_ACCEL))     //3.配置陀螺仪和加速计传感器的时钟和工作状态函数
			{return 1;}
			
		if(mpu_configure_fifo(INV_XYZ_GYRO | INV_XYZ_ACCEL))  //4.配置陀螺仪和加速计开启FIFO通道函数
			{return 2;}

		if(mpu_set_sample_rate(DEFAULT_MPU_HZ))               //5.配置默认的采样率
			{return 3;}
			
		mpu_get_sample_rate(&gyro_rate);                      //6.获得陀螺仪采样频率范围函数
	   
		mpu_get_gyro_fsr(&gyro_fsr);                          //7.获得陀螺仪全尺寸范围函数
	
		mpu_get_accel_fsr(&accel_fsr);                        //8.获得加速计全尺寸范围函数
	 
		memset(&hal, 0, sizeof(hal));                         //9.数组填数函数
		 
		hal.sensors = ACCEL_ON | GYRO_ON;                     //10.标志位-"开启传感器"设置为加速计和陀螺仪

		if(dmp_load_motion_driver_firmware())                 //11.加载并验证DMP映像函数
		  {return 4;}   
			
  if(dmp_set_orientation(inv_orientation_matrix_to_scalar(gyro_orientation)))    //12.推送陀螺仪和<a href="https://www.baidu.com/s?wd=%E5%8A%A0%E9%80%9F%E5%BA%A6%E8%AE%A1&amp;tn=24004469_oem_dg&amp;rsv_dl=gh_pl_sl_csd" target="_blank">加速度计</a>的方向矩阵到DMP
			{return 5;}
		 
  hal.dmp_features = DMP_FEATURE_6X_LP_QUAT | DMP_FEATURE_TAP |
  DMP_FEATURE_ANDROID_ORIENT | DMP_FEATURE_SEND_RAW_ACCEL | DMP_FEATURE_SEND_CAL_GYRO |
  DMP_FEATURE_GYRO_CAL;                                                           //13.DMP的功能选项标志位设置,用来告诉DMP要开启的功能

  if(dmp_enable_feature(hal.dmp_features))              //14.使能上述功能
			{return 6;}

  if(dmp_set_fifo_rate(DEFAULT_MPU_HZ))                 //15.配置DMP的FIFO速率
			{return 7;}
			
  mpu_set_dmp_state(1);                              		//16.开启DMP
		
  hal.dmp_on = 1;                                    		//17.标志位-"DMP状态"为开启
			
	  run_self_test();                                      //18.DMP的自检,就是标定现在的状态为坐标原点
				
		return 0;	 

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64

DMP初始化

  1. DMP_欧拉角读取
	short gyro[3], accel[3], sensors;
	unsigned char more;
	long quat[4];
	float q0=1.0f,q1=0.0f,q2=0.0f,q3=0.0f;
	float pitch,roll,yaw;
	 u8 DMP_DATA_UPDATA(void)
	{	 
		unsigned long sensor_timestamp;
	gyro_data_ready_cb();                   //数据采集结束标志位
				
	if (hal.new_gyro &amp;&amp; hal.dmp_on)         //用于计算四元数函数
		{
			if(dmp_read_fifo(gyro, accel, quat, &amp;sensor_timestamp, &amp;sensors,&amp;more))
				{return 1;}	
				
			if (!more)
					hal.new_gyro = 0;
					if(sensors &amp; INV_WXYZ_QUAT)
						{
								q0=quat[0]/q30;
								q1=quat[1]/q30;
								q2=quat[2]/q30;
								q3=quat[3]/q30;
								pitch=asin((-2)*q1*q3+2*q0*q2)*57.3;
								roll=atan2(2*q2*q3+2*q0*q1,(-2)*q1*q1-2*q2*q2+1)*57.3;
								yaw=atan2(2*(q1*q2+q0*q3),q0*q0+q1*q1-q2*q2-q3*q3)*57.3;
						}
		}
					
		return 0;

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33

欧拉角读取

  1. 注意事项
    1. 模拟i2c的内容:
      附件内有模拟I2C的代码,因为i2c内的延迟函数是通过while(time–)实现的,所以延迟长度可以通过time的值控制,为什么要考虑这个呢,因为在测试的时候发现单片机会 在“u8 DMP_Init(void) “函数中的 if(dmp_load_motion_driver_firmware()) /11.加载并验证DMP映像函数等待要很久,而这个函数的本质就是不断的通过I2C向6050收发数据,而我当时的I2C代码因为怕时钟线跳变时有延迟,所以给他每次跳变都加了很大的延迟,所以导致对于这个6050的这个函数也会延迟恒久,但是当我把软件延迟的变量变小,发现一下这个函数就通过了

    2. 关于mpu6050返回四元数的途径:
      我们知道获取外部的数据有两种方式,一种是单片机一直通过询问标志位的方式去获得外部数据,另外一种是外部给单片机引脚一个电平跳变方式,来告诉单片机读取数据,也就是外部中断,而且第二中种效率高,但是对于6050,如果设置的dmp,他的默认中断触发是50us的高电平(应该是的),us对于单片机来说可能会出bug,所以选择巡查的方式来读出数据,所以在测试中,我用的是滴答定时器在固定的时间间隔来读取数据,因为6050产出的数据速度远远大于每次单片机去读取的时间,所以不用担心会读出空数据,但是,会有一个问题,就是如果单片机的读取时间过慢,比如说1s读一次,那么就会死机,这个好像是因为fifo的会阻塞问题把。具体的不清楚,

    3. 编译结束时,warning和error都要关注:
      有时候warning也会让程序出bug

    4. Keil特有的格式:

      1. c99的结构体无法识别,要把它该成GUI的结构体
      2. static _inline 关键字无法识别 要改成static __inline
    5. mpu6050的功能报错:
      因为它没有 accel_cfg2,lp_accel_odr,accel_intel 这三个功能,所以在inv_mpu.c内的struct gyro_reg_s 中把它注释掉

第一次调mpu6050,应该会有很多bug,见谅

        </div>
					<link href="https://csdnimg.cn/release/phoenix/mdeditor/markdown_views-7b4cdcb592.css" rel="stylesheet">
            </div>
  • 54
    点赞
  • 201
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
移植 MPU6050 DMP 到 STM32F103 上需要进行以下步骤: 1. 准备工作 首先需要准备好 MPU6050 模块,以及 STM32F103 开发板,并连接好它们。另外,还需要下载 MPU6050 DMP 库文件和 STM32F103 的开发环境,例如 Keil 或者 CubeMX。 2. 配置 I2C MPU6050 是通过 I2C 协议与 STM32F103 通信的,因此需要配置好 I2C。在 CubeMX 中选择 I2C 外设并进行配置,设置好 I2C 的时钟和引脚等参数。在 Keil 中,需要编写 I2C 相关的初始化代码。 3. 配置 MPU6050MPU6050 DMP 库中,有一份 MPU6050 库文件,其中包含了 MPU6050 初始化相关的代码。需要将该文件添加到工程中,并按照需要进行修改。主要需要配置 MPU6050 的采样率、陀螺仪量程、加速度计量程等参数。 4. 导入 DMP 库 将 MPU6050 DMP 库文件加入到工程中,并在代码中进行调用。需要注意的是,DMP 库文件需要与 MPU6050 库文件进行配合使用。 5. 填充缓冲区 在 DMP 库文件中,有一个叫做“dmp_read_fifo”的函数,该函数用于读取 MPU6050 的原始数据,并调用 DMP 算法进行处理。在该函数内部,需要填充缓冲区,将处理后的数据存储到缓冲区中。 6. 解析数据 解析数据是将缓冲区中的数据进行解析,得到姿态角度等信息。在 DMP 库文件中,有一个叫做“dmp_get_data”的函数,该函数用于解析数据。需要注意的是,解析数据的过程需要根据具体情况进行调整,例如需要考虑坐标系的换等问题。 7. 输出结果 最后,将得到的姿态角度等信息进行输出。可以通过串口或者 OLED 屏幕等方式进行显示。 总的来说,移植 MPU6050 DMP 到 STM32F103 上需要进行一系列的配置和调试工作,需要有一定的硬件和软件基础。
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值