前言

为STM32F1/F4移植的Motion Driver 6.12库 俗称DMP库。

官方的库从初始化硬件到获取数据一条龙服务,关键是假如想要用MPU的DMP单元,对于一般人来说那就只能用官方库了,因为官方库包含一个最核心的闭源静态库

工程已经发布在Github:https://github.com/Huffer342-WSH/MPU6050_I2C

蓝奏云:https://wwz.lanzouo.com/iV0SQ004pn8b 密码:1n4j

该项目源自野火的例程,但野火MPU6050的例程对DMP的功能浅尝辄止,视频也讲的比较乱,我对原代码进行了一些删减,去掉了一些没有意义的部分,同时对略微的修改了官方库更方便移植,工程默认状态是在串口输出数据,想要匿名上位机的程序修改预编译指令即可。

除了移植程序外,在README文件中对使用DMP库接口获取数据的方法有详细解说。

结果展示


开发环境

STM32CubeIDE Version: 1.8.0

也可以使用VScode + GNU Arm Embedded Toolchain + OpenOCD
vscode的配置文件都在工程里,修改一下路径就能用,编译调试都有,gcc和openocd我都是MSYS2一键安装的。

使用的是HAL库

Includ path

假如不设置Includ path,那#include “…”都要改成相对路径,否则编译器找不到头文件

   Core/Inc Drivers/STM32F1xx_HAL_Driver/Inc   Drivers/STM32F1xx_HAL_Driver/Inc/Legacy   Drivers/CMSIS/Device/ST/STM32F1xx/Include Drivers/CMSIS/Include   Middlewares/Third_Party/FreeRTOS/Source/include   Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS_V2   Middlewares/Third_Party/FreeRTOS/Source/portable/GCC/ARM_CM3   Middlewares/MPU6050_Motion_Driver/driver/eMPL   Middlewares/MPU6050_Motion_Driver/driver/include   Middlewares/MPU6050_Motion_Driver/eMPL-hal   Middlewares/MPU6050_Motion_Driver/driver/stm32L   Middlewares/MPU6050_Motion_Driver/mllite   Middlewares/MPU6050_Motion_Driver/mpl   Middlewares/MPU6050_Motion_Driver/porting
macro

DEBUG
USE_HAL_DRIVER
STM32F103xE
//下面的是DMP相关的
EMPL
MPL_LOG_NDEBUG=0
MPU6050
USE_DMP
REMOVE_LOGGING
EMPL_TARGET_STM32F1//EMPL_TARGET_STM32F4,唯一的区别是用的头文件不一样
静态库

在工程的Middlewares\MPU6050_Motion_Driver.zip位置有官方的库,内部包含msp430和stm32f4两个例子,官方python上位机,说明文档和各个版本的静态库

STM32属于arm架构,使用\motion_driver_6.12\mpl libraries\arm目录下的文件

MSP430使用\motion_driver_6.12\mpl libraries\msp430目录下的文件

比如我是用 GNU Arm Embedded Toolchain工具链的,芯片是STM32F1系列,属于Cortex-M3架构,那选择的就是

\motion_driver_6.12\mpl libraries\arm\gcc4.9.3\liblibmplmpu_m3.zip

压缩包的库,使用用Keil和IAR同理

静态库放到MPU6050_Motion_Driver\mpl\liblibmplmpu.a
gcc要用库名的时候去掉开头lib和后缀.a
比如此处liblibmplmpu.a填写的是libmplmpu

源位置

*MDK的优化真的太糟心了,虽然代码量少,但总是bug,不如gcc稳定,工程使用stm32cubeide(eclipse)建立的,写代码编译都在vscode,代码补全真的好用,eclipse主要用来调试。

  • 之后中断会改成FreeRTOS的,对读数据的函数进一步封装

下面直接贴github上的readme,就不改了。

Motion Driver 6.12 移植

基于官方库文件略作修改,可以直接用于STM32F1系列,使用gcc编译器 hal库*(Middlewares\MPU6050_Motion_Driver\mpl\liblibmplmpu.a为官方静态库,此处使用的适用于GCC-CM3,假如使用其他编译器替换该静态库并设置链接命令即可)*

STM32F4、MSP430部分未作修改

文章目录

    • 前言
    • 结果展示
      • 开发环境
      • Includ path
      • macro
      • 静态库
      • 源位置
  • Motion Driver 6.12 移植
    • 目录
    • 修改
    • 移植
      • inv_mpu_dmp_motion_driver.c
      • inv_mpu.c
    • 引脚
    • 编译
    • 使用
    • 其他

目录

├── driver├── eMPL├── inv_mpu.c├── inv_mpu_dmp_motion_driver.c├── ...├── include...├── stm32L...
├── eMPL-hal...
├── mllite...
├── porting├── STM32F1_porting.c├── STM32F1_porting.h├──mpu6050_SL.c└──mpu6050_SL.h
├── README.md

porting文件夹存放移植需要的函数,其余四个文件夹均为Motion Driver 6.12原有的文件夹

其中STM32F1_porting.c为移植必须的内容,

​ mpu6050_SL.c是我自己使用时封装的一部分函数,可有可无。

修改

  • 基于原官方STM32F4部分略作修改,使之适用于STM32F1,编译器符号也应当从EMPL_TARGET_STM32F4改为EMPL_TARGET_STM32F1
  • /driver/eMPL/inv_mpu_dmp_motion_driver.c:627
#ifdef EMPL_TARGET_STM32F1__NOP();
#else__no_operation();
#endif// __no_operation();

__no_operation();是MSP的函数

  • 原文件中eMPL_outputs和hal_outputs在注册用于处理数据的回调函数时采用了相同的优先级,导致两个函数不能同时注册,导致eMPL_outputs.c和hal_outputs.c中的函数不能同时使用。所以修改了eMPL_outputs的优先级#define INV_PRIORITY_EMPL_OUTPUTS 899,经测试不影响结果,假如使用发现问题了,那就改回来吧。

    #define INV_PRIORITY_MOTION_NO_MOTION          100
    #define INV_PRIORITY_GYRO_TC                   150
    #define INV_PRIORITY_QUATERNION_GYRO_ACCEL     200
    #define INV_PRIORITY_QUATERNION_NO_GYRO        250
    #define INV_PRIORITY_MAGNETIC_DISTURBANCE      300
    #define INV_PRIORITY_HEADING_FROM_GYRO         350
    #define INV_PRIORITY_COMPASS_BIAS_W_GYRO       375
    #define INV_PRIORITY_COMPASS_VECTOR_CAL        400
    #define INV_PRIORITY_COMPASS_ADV_BIAS          500
    #define INV_PRIORITY_9_AXIS_FUSION             600
    #define INV_PRIORITY_QUATERNION_ADJUST_9_AXIS  700
    #define INV_PRIORITY_QUATERNION_ACCURACY       750
    #define INV_PRIORITY_RESULTS_HOLDER            800
    #define INV_PRIORITY_INUSE_AUTO_CALIBRATION    850
    #define INV_PRIORITY_EMPL_OUTPUTS              899
    #define INV_PRIORITY_HAL_OUTPUTS               900//原文件中均使用此优先级
    #define INV_PRIORITY_GLYPH                     950
    #define INV_PRIORITY_SHAKE                     975
    #define INV_PRIORITY_SM                        1000inv_register_data_cb(inv_generate_hal_outputs, INV_PRIORITY_HAL_OUTPUTS, INV_GYRO_NEW | INV_ACCEL_NEW | INV_MAG_NEW);
    inv_register_data_cb(inv_generate_eMPL_outputs, INV_PRIORITY_EMPL_OUTPUTS,INV_GYRO_NEW | INV_ACCEL_NEW | INV_MAG_NEW);
    

移植

inv_mpu.cinv_mpu_dmp_motion_driver.c中有宏定义以供移植,原代码注释如下

inv_mpu_dmp_motion_driver.c

/* The following functions must be defined for this platform:

** i2c_write(unsigned char slave_addr, unsigned char reg_addr,*

** unsigned char length, unsigned char const *data)*

** i2c_read(unsigned char slave_addr, unsigned char reg_addr,*

** unsigned char length, unsigned char *data)*

** delay_ms(unsigned long num_ms)*

** get_ms(unsigned long *count)*

*/

inv_mpu.c

/* The following functions must be defined for this platform:

** i2c_write(unsigned char slave_addr, unsigned char reg_addr,*

** unsigned char length, unsigned char const *data)*

** i2c_read(unsigned char slave_addr, unsigned char reg_addr,*

** unsigned char length, unsigned char *data)*

** delay_ms(unsigned long num_ms)*

** get_ms(unsigned long *count)*

** reg_int_cb(void (*cb)(void), unsigned char port, unsigned char pin)*

** labs(long x)*

** fabsf(float x)*

** min(int a, int b)*

*/

实际上需要提供的只有

  • i2c_write(unsigned char slave_addr, unsigned char reg_addr,unsigned char length, unsigned char const *data)

  • i2c_read(unsigned char slave_addr, unsigned char reg_addr,unsigned char length, unsigned char *data)

  • delay_ms(unsigned long num_ms)

  • get_ms(unsigned long *count)

    该部分具体代码如下

    #define i2c_write Sensors_I2C_WriteRegister#define i2c_read Sensors_I2C_ReadRegister#define delay_ms HAL_Delay#define get_ms get_ms_user
    

    具体实现在porting文件夹中

引脚

包含一个外部上升沿中断引脚和I2C的SDA、SCL引脚,共三个引脚

想要高频率的获取数据就用中断,不需要使用时关闭中断,等要数据时打开中断,高频率获取数据再滤波。

编译

编译器设置符号:

EMPL_TARGET_STM32F1

EMPL

MPL_LOG_NDEBUG = 0/1 没有用官方python上位机的话设置为0

MPU6050你使用的型号

USE_DMP

REMOVE_LOGGING

使用

请先完成移植

步骤为:

  • 硬件初始化(MPU初始化)
  • MPL初始化(MPL 库是 InvenSense Motion Apps 专有算法的核⼼,由 Mllite 和 mpl ⽬录组成。)
  • 设置MPL与DMP
  • 调用函数获取数据

注意:DMP传感器融合仅适用于+ -2000dps和Accel + -2G的陀螺仪(官方文档:DMP sensor fusion works only with gyro at ±2000dps and accel ±2G),大部分情况下我们都需要使用DMP(要不然也不用官方库了),所以设置并没有太多选择,照抄就完事了。除非你需要很大的量程,否则没有必要关闭DMP。

前三步基本都是按照官方给的例子,封装成三个函数:

uint8_t MPU6050_mpu_init(void);
uint8_t MPU6050_mpl_init(void);
uint8_t MPU6050_config(void);
在mpu6050_SL.c中

重点是使用库中给出的函数,获取数据

官方的库中有三个.c文件提供了获取数据的接口,分别是mllite/results_holder.cmllite/hal_outputs.ceMPL-hal/eMPL_outputs.c。这三个文件获取都通过data_builder.c中的函数获取数据,所以也可以从data_builder.c中的函数获取原始数据自己处理~~(有现成的为什么要自己做呢)~~

官方库处理数据的思路是将处理数据的函数以回调函数的方式存储起来,并在inv_error_t inv_execute_on_data(void)中统一调用,调用的顺序由注册时传入的优先级决定(本质就是拿一个数组把函数指针存起来,然后都调用一遍)。 官方库的步骤是先注册启动函数,在调用启动函数来注册数据处理函数,再统一调用。

例子如下(展示一下官方库处理数据的步骤,看一眼就行,不涉及使用):

inv_error_t inv_enable_hal_outputs(void)
{inv_error_t result;inv_init_hal_outputs();result = inv_register_mpl_start_notification(inv_start_hal_outputs);//注册启动函数,return result;
}inv_error_t inv_register_mpl_start_notification(inv_error_t (*start_cb)(void))
{if (inv_start_cb.num_cb >= INV_MAX_START_CB)return INV_ERROR_INVALID_PARAMETER;inv_start_cb.start_cb[inv_start_cb.num_cb] = start_cb;//将函数指针存起来inv_start_cb.num_cb++;return INV_SUCCESS;
}inv_error_t inv_start_mpl(void)
{INV_ERROR_CHECK(inv_execute_mpl_start_notification());//执行启动函数return INV_SUCCESS;
}inv_error_t inv_start_hal_outputs(void)
{inv_error_t result;result =inv_register_data_cb(inv_generate_hal_outputs, INV_PRIORITY_HAL_OUTPUTS,INV_GYRO_NEW | INV_ACCEL_NEW | INV_MAG_NEW);//注册数据处理函数,同样将函数指针存起来,此处INV_PRIORITY_HAL_OUTPUTS是优先级,数组中函数指针按优先级排序return result;
}inv_error_t inv_execute_on_data(void)
{inv_error_t result, first_error;int kk;int mode;#ifdef INV_PLAYBACK_DBGif (inv_data_builder.debug_mode == RD_RECORD){int type = PLAYBACK_DBG_TYPE_EXECUTE;fwrite(&type, sizeof(type), 1, inv_data_builder.file);}
#endif// Determine what new data we havemode = 0;if (sensors.gyro.status & INV_NEW_DATA)mode |= INV_GYRO_NEW;if (sensors.accel.status & INV_NEW_DATA)mode |= INV_ACCEL_NEW;if (sensors.compass.status & INV_NEW_DATA)mode |= INV_MAG_NEW;if (sensors.temp.status & INV_NEW_DATA)mode |= INV_TEMP_NEW;if (sensors.quat.status & INV_NEW_DATA)mode |= INV_QUAT_NEW;first_error = INV_SUCCESS;for (kk = 0; kk < inv_data_builder.num_cb; ++kk){if (mode & inv_data_builder.process[kk].data_required){result = inv_data_builder.process[kk].func(&sensors);//使用存起来的数据处理函数if (result && !first_error){first_error = result;}}}inv_set_contiguous();return first_error;
}

再上文提到过优先级冲突的事情,官方的相关部分代码如下:

 for (kk = 0; kk < inv_data_builder.num_cb; ++kk){if ((inv_data_builder.process[kk].func == func) || (inv_data_builder.process[kk].priority == priority)){return INV_ERROR_INVALID_PARAMETER; // fixme give a warning}}

可以看到它不允许相同函数或相同优先级的函数多次注册,所以就有了上文改优先级的事情。

那么接下来是具体使用方法

  1. inv_error_t inv_init_mpl(void);初始化mpl

  2. 首先调用文件中的enable函数,完成启动函数的注册

    1. inv_error_t inv_enable_results_holder(void);
    2. inv_error_t inv_enable_hal_outputs(void);
    3. inv_error_t inv_enable_eMPL_outputs(void);
  3. 然后调用inv_error_t inv_start_mpl(void);调用启动函数来注册数据处理函数

  4. 获取原始数据int dmp_read_fifo(short *gyro, short *accel, long *quat, unsigned long *timestamp, short *sensors, unsigned char *more)

  5. 然后inv_build后调用inv_error_t inv_execute_on_data(void);处理数据(可以在接收到MPU的INT引脚发送过来的上升沿处理完成中断后使用)

    inv_error_t inv_build_gyro(const short *gyro, inv_time_t timestamp);
    inv_error_t inv_build_compass(const long *compass, int status, inv_time_t timestamp);
    inv_error_t inv_build_accel(const long *accel, int status, inv_time_t timestamp);
    inv_error_t inv_build_temp(const long temp, inv_time_t timestamp);
    inv_error_t inv_build_quat(const long *quat, int status, inv_time_t timestamp);
    inv_error_t inv_execute_on_data(void);//先调上面5个至少成功一个,再调用此函数
    
  6. 接下来就可以随意调用获取数据的函数了

    results_holder.c中的函数可以获取原始的角速度,加速度等数据(没什么用,)

    hal_outputs.c可以获取矫正的方位角(与航空中使用的偏航,俯仰和横滚不同)、四元数 以及加速度角速度什么的,并且都是可以直接使用的浮点数 都可以直接代公式。

    eMPL_outputs.c中的函数可以获取欧拉角以及…,不过欧拉角获取的是32位的q16.16定点数,整形消耗计算资源少,可以自己写定点数的计算函数,当然也可以转化为32位的单精度浮点数
    float=q16∗1.0/(1<<16);float=q16* 1.0 / (1 << 16); float=q161.0/(1<<16);
    具体是干什么的,返回什么数据官方库都在.c 里有英文注释,还是比较易懂的。

上文还提了一嘴data_builder.c,这文件的内容就是set、build、get,get的都是原始数据,和dmp_read_fifo读出来的寄存器数据没什么差别,重点是set和build。既然用了官方的那自然是要用DMP,所以就不解释这个文件了。

其他

听说STM32F1的硬件I2C有bug,但我目前没有遇到,此处都是基于HAL库的硬件I2C实现。

小技巧,看一大堆文件不知道干什么,可以debug看看调用顺序(只能打8个断点可太累了)

STM32移植MPU6050/9250的DMP官方库(motion_driver_6.12)修改移植 DMP简单使用教程相关推荐

  1. STM32平台下官方DMP库6.12超详细移植教程

    前记 Motion Driver官方库:Motion_Driver_6.12 STM32工程源码:STM32F103C8-软件MPU6050(DMP) MPU6050软件I2C驱动,带OLED显示,移 ...

  2. STM32F103HAL库移植MPU6050的DMP库

    前言 众所周知啊,MPU6050是一个在硬件上使用非常广泛的IC,在我们的使用中,MPU6050是一个不可缺少的东西,特别是四轴. 我们一般都是用软件模拟IIC与MPU6050进行通信,但是读到的是它 ...

  3. IAR 下根据官方库建立 STM32的工程

    目录 1. IARforSTM32工程v0.0版本.... 1 2. IARforSTM32工程v0.1版本.... 6 2.1今天v0.0版本出现了警告.... 6 2.2下载仿真.... 7 2. ...

  4. 在STM32的官方库切换芯片型号

    对象:在STM32F10X的3.5官方库的进行芯片的切换 例子:f103切换成f107 资源吸取自:野火的<[野火®]零死角玩转STM32-F103霸道>.网上大神 所需材料:STM32F ...

  5. 基于STM32标准库的MS5837程序移植

    基于STM32标准库的MS5837程序移植 一.准备工作 1. 硬件电路 2. 新建工程 二.开始移植 1. IIC底层模拟 2. MS5837移植 3. 主函数编写 4. 代码调试结果 三.源代码下 ...

  6. STM32学习——MPU6050姿态传感器

    STM32移植(抄)起来特别爽... MPU6050简介 1.MPU6050是一款六轴(三轴加速度+三轴角速度(陀螺仪))传感器 2.MPU6050含有一个第二IIC接口,可用于连接外部磁力传感器 3 ...

  7. STM32驱动MPU6050(二)——软件实现

    前言: 为了方便查看博客,特意申请了一个公众号,附上二维码,有兴趣的朋友可以关注,和我一起讨论学习,一起享受技术,一起成长. 软件实现将从下面三个部分来介绍:IIC通信:MPU6050数据读取:数据融 ...

  8. 基于STM32的MPU6050

    热泪盈眶 最近的考核任务是基于STM32的MPU6050 我移植的是正点的模板 1.第一个出现的问题 #define SDA_IN()  {GPIOB->MODER&=~(3<&l ...

  9. MPU6050工作原理及STM32控制MPU6050

    一·简介: 1.要想知道MPU6050工作原理,得先了解下面俩个传感器: ①陀螺仪传感器: 陀螺仪的原理就是,一个旋转物体的旋转轴所指的方向在不受外力影响时,是不会改变的.人们根据这个道理,用它来保持 ...

  10. LPC1768用官方库中用寄存器开启两个硬件PWM

    第一次使用LPC芯片.在NXP官网上面下载了官方库函数如下图 但是在使用过程中发现该库很多东西都不齐全,比如说硬件pwm,是的,连这个都没有,然后当我想要移植在网上下载的寄存器硬件PWM列子进去的时候 ...

最新文章

  1. 多语言互通:谷歌发布实体检索模型,涵盖超过100种语言和2000万个实体
  2. 如何用AI实现视频防抖?还是无需裁剪画面的那种 | 谷歌台湾大学
  3. C++ :: 的用法小结
  4. vue在微信里面的兼容问题_vuejs在安卓系统下微信X5内核这个兼容性问题如何破?...
  5. wdns服务器未响应,Win7系统​网络诊断提示DNS服务器未响应的解决方法
  6. [Redis6]常用数据类型_List列表
  7. 贝叶斯统计 传统统计_统计贝叶斯如何补充常客
  8. mvc mysql linq_MVC3+Linq to sql 显示数据库中数据表的数据
  9. Webpack 5 配置手册(从0开始)
  10. 7个设计模式的基本原则
  11. loj #6013. 「网络流 24 题」负载平衡
  12. mac虚拟机桌面图标隐藏_教你隐藏 Mac 的桌面文件
  13. DaZeng:雪碧图(精灵图)的使用
  14. QNX Hypervisor —— 体系结构
  15. 【java1234】java学习路线图2018
  16. 电子厂计算机常用英语,电子厂常用英语词汇
  17. 教室外的风景(宁波市第25届小学组)
  18. com.alibaba.fastjson.JSONException: default constructor not found. class com.srbl.mytx.domain.Locati
  19. 统计学习方法笔记_cbr:统计学习及监督学习概论
  20. 学完计算机网络基础及应用的感想,学习《计算机网络基础知识》心得体会

热门文章

  1. c语言公路曲线要素,一、圆曲线要素及计算公式
  2. 输出实数的格式,包括:⑴一行输出一个实数;⑵一行内输出两个实数;⑶一行内输出三个实数。实数用“6.2f“格式输出2020.11.12
  3. 参数显著性检验的p值小于显著性水平不等于其具有经济学意义
  4. Angular内置指令
  5. 智能科学与技术——介绍概要
  6. 计算机win7卡顿如何解决方法,win7卡顿严重解决方法_win7运行卡顿严重最流畅设置方法-win7之家...
  7. 机器学习和人工智能之间的区别
  8. logging日志带颜色
  9. python可视化(2-1)绘图对象(条形图、直方图、柏拉图)
  10. IT大学生应该经常浏览的十大网站