你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

基于STM32的驱动MPU6050输出欧拉角经验分享

[复制链接]
攻城狮Melo 发布时间:2023-3-18 12:25
一.MPU6050介绍
* |" U8 u9 A+ E! L1.MPU6050与陀螺仪、加速度计的关系:

: n: J& \0 v1 [4 @MPU6050是InvenSense公司推出的一款全球首款的整合性9轴运动处理传感器,其最大的特色就是:消除了陀螺仪和加速度计的误差,将陀螺仪和加速度计组合在一起,而且缩小了空间。
7 o: F7 U7 X/ S+ g" o1 E# H
( u3 M( u! c) N6 n6 u2 o0 w, f
2.整体概括
! o8 b7 W3 u. w' ~$ o: C3 u$ e
MPU6050内部整合了三轴MEMS陀螺仪、三轴MEMS加速度计以及一个可扩展的数字运动处理器DMP,而且还可以连接一个第三方数字传感器(比如:磁力计),这样的话,就可以通过IIC接口输出一个9轴信号。
$ d* f8 W2 T. j1 g* P! n更加方便的是,有了DMP,可以结合InvenSense公司提供的运动处理资料库,实现姿态解算。通过自带的DMP,可以通过IIC接口输出9轴融合演算的数据,大大降低了运动处理运算对操作系统的负荷,同时也降低了开发难度。
, r$ @  n, R  j, ?/ I+ _9 M& Z  I' Z; i
; J7 d5 X, v# \4 f8 k; E特点:
1 @! r3 {/ V, c" O① 以数字形式输出 6 轴或 9 轴(需外接磁传感器)的旋转矩阵、四元数(quaternion)、欧
! T4 C& E$ |) `2 x& y! M拉角格式(Euler Angle forma)的融合演算数据(需 DMP 支持)3 q% c# t. n  z4 ?4 L, j0 p
② 具有 131 LSBs/° /sec 敏感度与全格感测范围为±250、±500、±1000 与±2000° /sec# A5 C2 q- R* T2 N! l
的 3 轴角速度感测器(陀螺仪)2 M! s* D& }7 x2 M6 a% V
③ 集成可程序控制,范围为±2g、±4g、±8g 和±16g 的 3 轴加速度传感器  |5 W6 Z" d3 C
④ 移除加速器与陀螺仪轴间敏感度,降低设定给予的影响与感测器的飘移+ n, o( x. T+ \+ c$ t
⑤ 自带数字运动处理(DMP: Digital Motion Processing)引擎可减少 MCU 复杂的融合演算( A  X* |' B" y2 I) z' |* R
数据、感测器同步化、姿势感应等的负荷
7 q" ~! S4 G) Q⑥ 内建运作时间偏差与磁力感测器校正演算技术,免除了客户须另外进行校正的需求4 Y" g5 S. g1 [* [  b9 @9 N: f
⑦ 自带一个数字温度传感器9 ?! I1 S% @5 N, T4 ?+ E
⑧ 带数字输入同步引脚(Sync pin)支持视频电子影相稳定技术与 GPS
) C* E* C5 `9 |7 O⑨ 可程序控制的中断(interrupt),支持姿势识别、摇摄、画面放大缩小、滚动、快速下降8 `$ f. [9 M3 [6 B4 a& X
中断、 high-G 中断、零动作感应、触击感应、摇动感应功能9 `& J  u* E# A6 J: _1 w& Y) }
⑩ VDD 供电电压为 2.5V±5%、 3.0V±5%、 3.3V±5%; VLOGIC 可低至 1.8V± 5%
% O6 q% ]$ T% x5 [⑪ 陀螺仪工作电流: 5mA,陀螺仪待机电流: 5uA; 加速器工作电流: 500uA,加速器省1 N& q: y* L* L  E9 V/ P, u
电模式电流: 40uA@10Hz" `" E0 h; L( y
⑫ 自带 1024 字节 FIFO,有助于降低系统功耗; g& F3 z1 J  z
⑬ 高达 400Khz 的 IIC 通信接口
0 T$ v8 P8 W$ t⑭ 超小封装尺寸: 4x4x0.9mm(QFN)" P2 B0 ?: L1 z! J

8 h/ l' c& `8 G$ \
其检测轴如图所示:! c" h, l9 j) u$ r: e5 q

( |4 f4 z8 Y; P% U1 [2 Q% e  p
20200215154932517.png
% R9 }/ ], _: ~# G% ^2 C2 z2 i# i8 O( j" M
' s% z8 d3 a; b2 o
3.引脚说明
# I1 h. M  x: Y& A7 g* `& c0 P' X& a, v7 ~0 M
20200215160046383.jpg : N" E8 M0 l4 }& @( l. V7 z8 d) L( t2 Z

' k4 D) t- U2 |. q如图,MPU6050一共有8个引脚,实际上输出六轴数据时,只用了5个:VCC、GND、SCL、SDA、AD0。下面介绍一下引脚:
5 t  @- a, x/ j" u# J. kVCC:供电,3.3V即可
4 U, s' T) x$ j" Y% k& cGND:接地
# x, R: M* }" j$ CSCL:连接MCU的IIC时钟接口/ I& s) `5 Y( Z0 q" y$ ]
SAD:连接MCU的IIC数据接口6 L& @# v7 j: B) t  B5 u
XCL:连接外部设备的IIC时钟接口$ f$ w* e% R# S; H( m6 F
XAD:连接外部设备的IIC数据接口
7 S, I9 m0 A) @+ C8 q  C/ K/ oAD0:地址控制引脚(控制地址的最低位)
# n% ]) C, T3 CINT:中断触发接口(不用)6 x* \! H4 K. Z* H4 J
XCL、XDA只有在连接外部设备(比如磁力计的时候才用),AD0用来控制MPU6050的地址,如果AD0低电平,地址就是0X68;如果AD0高电平,地址就是0X69。
8 C) p5 c* u( E8 h% x$ y) T/ Q
. k, p/ z. P  j- P$ ?+ \4 F4.基本配置及相关寄存器
5 j7 P% ]9 @5 _+ _- pMCU与MPU6050的通信是建立在IIC通信机制上的,在IIC的基础上,可以实现对MPU6050的寄存器的操作,而MPU6050的运作就是过对寄存器进行读写。所以,了解相关的寄存器和对寄存器的操作是很有必要的。MPU6050的寄存器相关资料都可以在数据手册中查到,下面介绍一下几个重要的寄存器:
' `9 `/ J; b) `$ f+ O8 A
  \# \- {7 x2 ^, m电源管理寄存器10 [1 y$ M5 |9 y& ^: r
地址:0X68! a' }/ W( a) T  f

3 Q, `9 X. n- a9 ?0 i  W2 r# k0 \! f
2 ~" Z' ]( _5 r5 J2 P- O
20200215163434244.png 8 ?! U) w  \3 o5 B
1 s% e# O; N; i* Z' A) T
主要位的功能:9 N$ ?% B& o+ i* |& Y$ Z
DEVICE_RESET:控制复位,1表示复位,复位后会自动清零;9 B1 K" Q) G. M, A0 A
SLEEP:控制MPU6050工作模式,1表示睡眠模式,0表示正常工作模式,复位后改位为1,要手动将改位清零;/ c3 R) Y$ E. Z6 _
TEMP_DIS:使能温度传感器位,0代表使能;% I6 v9 q" E! y! s
CLKSEL[2:0]:选择系统时钟源,一般采用PLL_X轴陀螺作为参考,具体的时钟源选择及相应位的值如图:3 G. J7 i1 n: V- P

7 t& j0 h3 S! q. S; [2 l

4 f. v" M9 V$ {$ C" y3 N. ` 20200215164457650.png
6 i; `+ O' h1 O5 F2 T: |. I: H: A& G
陀螺仪配置寄存器
* z  L5 t( \) B" e" g  t地址:0X1B, Y' N; c5 U2 w

) ?2 t. A- e1 S; b# w
20200215164757727.png
1 W- @0 N/ @& Q5 [" y9 P9 u8 `
: _$ g5 M- }) Q6 i. C2 k; J2 n( Z
主要位的功能:
. {$ J6 V- @5 r( q4 BFS_SEL[1:0]:设置陀螺仪满量程范围:为0代表±250° /S、为1代表±500° /S、为2代表±1000° /S为3代表±2000° /S;$ q9 v) l8 U, q0 _2 Z% p# ~: g1 o
% G0 \8 A& D- V* j% a! x% e* P: \
陀螺仪的分辨率是16位,所以在最大量程下灵敏度为: 65536/4000=16.4LSB/(° /S)。+ U! g, S3 H2 d* |3 C

' C1 M9 X6 _6 h/ x9 c& Z  }4 ]加速度计配置寄存器
: r  o1 ]4 C9 F# U. A地址:0X1C4 [+ X" E  M% p& D

  D8 z5 `8 }. J' i
20200215165411152.png
4 p9 E: i% g8 p$ k

' T2 e) ]2 x2 y- \7 k主要位的功能:; i! B, Q& s7 r0 G6 Z( w+ z
AFS_SEL[1:0]:设置加速度计满量程范围:为 0代表±2g、为1代表±4g、为 2代表±8g、为 3代表±16g;
9 C1 x# E8 J$ Y* C% t8 Z& D. q- s8 Q
FIFO使能寄存器3 R9 c5 ?9 m, t% n. W
地址:0X23
  C' p8 \9 `6 V) \+ }3 J% E7 B" k  |' c
20200215165816272.png : b- T; d; V% k9 Q* M8 t! U

4 R- B3 J* h) d  i用来控制FIFO功能,相应位对应着相应的传感器FIFO功能,为0代表禁止,为1代表使能。注意:加速度传感器的三个轴的FIFO功能由一个位ACCEL_FIFO_EN控制。在简单读取传感器数据的情况下可以不使用FIFO。+ V& s* o- f  s  ~
8 ?  W1 Q9 U3 l" I
陀螺仪采样率分频寄存器
6 h( J6 ]% h/ R! a2 x- z' A  Q地址:0X19& P% q* w6 U# r0 A6 z# i- D0 b8 E/ y
1 L! J# X* [/ L; [7 j& Y
20200215170242372.png
% R8 m/ B" n! o

* @$ \4 Y! k# D4 d! X改寄存器用来设置MPU6050陀螺仪的采样频率,与之相关的是陀螺仪的输出频率,俩者关系是:采样频率 = 陀螺仪输出频率 / (1+SMPLRT_DIV)
" _( C, v- x7 n3 ]( Z陀螺仪输出频率与数字低通滤波器(DLPF)有关,DLPF滤波频率一般设置为采样率的一半。4 x( J4 X/ j6 M- J

$ F3 b1 Z$ [$ i! S3 w温度传感器寄存器
* Y* p: l4 k! O3 E! O" G+ A地址:高八位0X41、低八位0X422 Y4 L( B. R# P/ n
直接通过读取寄存器中的值来得到温度数据,温度换算公式为:; J  r  S  q0 T# X; _, z
Temperature = 36.53 + regval/3402 w% R& i% b- }# c& e
  F7 N& w. S- \
二.代码详解, b8 p& m7 U/ `4 o, l
1.框架

. {, \  q) P$ R8 s* o, C0 N, \我是用STM32驱动MPU6050,MPU6050输出原始的六轴数据,经过DMP处理(有库)得到四元数,再由四元数算出欧拉角:yaw、roll、pitch。由串口打印在电脑屏幕上。
: X  d, c2 H: s, l" i( g) `2 q首先,要做底层的IIC驱动,用来和MPU6050建立通信,我在mpu_iic.c中实现了;
: [; A( e+ B3 D3 e然后,有了底层的驱动,就要写一些函数来与MPU6050交流了(通过读写寄存器),还可以写入命令、配置MPU6050、读取原始数据等等,这些操作我都写在mpu6050.c中,当然在mpu6050.h头文件中还包含了MPU各寄存器地址和相关指令。
* A1 ?; }7 T' D2 I通过mpu6050.c的实现,就可以读出原始六轴数据,下一步就是通过DMP将原始数据转换为四元数,这一步的DMP算法我水平有限,只能移植InvenSense公司提供的例程。关于移植DMP算法,由于DMP算法本质也是对MPU6050的操作,所以我们只需要向移植过来的算法提供:对MPU6050寄存器执行读和写的函数接口即可,最后通过移植过来的函数直接读出四元数!
, k1 I9 V% I' b& Q" Q8 L然后,就是将四元数转换为欧拉角了,这个比较简单,一个函数就可以实现。0 E. `% e7 i3 Y2 ~5 H5 ]
最后,打印串口到屏幕。) g7 [0 P" L5 l, z

2 v# o' t0 q% d) _
下面给出各函数文件5 \. e  m0 T; s/ Y) K5 t
/ ~: n: U4 g$ W% q. F" [
2.mpu_iic.c/mpu_iic.h7 X6 [1 R$ Q$ L0 l' e
mpu_iic.h5 {2 I: Z- R4 L% N) F, Y
主要是宏定义对引脚电平的操作和进行函数声明。
* ]; [4 N9 U: _' Y# a5 U! i
  1. #ifndef __MPU_IIC_H1 L' N; U. S; z' d
  2. #define __MPU_IIC_H
    # u0 ]- o3 M2 J  y# w

  3. 2 h% G; c! `" M8 [
  4. #include "stm32f10x.h"( S. a: X2 ]9 e+ h6 j# G
  5. #include "delay.h"/ Y: D/ f$ A' N" E$ H% A- S- n4 b6 D
  6. 9 I. s2 |  t  ]/ i4 G
  7. /* 宏定义引脚电平操作函数 */" _8 u- K( w3 |, J; C
  8. #define MPU_SDA_IN()  {GPIOB->CRH&=0XFFFF0FFF;GPIOB->CRH|=8<<12;}
    . k) E/ e6 \) D& F8 I, y" Z
  9. #define MPU_SDA_OUT() {GPIOB->CRH&=0XFFFF0FFF;GPIOB->CRH|=3<<12;}  
    " ]$ V/ T6 }$ I0 J" c, v5 u$ e
  10. . C% J6 \3 G* Z. N- M% L6 \1 C! q

  11. " w7 O+ U6 X; c) X; p0 H
  12. #define MPU_IIC_SDA_1() GPIO_SetBits( GPIOB, GPIO_Pin_11 )
    9 k- H. |7 U% T9 `, D
  13. #define MPU_IIC_SDA_0() GPIO_ResetBits( GPIOB, GPIO_Pin_11 )
    $ `: ~) a7 {5 h1 M1 }4 U' k* l5 a

  14. + X% [9 n2 [- b% i
  15. #define MPU_IIC_SCL_1() GPIO_SetBits( GPIOB, GPIO_Pin_10 )
    3 e+ Q4 k' U/ |  |4 P$ ]
  16. #define MPU_IIC_SCL_0() GPIO_ResetBits( GPIOB, GPIO_Pin_10 )
    2 O* n8 H+ F0 a9 y* i6 x+ [

  17. # v  `( ?+ o4 L* r( g
  18. #define MPU_IIC_AD0_1() GPIO_SetBits( GPIOA, GPIO_Pin_15 )  G- I; L5 I/ v4 k/ Q2 V
  19. #define MPU_IIC_AD0_0() GPIO_ResetBits( GPIOA, GPIO_Pin_15 )
    " Z5 R- _; {0 X* {
  20. 7 o( D; g' n1 P
  21. #define MPU_IIC_SDA_READ() GPIO_ReadInputDataBit( GPIOB, GPIO_Pin_11 )6 d) Q, X- d: ~! c  I* H8 _9 W
  22. 3 F1 g/ l. l9 R* |
  23. #define MPU_IIC_Delay() delay_us(2)% z* s% T2 V, g

  24. % Y: o4 q0 o2 F7 \
  25. /* 函数声明 */
    , ~7 w- f4 X. h  b
  26. void MPU_IIC_Init( void );
    5 }8 L4 J0 T: I, _9 d
  27. void MPU_IIC_Start( void );
    . L" k  r5 R3 f' n8 z5 o* I
  28. void MPU_IIC_Stop( void );
    , I' t9 Z2 `# Y' c" D( M# ^+ X
  29. uint8_t MPU_IIC_Wait_Ack( void );. c- f/ e1 [0 z' L/ T6 W
  30. void MPU_IIC_Ack( void );
      ]. P9 T- u, z
  31. void MPU_IIC_NAck( void );+ ?7 I/ q9 I" P6 a: Q# m5 ~
  32. void MPU_IIC_Send_Byte( uint8_t data );$ l2 O4 S, K7 |# n0 X6 H
  33. uint8_t MPU_IIC_Read_Byte( uint8_t ack );) `* a& p, D! g; w

  34. / O% |& s7 P' g6 t7 H
  35. #endif. v) p1 v- s% [
  36. & ]8 W' L: J$ y! ]! A; L
复制代码

7 v& N! V# L: x6 f3 Ympu_iic.c
' r0 P) S  {5 C9 t通过软件模拟IIC的代码,没什么好说的。
/ X0 P" ]) @0 P; R# [
  1. #include "mpu_iic.h"
    / ~+ u# y1 M8 ]
  2. #include "usart.h"( \: q* I8 M' _6 [
  3. . y- b! U- F% q- H8 a2 i; o' f- s
  4. /*
    + h/ I. T: U7 m  \0 Z" o
  5. IIC接口引脚配置
    ) q" _: E# J3 ]" W& m
  6. SDA:PB11" b. ?/ k4 a1 i0 |. V
  7. SCL:PB10+ X/ E! q. ?4 d, U4 a/ u
  8. AD0:PB29 {4 \: ^' Z7 G# N/ @4 E
  9. */
    4 U- M9 N" C; ~1 y6 w8 T) F/ E
  10. void MPU_IIC_Init( void )
    . g5 b4 f+ s; E0 i4 j
  11. {
    9 q( A$ b+ O9 j# }- v! U
  12.         GPIO_InitTypeDef  GPIO_InitStruct;' e! Q! V6 q, N* y/ z1 K
  13.        
    , [3 M6 ^% h9 T3 {0 V
  14.         RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB, ENABLE );
    % E; {4 R: e7 W: J2 e" J
  15.        
    7 G( E: i: s( f( R) O2 e- V
  16.         GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
    % E" @% T' e) Q7 P
  17.         GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
    ' y8 s% s8 L2 r( ^3 u, c/ }! X
  18.         GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10|GPIO_Pin_11;
    & V4 Z* d: X8 \6 p, h  V' g. h6 t
  19.         GPIO_Init( GPIOB, &GPIO_InitStruct );
    . r) d& }. }1 Z2 j1 z/ {
  20.        
    , [5 _9 e, ]. O8 L* {
  21.         MPU_IIC_SDA_1();
    3 y$ G! j5 ^) h# }2 [
  22.         MPU_IIC_SCL_1();6 j, f7 K2 P: c
  23. 1 O/ T7 y: B' e' @' U. y
  24. }7 F- [* Y7 k6 b9 k

  25. 0 w/ F; @; Z! C
  26. % ~5 J3 F9 S; Z
  27. void MPU_IIC_Start( void )
    - \- [: k8 ?+ M* ~7 v5 m
  28. {! v0 c7 z* K/ ^1 t
  29.         MPU_SDA_OUT();
    ' H3 }* E+ ~+ k3 h  J& {
  30.        
    ( e$ l4 Q# Z/ _7 a
  31.         MPU_IIC_SDA_1();# ]6 b* H5 c$ l. j
  32.         MPU_IIC_SCL_1();9 j) J) ~5 ?% J* b8 c& n2 q
  33.         delay_us(2);( k$ I* P+ B- c$ y! I7 y
  34.         MPU_IIC_SDA_0();$ Q* [3 n9 P1 O4 i* L0 y
  35.         delay_us(2);/ {$ }% t+ c$ \  o
  36.         MPU_IIC_SCL_0();# v4 G2 K4 j; ]. Y( {% b6 c1 c
  37. }
    5 r5 s* p9 q" Y* B
  38. 4 ~$ Z: l( }8 }  I$ c
  39. void MPU_IIC_Stop( void )
    ; r! G. j& Z$ `0 v* ^5 ]! J; ]
  40. {. h" k1 T9 D7 P8 T$ r+ Y0 L
  41.         MPU_SDA_OUT();9 ]7 S3 k+ O7 W( S8 |) U
  42.         4 Q: @, Q% `1 j0 B; P
  43.         MPU_IIC_SDA_0();- h' o& P5 o3 h* ], C9 Q
  44.         MPU_IIC_SCL_1();
    : y0 l# L$ ~! w
  45.         delay_us(2);+ c+ S* d' i8 _% G
  46.         MPU_IIC_SDA_1();2 C- j* A1 S  W0 f. K
  47.         MPU_IIC_SCL_1();$ i+ E+ S/ S+ i+ S( D
  48.         delay_us(2);( Q" V# G6 ~7 I9 q) }7 \8 D
  49.         & L& K0 e- t/ U: I/ T' }
  50. }( {6 r) u6 N  K6 [
  51. : M- {8 g9 S4 F0 ]3 F
  52. /* 由从设备在SCL为高电平的时候拉低SDA作为应答
    6 w$ |  o% [4 Q6 B
  53. 返回值:1:未应答
    ! X* F8 c) a. S* Q
  54.         0:已应答! W1 u, q2 j3 w
  55. */% R: \9 X, {; _
  56. uint8_t MPU_IIC_Wait_Ack( void )- k# M  `9 _/ b. N8 }6 J- P5 @: X
  57. {
    ! L2 t0 B4 D. Q" y
  58.         uint8_t count;2 V+ ~$ H0 ^, O7 c+ a
  59.         MPU_SDA_IN();
    6 L" y# t& i! r7 n* y; r
  60.         ) D$ s6 u( \2 A) P, N
  61.         MPU_IIC_SCL_1();
    ( Z( |4 I; x: g+ |6 Y. \
  62.         delay_us(2);( m! a0 ?4 E, i* R! A
  63.         MPU_IIC_SDA_1();
    , i5 j/ @/ X& S% s
  64.         delay_us(2);
    8 Q* P% ^) G/ e4 N
  65.         ! A; @. `  U: E5 J- I
  66.         while( MPU_IIC_SDA_READ()==1 )
    $ `# l1 }/ r8 c# C# \( ?
  67.         {
    4 k3 V! v  k# ?& V# o
  68.                 count++;
    8 V2 i1 S% A% V' Y
  69.                 if( count>250 )* c+ }7 h( ^# ?6 f1 v5 _
  70.                 {, D5 r8 N8 P3 [9 w! B$ V
  71.                         MPU_IIC_Stop();
    0 Z: _/ U; p2 z
  72.                         return 1;
    8 K% V( Q4 o3 f
  73.                 }7 ?; E- u+ }$ {
  74.         }        1 X' I' J. L: b, B# x
  75.         MPU_IIC_SCL_0();
    8 g) V6 d" {$ O9 \, R% u
  76.         return 0;
    5 R. D6 s0 h3 q1 [; M: N
  77. }6 @1 C) u8 u! C% {% K

  78. % k* z8 R" {( o1 `! S! H
  79. ! G( s2 f. l1 B5 D" r
  80. void MPU_IIC_Ack( void )8 z! c9 d, ?- w! @8 H/ G
  81. {' `; p/ t2 r4 b2 X& P. B
  82.        
      C9 W: [1 W# X, W; f/ S
  83.         MPU_IIC_SCL_0();
    8 z) A" @! O1 S, U& q) X
  84.         MPU_SDA_OUT();4 H: {: A" N, u' }$ z: s
  85.         MPU_IIC_SDA_0();. m' n( z  m, D* A0 }! Q
  86.         delay_us(2);
    , x" u' l  L2 H2 }( @
  87.         MPU_IIC_SCL_1();, G( k! A* v/ w2 w" D
  88.         delay_us(2);4 D1 k: t# z  q* g
  89.         MPU_IIC_SCL_0();
    4 ?5 m7 k3 J2 M- u
  90.         $ \7 ~& E/ i2 y0 y" _' j+ o7 V( a
  91. }
    # W' ^! n. @- J( C! n

  92. 4 p. p  l' n$ A1 d' f
  93. 4 O* z9 ~; k# z) }
  94. void MPU_IIC_NAck( void )
    5 \. p$ C( s0 ^4 k% r0 t; C6 l. O
  95. {
    # C2 n4 N3 c. ]1 \* b
  96.        
    9 V' K. S% K! Q$ H4 `
  97.        
    4 U+ a) S/ w2 i% _+ ^1 U9 a
  98.         MPU_IIC_SCL_0();
    8 U) R; r) q6 }. \
  99.         MPU_SDA_OUT();) b* \* ^, |% L4 T# X* W
  100.         MPU_IIC_SDA_1();
    7 B: z( F: O; r; P
  101.         delay_us(2);  a/ i! O  z  P0 t! T1 F/ W
  102.         MPU_IIC_SCL_1();
    2 O9 [" l( e6 @6 j, i
  103.         delay_us(2);
    8 X# z( o- `% i0 ~5 n0 y# O& f
  104.         MPU_IIC_SCL_0();
    : A% ?! T; J0 L* D9 y8 b5 i0 O2 R# u
  105. }
    % f2 S( ^) t% o% s) t. j2 {

  106. % r+ b' \- k: ]' }" i% D

  107. / Z6 z5 O5 b: v
  108. /* 发送一个字节数据,高位先行 */- n; v* M" V$ Z
  109. void MPU_IIC_Send_Byte( uint8_t data )$ i9 [  u/ s9 g1 D+ a9 O
  110. {
    5 U1 Y6 W  |$ ?; W' t) k/ }
  111.         uint8_t t;, U  \) B) D, B9 X$ G% B5 ]4 ~6 d
  112.         MPU_SDA_OUT();
    & V, h5 w" I! U. i
  113.        
    ( w9 z4 m$ K& Y  m. U) T( Z! y) ]
  114.         MPU_IIC_SCL_0();
    - t& H) o2 c) Q- }9 d4 I6 S# f
  115.         for( t=0;t<8;t++ )
    ' s  C! A5 [/ r+ P2 B) J- K; `
  116.         {
    * J  J4 @* T7 Z3 [6 k' g
  117.                 if( ((data&0x80)>>7)==1 )6 }0 Y+ _4 y/ k2 v, t( l
  118.                         MPU_IIC_SDA_1();2 C0 K, z# ]; _& V
  119.                 else  ?' |. Q; f4 o/ e4 s8 v
  120.                         MPU_IIC_SDA_0();" c! j* |% m2 b7 j, L
  121.                 data<<=1;( \" Z5 A6 n1 L4 H4 K2 m
  122.                 MPU_IIC_SCL_1();
    5 F  F+ ?- g- R( r: ]
  123.                 delay_us(2);
    0 s4 d' _' e* u) Q2 _1 ?
  124.                 MPU_IIC_SCL_0();2 {3 M' N( d! ~
  125.                 delay_us(2);4 w: R/ O- B: P. R9 d. c, b% Z
  126.         }
    - P* c* |* d2 b6 O& t8 {2 V  W: \0 a0 r
  127. }
    + [2 z+ ?. I  S& I3 ]: p
  128. 0 {8 E/ q1 y8 B" m. {  t, y; R

  129. - Q7 j$ l6 t1 L% ^- ^: S/ H, `
  130. /* 读取一个字节,ack=1时,读取完成后主机发送应答 */+ r1 K% ?1 o. ?$ d% j
  131. uint8_t MPU_IIC_Read_Byte( uint8_t ack ): E. V& g0 y" X. A, K  s
  132. {$ k4 o$ U! r3 |0 ~% C
  133.         uint8_t t,data=0;/ O. S4 H0 r8 I+ J' X% P
  134.         MPU_SDA_IN();) Z/ F1 M1 ~* \, |8 J- R% j; \5 }
  135.         for( t=0;t<8;t++ )' C6 F: Q3 s+ F! Q5 y- B
  136.         {- [3 B4 U' w# p# m( [0 E& v8 R0 B( p
  137.                 MPU_IIC_SCL_0();
    & h0 h: E. A7 A0 I9 w9 Y0 O6 F& [
  138.                 delay_us(2);//等待SDA的变化, x( J: a0 f2 j8 o- c# m2 Q  V
  139.                 MPU_IIC_SCL_1();
    . Q7 |  o( y% c0 h4 d) T
  140.                 : G, B0 Y: B4 u! }
  141.                 data<<=1;//必须在读取前面,因为之后一位读取后就不再移位
    0 b  t# g& W. ]+ W1 Z9 G8 ?5 B8 Q
  142.                 if( MPU_IIC_SDA_READ()==1 )# _* J) P& k: b# b0 ^4 {- m, ^6 D
  143.                         data++;
    9 T! _6 ~) a& e
  144.                
    4 g' g1 B1 I3 O1 E" ?$ W
  145.                 delay_us(2);//等待SDA的变化
    0 b+ t# a& w" K# |7 q
  146.                
    $ g( @" S; n) N9 @+ ~
  147.         }
    & _5 w7 g- l8 K9 F
  148. 9 c" L- F4 g7 i" i
  149.         if( !ack )
    3 [0 }+ k1 x. C0 D  |/ C2 T
  150.                 MPU_IIC_NAck();//发送nACK
    5 ~& t" {5 T# }& ^
  151.     else
    ) o2 G6 |9 |6 f4 n  s% h& q$ `
  152.         MPU_IIC_Ack(); //发送ACK 6 s/ \; Z: B3 k4 D4 K9 t8 k( X
  153.         return data;
    * S* N  a4 D, m7 D' x' `
  154. }4 z( R' O8 [; y. ?5 u
  155. ; S: B2 Q6 u) S* x( M
  156. 4 T+ F& M+ g: c7 ]- s7 s1 L
复制代码
, Z+ t6 V" [" B+ y2 r
3.mpu6050.c/mpu6050.h
, d% K/ r+ l+ D' O$ pmpu6050.h
# Q* u& ^5 |* M" q3 G+ |* b  G主要是定义MPU相关寄存器的地址,和进行函数声明。( c5 ~& Y3 A# b9 a) X
  1. #ifndef __MPU6050_H
    1 _2 o1 U4 z( v% ?
  2. #define __MPU6050_H
    ) `: k% s' j* h. s+ p9 \7 O
  3. 7 p; V6 e( d" [3 T
  4. #include "stm32f10x.h"
    : i, ~! u  U# U' V& C% w0 d$ E
  5. #include "mpu_iic.h"# C* ]" z& j8 W- c+ R% f3 }/ k
  6. ( ^3 J5 \0 O, `; {1 Z
  7. - f5 @4 E2 m1 t  l
  8. /* AD0接地,MPU6050的IIC地址为0x68   接3.3V就为0x69*/0 ?9 l* `/ d8 S+ }
  9. #define MPU_ADDR                                0X68
    1 V* f) _* O$ c
  10. ( P6 x+ u  ~" u* c
  11. /************** MPU6050相关寄存器地址 *********************/
    1 c& K# D0 y$ M1 d3 y  z
  12. #define MPU_ACCEL_OFFS_REG                0X06        //accel_offs寄存器,可读取版本号,寄存器手册未提到
    1 X2 L% l: d& |, L
  13. #define MPU_PROD_ID_REG                        0X0C        //prod id寄存器,在寄存器手册未提到
    2 ?1 F( I2 `- F5 e7 w
  14. #define MPU_SELF_TESTX_REG                0X0D        //自检寄存器X! |' ?; t/ a; ]. W3 u# t
  15. #define MPU_SELF_TESTY_REG                0X0E        //自检寄存器Y. @5 [+ j" K+ X
  16. #define MPU_SELF_TESTZ_REG                0X0F        //自检寄存器Z
    , x, _  M( A$ U  c- b9 }
  17. #define MPU_SELF_TESTA_REG                0X10        //自检寄存器A9 Y7 G2 a+ t7 C( B" n% ^4 s
  18. #define MPU_SAMPLE_RATE_REG                0X19        //采样频率分频器
    ) X' i1 L5 Q3 _
  19. #define MPU_CFG_REG                                0X1A        //配置寄存器* r- D- \  ^. s7 v3 ~* V
  20. #define MPU_GYRO_CFG_REG                0X1B        //陀螺仪配置寄存器8 B7 ^1 `" I3 h, M
  21. #define MPU_ACCEL_CFG_REG                0X1C        //加速度计配置寄存器% q1 e8 c+ C9 Y, V) u" p. ^$ _2 Y  i
  22. #define MPU_MOTION_DET_REG                0X1F        //运动检测阀值设置寄存器1 B; h! V$ f; Z6 n$ @5 L4 Y/ t
  23. #define MPU_FIFO_EN_REG                        0X23        //FIFO使能寄存器
    * \) d  Q) a' k% c$ X
  24. #define MPU_I2CMST_CTRL_REG                0X24        //IIC主机控制寄存器  q$ _9 l2 w# H% Q( _* v
  25. #define MPU_I2CSLV0_ADDR_REG        0X25        //IIC从机0器件地址寄存器
    1 j5 ~  m9 Y, a" Q! [" `* N: p
  26. #define MPU_I2CSLV0_REG                        0X26        //IIC从机0数据地址寄存器
    % B% I! h" a& G% ~' d, Y
  27. #define MPU_I2CSLV0_CTRL_REG        0X27        //IIC从机0控制寄存器! E5 m% s1 q5 S, k
  28. #define MPU_I2CSLV1_ADDR_REG        0X28        //IIC从机1器件地址寄存器3 ^: U9 `! ?  ]+ b: v( P- D" E
  29. #define MPU_I2CSLV1_REG                        0X29        //IIC从机1数据地址寄存器' L( m' ]2 D& K+ o: b' |
  30. #define MPU_I2CSLV1_CTRL_REG        0X2A        //IIC从机1控制寄存器5 a4 s# S, h7 X: ^/ H
  31. #define MPU_I2CSLV2_ADDR_REG        0X2B        //IIC从机2器件地址寄存器/ e6 z7 X+ n3 P8 d- \
  32. #define MPU_I2CSLV2_REG                        0X2C        //IIC从机2数据地址寄存器' o" e; R1 y. _( b& Z
  33. #define MPU_I2CSLV2_CTRL_REG        0X2D        //IIC从机2控制寄存器$ |* d7 Y9 w9 {$ d" n8 N
  34. #define MPU_I2CSLV3_ADDR_REG        0X2E        //IIC从机3器件地址寄存器
    3 B1 u; V- g4 Q9 h  l$ s# ?
  35. #define MPU_I2CSLV3_REG                        0X2F        //IIC从机3数据地址寄存器6 k) p/ E& E: i
  36. #define MPU_I2CSLV3_CTRL_REG        0X30        //IIC从机3控制寄存器
    4 U: l3 s1 j. j) v- i' ^
  37. #define MPU_I2CSLV4_ADDR_REG        0X31        //IIC从机4器件地址寄存器
    ; t3 g/ U2 q+ G1 h; A. A
  38. #define MPU_I2CSLV4_REG                        0X32        //IIC从机4数据地址寄存器
    : a, K5 j% z, U1 q; J3 ?
  39. #define MPU_I2CSLV4_DO_REG                0X33        //IIC从机4写数据寄存器
    + t4 j5 E" ]3 Y6 q  p) j4 x
  40. #define MPU_I2CSLV4_CTRL_REG        0X34        //IIC从机4控制寄存器
    4 R& T/ c5 O# V2 X6 u
  41. #define MPU_I2CSLV4_DI_REG                0X35        //IIC从机4读数据寄存器
    8 {( ]. i4 ~$ E
  42. ; S+ G8 |; B+ ]2 w2 t" h- \" ^
  43. #define MPU_I2CMST_STA_REG                0X36        //IIC主机状态寄存器
    & D2 {, [" @/ M1 f
  44. #define MPU_INTBP_CFG_REG                0X37        //中断/旁路设置寄存器% Z$ _: ~) @% b1 m% u* L
  45. #define MPU_INT_EN_REG                        0X38        //中断使能寄存器( E! I; ?. `+ g: i; _2 S
  46. #define MPU_INT_STA_REG                        0X3A        //中断状态寄存器
    ) S* n( O# h* c  F
  47. * O; D$ }% A! _7 P' i
  48. #define MPU_ACCEL_XOUTH_REG                0X3B        //加速度值,X轴高8位寄存器
    - a- ^$ w) F. k" c
  49. #define MPU_ACCEL_XOUTL_REG                0X3C        //加速度值,X轴低8位寄存器, F& `6 s& m) k; c
  50. #define MPU_ACCEL_YOUTH_REG                0X3D        //加速度值,Y轴高8位寄存器: Z* S2 _% D' }
  51. #define MPU_ACCEL_YOUTL_REG                0X3E        //加速度值,Y轴低8位寄存器& ^% y- z5 H* f
  52. #define MPU_ACCEL_ZOUTH_REG                0X3F        //加速度值,Z轴高8位寄存器
    , `$ ?, O1 R2 J$ v6 V; B
  53. #define MPU_ACCEL_ZOUTL_REG                0X40        //加速度值,Z轴低8位寄存器8 p( E& g$ {* c+ f' N& u$ d# q
  54. 1 D, u8 n2 n! W% m& A/ W
  55. #define MPU_TEMP_OUTH_REG                0X41        //温度值高八位寄存器- s9 d! l# j6 v5 A& u7 g8 D4 O
  56. #define MPU_TEMP_OUTL_REG                0X42        //温度值低8位寄存器: v3 X9 k  z. J; N  c, }

  57. % ]; U8 }! o6 J- |" |6 D/ K, T
  58. #define MPU_GYRO_XOUTH_REG                0X43        //陀螺仪值,X轴高8位寄存器
    3 k. r/ ?' J7 M9 L9 W1 ~$ g: _
  59. #define MPU_GYRO_XOUTL_REG                0X44        //陀螺仪值,X轴低8位寄存器* ?) W; P8 X9 e- ^4 Q$ [, z
  60. #define MPU_GYRO_YOUTH_REG                0X45        //陀螺仪值,Y轴高8位寄存器1 d; d" ~% f& N# v4 n9 j5 o
  61. #define MPU_GYRO_YOUTL_REG                0X46        //陀螺仪值,Y轴低8位寄存器/ n( b/ x+ B4 O, d2 g6 i. l3 w
  62. #define MPU_GYRO_ZOUTH_REG                0X47        //陀螺仪值,Z轴高8位寄存器
    0 G) M% c7 l2 ~
  63. #define MPU_GYRO_ZOUTL_REG                0X48        //陀螺仪值,Z轴低8位寄存器
    / W. w1 C8 v* A4 [% a

  64. ( D  T1 Q* v4 M2 ~  A# y& i* F
  65. #define MPU_I2CSLV0_DO_REG                0X63        //IIC从机0数据寄存器
    * X$ k7 ?4 X: t# r
  66. #define MPU_I2CSLV1_DO_REG                0X64        //IIC从机1数据寄存器* L7 i* F, E" h. f- E4 H
  67. #define MPU_I2CSLV2_DO_REG                0X65        //IIC从机2数据寄存器5 o" y2 f. ]6 {6 A8 H" U- v6 q' c
  68. #define MPU_I2CSLV3_DO_REG                0X66        //IIC从机3数据寄存器
    6 I7 H3 K8 |- o0 M

  69. / G' k  \- ]7 ]% r
  70. #define MPU_I2CMST_DELAY_REG        0X67        //IIC主机延时管理寄存器- u# k" ^3 [" t& W; H/ m+ t% j
  71. #define MPU_SIGPATH_RST_REG                0X68        //信号通道复位寄存器0 M" J5 B' C: X
  72. #define MPU_MDETECT_CTRL_REG        0X69        //运动检测控制寄存器
    0 E6 u) j) v# q0 T2 \* B
  73. #define MPU_USER_CTRL_REG                0X6A        //用户控制寄存器
    ) i" P& z+ K6 V3 z: Q
  74. #define MPU_PWR_MGMT1_REG                0X6B        //电源管理寄存器1
      N' h  Q7 O8 W+ N! L3 x
  75. #define MPU_PWR_MGMT2_REG                0X6C        //电源管理寄存器2
    7 l' D; [  n9 k. s$ r9 M) d/ J
  76. #define MPU_FIFO_CNTH_REG                0X72        //FIFO计数寄存器高八位# C' B0 L5 w0 \% H8 R
  77. #define MPU_FIFO_CNTL_REG                0X73        //FIFO计数寄存器低八位5 ^8 z+ s6 `# M* v0 I
  78. #define MPU_FIFO_RW_REG                        0X74        //FIFO读写寄存器
    6 A4 ~$ Y. h& Q/ c
  79. #define MPU_DEVICE_ID_REG                0X75        //器件ID寄存器
    : }: _7 v4 _+ J# u# M; ~

  80. % U' ]  F7 M( g) ~2 b; P
  81. ; m$ m! A4 R$ h' z7 f* U

  82. & R/ x" O$ n$ W: S5 A
  83. + j4 f; }- x  w
  84. /* 函数声明 */; c8 I, \1 W! b9 Q: ?" ?
  85. uint8_t MPU_Read_Byte( uint8_t reg );
    ( S, I+ |7 Q/ y, h9 D0 k
  86. uint8_t MPU_Write_Byte( uint8_t reg, uint8_t data );8 h' a+ ~7 @9 n* x
  87. uint8_t MPU_Read_Continue( uint8_t addr, uint8_t reg, uint8_t len, uint8_t *buf );
    3 q# l0 @, E" Y2 b9 ]5 J
  88. uint8_t MPU_Write_Continue( uint8_t addr, uint8_t reg, uint8_t len, uint8_t *buf );- e6 P+ M% k) s

  89. ) o) C! o5 }6 `
  90. uint8_t MPU_Init( void );' P8 P( N8 R, A% _3 F' a1 s& i
  91. . u/ i% a5 |, C9 F6 b+ G4 k: e/ V

  92. % V) [, X  ]5 k5 [! Z! h
  93. uint8_t MPU_Set_Gyro_Fsr( uint8_t fsr );4 E6 K3 O9 w, D& t; I+ k. G
  94. uint8_t MPU_Set_Accel_Fsr( uint8_t fsr );
    5 l! U) e. w7 ^1 [+ X$ l. P/ `
  95. uint8_t MPU_Set_LPF( uint16_t lpf );; ?8 H- X9 M. a9 f5 o* N
  96. uint8_t MPU_Set_Rate( uint16_t rate );) D. P! M: d' a
  97. short MPU_Get_Temperature( void );! N% B8 s' \9 D( J; U1 U$ I  d' k& x
  98. uint8_t MPU_Get_Gyroscope( short *gx, short *gy, short *gz );
    * b; i8 N& y$ B) V- {3 ]
  99. uint8_t MPU_Get_Accelerometer( short *ax, short *ay, short *az );
    3 s8 _0 G1 v# N, M- n* A& z$ r# ]
  100. 6 k3 g2 S/ T+ N; O8 G3 q
  101. #endif
    8 n/ r  y6 B9 Q$ V

  102. & @! L2 F3 A3 E3 c% k
复制代码
8 G& k: R! O8 m- K
mpu6050.c! T- J3 {# o- r9 k: n
最为重要的一部分代码,包括了对MPU6050的一系列基本配置和读取原始数据的操作,代码都注解的很详细了。
; T) `1 W! ^' r5 ~AD0引脚用了PA15,所以要GPIO_Remap_SWJ_JTAGDisable,换个引脚也可以。. l- @, _( h) U; V
  1. #ifndef __MPU6050_H% q. y, }+ \- n+ r7 t: n
  2. #define __MPU6050_H
    & F+ P6 W. I4 K( ?. ?- n

  3. 4 L. J/ x' J) S4 n0 A
  4. #include "stm32f10x.h"- K" j) ~  n" u- P/ k" A2 Y2 V
  5. #include "mpu_iic.h"
    # s6 G# G" Z2 w) ]& R3 {  @! W

  6. 8 K0 C* C% ^3 V# j( y8 P: q

  7. & J2 V% ?- Z0 l! g+ g: C
  8. /* AD0接地,MPU6050的IIC地址为0x68   接3.3V就为0x69*/
    & b% X) @! A8 U+ h! I+ L
  9. #define MPU_ADDR                                0X68; k  C  W* \: b) U8 A( _: K

  10. " O  |; l# w9 @' Q" Y7 e" H
  11. /************** MPU6050相关寄存器地址 *********************/
    3 n2 E  H- S+ E7 @* h8 b0 }
  12. #define MPU_ACCEL_OFFS_REG                0X06        //accel_offs寄存器,可读取版本号,寄存器手册未提到
    ! u" e& _' W  o
  13. #define MPU_PROD_ID_REG                        0X0C        //prod id寄存器,在寄存器手册未提到
      ?$ }7 z4 K, B: c) b- [' {
  14. #define MPU_SELF_TESTX_REG                0X0D        //自检寄存器X1 d% ], {% N* m2 b0 l
  15. #define MPU_SELF_TESTY_REG                0X0E        //自检寄存器Y
    $ ?  B$ \% V& B1 x; T
  16. #define MPU_SELF_TESTZ_REG                0X0F        //自检寄存器Z8 r' v! S+ m/ P
  17. #define MPU_SELF_TESTA_REG                0X10        //自检寄存器A- Q# I0 D/ o. j  X- ?
  18. #define MPU_SAMPLE_RATE_REG                0X19        //采样频率分频器- f1 y/ I8 j. N/ u+ [2 R
  19. #define MPU_CFG_REG                                0X1A        //配置寄存器- f; G* u; _4 q: K2 m
  20. #define MPU_GYRO_CFG_REG                0X1B        //陀螺仪配置寄存器2 l3 n# k" z5 t& F9 p' E/ F
  21. #define MPU_ACCEL_CFG_REG                0X1C        //加速度计配置寄存器
    ' Y- `7 D& S  |& R0 s3 y6 k# J
  22. #define MPU_MOTION_DET_REG                0X1F        //运动检测阀值设置寄存器5 [& v' O) z5 W8 G9 |
  23. #define MPU_FIFO_EN_REG                        0X23        //FIFO使能寄存器
    0 q( [! C% k  Q+ F/ v
  24. #define MPU_I2CMST_CTRL_REG                0X24        //IIC主机控制寄存器
    ) a: E' A  i& P0 j# i& h2 G) {. c  E' N
  25. #define MPU_I2CSLV0_ADDR_REG        0X25        //IIC从机0器件地址寄存器7 B9 ~1 N' P# X( ]
  26. #define MPU_I2CSLV0_REG                        0X26        //IIC从机0数据地址寄存器
    6 e# Z  u3 Y4 _$ p
  27. #define MPU_I2CSLV0_CTRL_REG        0X27        //IIC从机0控制寄存器8 o% U8 S. \6 t, H- k. U1 ^
  28. #define MPU_I2CSLV1_ADDR_REG        0X28        //IIC从机1器件地址寄存器# `! |$ c) z9 _7 |! T0 {
  29. #define MPU_I2CSLV1_REG                        0X29        //IIC从机1数据地址寄存器
    - }+ f3 m% s" Q" h& H
  30. #define MPU_I2CSLV1_CTRL_REG        0X2A        //IIC从机1控制寄存器' _7 o' u; q' j! |" n% `) W( z$ P
  31. #define MPU_I2CSLV2_ADDR_REG        0X2B        //IIC从机2器件地址寄存器
    2 d. P. T; _9 G/ ^) z  ?5 M
  32. #define MPU_I2CSLV2_REG                        0X2C        //IIC从机2数据地址寄存器
    8 S( Z2 x3 }! c+ n" ]7 ~
  33. #define MPU_I2CSLV2_CTRL_REG        0X2D        //IIC从机2控制寄存器
    ! G* k1 S' @2 E2 n8 z6 l& t' \6 |
  34. #define MPU_I2CSLV3_ADDR_REG        0X2E        //IIC从机3器件地址寄存器8 H* N2 W! A4 g0 i
  35. #define MPU_I2CSLV3_REG                        0X2F        //IIC从机3数据地址寄存器/ h( {5 q! b# @/ v- w
  36. #define MPU_I2CSLV3_CTRL_REG        0X30        //IIC从机3控制寄存器1 {8 Y. j- A5 I1 d% H
  37. #define MPU_I2CSLV4_ADDR_REG        0X31        //IIC从机4器件地址寄存器3 p; p5 }1 {0 T) I
  38. #define MPU_I2CSLV4_REG                        0X32        //IIC从机4数据地址寄存器
      c) Q. \* [/ e+ L
  39. #define MPU_I2CSLV4_DO_REG                0X33        //IIC从机4写数据寄存器
    ) W& x" d" ]4 ~8 |" G: H) ]4 ^# L
  40. #define MPU_I2CSLV4_CTRL_REG        0X34        //IIC从机4控制寄存器9 P( s* W- v8 |5 e/ a; ^
  41. #define MPU_I2CSLV4_DI_REG                0X35        //IIC从机4读数据寄存器
    . x: W& |0 t+ s3 Z8 u) c
  42. . e( u. T: u" o! x) E) S, x
  43. #define MPU_I2CMST_STA_REG                0X36        //IIC主机状态寄存器
    ' ?( t+ B- A& ?- o1 ~
  44. #define MPU_INTBP_CFG_REG                0X37        //中断/旁路设置寄存器
    - @* l" d7 b; {4 e/ E4 l
  45. #define MPU_INT_EN_REG                        0X38        //中断使能寄存器, y# T  `0 D. I. T" \. Q
  46. #define MPU_INT_STA_REG                        0X3A        //中断状态寄存器
    - b$ y5 c% L& c
  47. 8 |: {' B. M) v/ n# J. M
  48. #define MPU_ACCEL_XOUTH_REG                0X3B        //加速度值,X轴高8位寄存器
    5 s6 m: d5 q$ T$ Q* Z
  49. #define MPU_ACCEL_XOUTL_REG                0X3C        //加速度值,X轴低8位寄存器
    6 E2 e% W: y- ~7 H0 ?) c' P; P% o
  50. #define MPU_ACCEL_YOUTH_REG                0X3D        //加速度值,Y轴高8位寄存器2 Q6 m1 |* H: a3 s- U% I- _6 O
  51. #define MPU_ACCEL_YOUTL_REG                0X3E        //加速度值,Y轴低8位寄存器' x! V0 n0 q1 Q" ^, x. c4 G, \
  52. #define MPU_ACCEL_ZOUTH_REG                0X3F        //加速度值,Z轴高8位寄存器
    3 h6 A1 D3 q9 M$ u, k$ N( C
  53. #define MPU_ACCEL_ZOUTL_REG                0X40        //加速度值,Z轴低8位寄存器1 t5 X* C) F3 w- }5 f2 v; q# W

  54. : i& H0 E) r  r. j  J
  55. #define MPU_TEMP_OUTH_REG                0X41        //温度值高八位寄存器
    + q6 K2 S6 a+ i+ L1 Q
  56. #define MPU_TEMP_OUTL_REG                0X42        //温度值低8位寄存器
    8 ?* h5 U& m. B+ C
  57. * I, k% u" n  K+ P- L  d
  58. #define MPU_GYRO_XOUTH_REG                0X43        //陀螺仪值,X轴高8位寄存器& t- Z; i, ?0 j$ ^. _+ S% g1 W
  59. #define MPU_GYRO_XOUTL_REG                0X44        //陀螺仪值,X轴低8位寄存器
    ! N  E( K1 N, O2 q
  60. #define MPU_GYRO_YOUTH_REG                0X45        //陀螺仪值,Y轴高8位寄存器" q# p0 _2 a2 k$ s" X+ `6 F
  61. #define MPU_GYRO_YOUTL_REG                0X46        //陀螺仪值,Y轴低8位寄存器
    ) j+ e2 V. h$ r
  62. #define MPU_GYRO_ZOUTH_REG                0X47        //陀螺仪值,Z轴高8位寄存器0 h# }- |$ h! {* K, o7 I
  63. #define MPU_GYRO_ZOUTL_REG                0X48        //陀螺仪值,Z轴低8位寄存器
    " r8 ]4 t7 K' s2 Z

  64. : r4 t; ^* c) L# t" L, S
  65. #define MPU_I2CSLV0_DO_REG                0X63        //IIC从机0数据寄存器, J6 b. r. x0 S3 T9 @
  66. #define MPU_I2CSLV1_DO_REG                0X64        //IIC从机1数据寄存器
    5 M0 t* G+ O' h3 F# U( l, ]$ @
  67. #define MPU_I2CSLV2_DO_REG                0X65        //IIC从机2数据寄存器8 u1 m: Z4 t8 ?$ Q% b
  68. #define MPU_I2CSLV3_DO_REG                0X66        //IIC从机3数据寄存器
    0 U$ V4 ]& g- r$ O/ ~

  69. + o* z% B5 Q: T8 j  D2 b) \. ~5 V
  70. #define MPU_I2CMST_DELAY_REG        0X67        //IIC主机延时管理寄存器
    2 q' ]8 s  |$ q+ D: b  b
  71. #define MPU_SIGPATH_RST_REG                0X68        //信号通道复位寄存器
    ; I" [4 q# ?( r/ E: h1 _0 g0 N2 y
  72. #define MPU_MDETECT_CTRL_REG        0X69        //运动检测控制寄存器
    7 \  N: S! s- l9 h& \, v, P
  73. #define MPU_USER_CTRL_REG                0X6A        //用户控制寄存器8 _$ ?/ C2 h7 K9 T3 H0 R
  74. #define MPU_PWR_MGMT1_REG                0X6B        //电源管理寄存器19 F  I5 t8 N; ?2 B4 p( N" T" k
  75. #define MPU_PWR_MGMT2_REG                0X6C        //电源管理寄存器2 7 W, W( Q# q( x7 h
  76. #define MPU_FIFO_CNTH_REG                0X72        //FIFO计数寄存器高八位7 D; j- w' ~5 w3 X- h
  77. #define MPU_FIFO_CNTL_REG                0X73        //FIFO计数寄存器低八位% v: I: s# n  S
  78. #define MPU_FIFO_RW_REG                        0X74        //FIFO读写寄存器
    0 T0 ?, {/ w; R1 P! d6 {/ u
  79. #define MPU_DEVICE_ID_REG                0X75        //器件ID寄存器
    ) r, D, B9 L! |: x( U3 k: H

  80. % z0 O+ O1 P$ t4 t- t
  81. . X0 W1 v+ V& y1 G

  82. 4 f+ C+ r5 |/ S3 D3 J

  83. / r. L$ y7 n1 _# u
  84. /* 函数声明 *// v; N  b# _  q) y
  85. uint8_t MPU_Read_Byte( uint8_t reg );' U; _' m& F5 e
  86. uint8_t MPU_Write_Byte( uint8_t reg, uint8_t data );) \$ a' X) C, }2 h8 r3 N$ X
  87. uint8_t MPU_Read_Continue( uint8_t addr, uint8_t reg, uint8_t len, uint8_t *buf );( o* R  w) V' h+ c$ z& b
  88. uint8_t MPU_Write_Continue( uint8_t addr, uint8_t reg, uint8_t len, uint8_t *buf );/ u$ K. {4 v# a$ a$ M6 O
  89. 6 Q# n4 g( D8 X. f& [
  90. uint8_t MPU_Init( void );
    - V: N1 ]7 |$ j4 f' @4 D& i0 K
  91. 7 J  @. `! N9 F9 s

  92. % \1 N, V. _0 W+ U
  93. uint8_t MPU_Set_Gyro_Fsr( uint8_t fsr );1 Q7 q5 i$ C+ |4 m# i1 s" L
  94. uint8_t MPU_Set_Accel_Fsr( uint8_t fsr );- E7 |" K) v2 N6 |
  95. uint8_t MPU_Set_LPF( uint16_t lpf );' B% g8 _; d5 n$ l
  96. uint8_t MPU_Set_Rate( uint16_t rate );
    $ T* {& N! y% K( O
  97. short MPU_Get_Temperature( void );
    , ?! R6 ]# X$ z+ P4 t2 G) w
  98. uint8_t MPU_Get_Gyroscope( short *gx, short *gy, short *gz );" K2 p0 h; ~3 C( H: g9 t, l
  99. uint8_t MPU_Get_Accelerometer( short *ax, short *ay, short *az );
    8 Y. v& @$ K1 p) N( {: d% }
  100. 9 l# [- |* I7 c, M, M
  101. #endif4 ~" [9 p( e5 N! z( g5 e8 l. b2 a

  102. 6 y8 [/ a( [. z6 F
复制代码
! _; b+ q0 G+ x
4.DMP相关代码6 F4 k# c9 V8 b  N" |$ v5 s
要想使用DMP求欧拉角的代码,包含下面这几个文件即可,下面列出接口函数,到时候使用时直接使用接口函数即可。5 c" S* e+ L+ H" E. x6 {: n6 G

  x* y6 c$ J; q. v2 s- w- G$ ^' H  H
20200215175340295.png
* S) f: ^4 \, E. \; [% |% {3 n
& q9 ~' \. o" q3 o' p, B* d- S2 x2 Z
向DMP算法提供的接口宏定义! |% e- n* `3 q% C
只需要提供:对MPU6050的读写操作函数和延时函数即可; D( N4 q, J' s/ m6 u% B
  1. #define i2c_write   MPU_Write_Continue
    1 F* e* {: x) ~4 ?$ K3 _) B% g
  2. #define i2c_read    MPU_Read_Continue
    ( ~& B9 A! F" Z/ Z$ q% [% k
  3. #define delay_ms    delay_ms+ H/ g1 n; l$ W' a
复制代码

8 O9 {9 `6 E5 Z9 e. mDMP初始化) M: Z$ @/ N6 H: u7 z
  1. //mpu6050,dmp初始化7 R% ?' P# X, L
  2. //返回值:0,正常
    ( x5 J; s( |2 V
  3. //    其他,失败- _1 j; z7 Z- P& u! G0 u/ u0 L) ]
  4. uint8_t mpu_dmp_init(void)
    6 i$ m, S4 A7 V
  5. {6 L# O+ w/ o" \) V8 B) |
  6.         uint8_t res=0;- d  a! a, ~/ e8 D6 [0 Z
  7.         MPU_IIC_Init();         //初始化IIC总线
    1 `! d) I# d2 G- \6 h
  8.         if(mpu_init()==0)        //初始化MPU60507 v# R& k* g, t; T5 o( |% ~' r, r( Q
  9.         {         2 {) ]3 L( D3 ]9 j4 O) e% T% l# i' n
  10.                 res=mpu_set_sensors(INV_XYZ_GYRO|INV_XYZ_ACCEL);//设置所需要的传感器5 ~/ g6 e5 o3 k2 J
  11.                 if(res)return 1; - |+ I( \1 ~  T0 v/ E% Y  j+ i
  12.                 res=mpu_configure_fifo(INV_XYZ_GYRO|INV_XYZ_ACCEL);//设置FIFO
    + }3 c/ O/ c9 o8 _) T- Q% \
  13.                 if(res)return 2; 0 k$ Y' W2 X6 g( t& A
  14.                 res=mpu_set_sample_rate(DEFAULT_MPU_HZ);        //设置采样率
    , b: ~( }5 c- H4 Y
  15.                 if(res)return 3;
    * c# H# Q: C: L* a5 |& m8 @0 N
  16.                 res=dmp_load_motion_driver_firmware();                //加载dmp固件( h  C/ y7 \5 t! J& @/ n) F
  17.                 if(res)return 4; & h. G" U; f- X
  18.                 res=dmp_set_orientation(inv_orientation_matrix_to_scalar(gyro_orientation));//设置陀螺仪方向% S( J1 s6 Q' Q$ M& \
  19.                 if(res)return 5; % m# v6 s( W" j# A+ }
  20.                 res=dmp_enable_feature(DMP_FEATURE_6X_LP_QUAT|DMP_FEATURE_TAP|        //设置dmp功能
    # P7 r% {' P8 L6 J# `: G8 I
  21.                     DMP_FEATURE_ANDROID_ORIENT|DMP_FEATURE_SEND_RAW_ACCEL|DMP_FEATURE_SEND_CAL_GYRO|
    7 D8 O& M$ Q# [/ N6 A  {
  22.                     DMP_FEATURE_GYRO_CAL);
    $ z5 R2 H; B) F: X
  23.                 if(res)return 6; 4 r+ \6 g1 l( c  H, y
  24.                 res=dmp_set_fifo_rate(DEFAULT_MPU_HZ);        //设置DMP输出速率(最大不超过200Hz)' T0 M* `7 |9 x* Q1 [
  25.                 if(res)return 7;   6 V9 D. W+ j+ S1 @
  26.                 res=run_self_test();                //自检
    2 {9 Q, h# C% B  m5 F2 n8 w
  27.                 if(res)return 8;    # g3 V( k- f% ^  E; b& N
  28.                 res=mpu_set_dmp_state(1);        //使能DMP( i: b* A: _8 w2 K, K
  29.                 if(res)return 9;     
    ( |8 H/ Q2 C* [' ~! a4 _% p0 n
  30.         }else return 10;
    : b2 [8 \0 h1 _' u- @0 V
  31.         return 0;
    . }  M' ?' k1 i3 O& }  w% u
  32. }7 u+ b; t! ?) A; p6 w1 F. v6 ?
复制代码

2 W' e. T& V4 s获取欧拉角0 p& Q# i) W3 X  t6 Z
  1. //得到dmp处理后的数据(注意,本函数需要比较多堆栈,局部变量有点多)9 F0 G+ s8 D; t8 G8 z+ e- g3 g0 ~
  2. //pitch:俯仰角 精度:0.1°   范围:-90.0° <---> +90.0°
    ; \9 ~6 i" g1 f7 c
  3. //roll:横滚角  精度:0.1°   范围:-180.0°<---> +180.0°5 Q- {$ Q6 d/ M
  4. //yaw:航向角   精度:0.1°   范围:-180.0°<---> +180.0°
    / \6 U/ `  R. U# N
  5. //返回值:0,正常
    ( D) z7 v. X3 K
  6. //    其他,失败2 n; u& d, l1 C) Q$ X* Z; M
  7. uint8_t mpu_dmp_get_data(float *pitch,float *roll,float *yaw)
    9 K. k; k: q0 T% U0 {0 v
  8. {
    * f8 v* G2 p& _" }8 H0 a9 N; s
  9.         float q0=1.0f,q1=0.0f,q2=0.0f,q3=0.0f;, d  e; _# O) _7 E! n$ s1 u
  10.         unsigned long sensor_timestamp;) J4 H. ?" D! }( E+ u
  11.         short gyro[3], accel[3], sensors;" B9 v5 V  I1 W$ c6 F2 Y9 a' U
  12.         unsigned char more;
    , E, M. q# a: a. M( t2 \. _- D0 a% j
  13.         long quat[4]; 7 x0 b/ w& O$ \
  14.         if(dmp_read_fifo(gyro, accel, quat, &sensor_timestamp, &sensors,&more))return 1;         
    7 ~! m4 [- _0 L- L1 V  @' Q
  15.         /* Gyro and accel data are written to the FIFO by the DMP in chip frame and hardware units.
    7 q+ W$ Z; r& u" f8 P+ u) Z" Z
  16.          * This behavior is convenient because it keeps the gyro and accel outputs of dmp_read_fifo and mpu_read_fifo consistent.
    4 s0 H* J. O# F; `1 U
  17.         **/; m0 h0 \# E! ~; @, T
  18.         /*if (sensors & INV_XYZ_GYRO ): k: i2 A, U0 I$ L! F
  19.         send_packet(PACKET_TYPE_GYRO, gyro);
    ; E! v) o# A1 z( N5 |* E% x
  20.         if (sensors & INV_XYZ_ACCEL)
    2 q  }2 H- f. X7 l
  21.         send_packet(PACKET_TYPE_ACCEL, accel); */
    6 H5 g7 T( ?4 }# _$ O" z
  22.         /* Unlike gyro and accel, quaternions are written to the FIFO in the body frame, q30.
    % J) a% I% V! f" p
  23.          * The orientation is set by the scalar passed to dmp_set_orientation during initialization. / a6 Y+ s7 \0 j* L
  24.         **/# |- K0 m: |4 ^+ d3 H* [0 P
  25.         if(sensors&INV_WXYZ_QUAT) + D3 k+ `- y# y; i' f; r/ j
  26.         {; F; }: o0 x* P) f, }" P4 e; X% a0 t
  27.                 q0 = quat[0] / q30;        //q30格式转换为浮点数
    6 v  `% i/ U0 Z' h( ~8 w
  28.                 q1 = quat[1] / q30;
    1 i! _9 e8 T# O. x/ Z% @
  29.                 q2 = quat[2] / q30;
    / M, b# t% Z) U# K6 p
  30.                 q3 = quat[3] / q30; ) ], P9 ?$ v3 ~; ~4 K
  31.                 //计算得到俯仰角/横滚角/航向角
    $ Q/ A' w, P4 f# U
  32.                 *pitch = asin(-2 * q1 * q3 + 2 * q0* q2)* 57.3;        // pitch/ R0 N, z) @8 E% ]% ]8 o) [  }
  33.                 *roll  = atan2(2 * q2 * q3 + 2 * q0 * q1, -2 * q1 * q1 - 2 * q2* q2 + 1)* 57.3;        // roll. \# e0 [0 R$ F2 f" A
  34.                 *yaw   = atan2(2*(q1*q2 + q0*q3),q0*q0+q1*q1-q2*q2-q3*q3) * 57.3;        //yaw
    + S4 t9 j2 [, v
  35.         }else return 2;
    , ^/ Q% z+ d7 v8 t2 F
  36.         return 0;
    % W7 r# v/ s* t) l. n+ P
  37. }
    & t1 s4 m3 j$ L, p# V
  38. & X9 a: D# Y3 {( z" W
复制代码
) ~5 V$ N: A) O7 U
5.mian()函数
# E: w& U* _. P8 a/ p主函数中对MPU6050进行初始化后,对DMP也进行初始化,然后就可以直接使用mpu_dmp_get_data()获取欧拉角,还可以获取温度值。
& U8 [- k. a* E( s  @* k, s
  1. #include "stm32f10x.h"   
    9 v0 A  l4 Z0 ~7 p$ l
  2. #include "usart.h"
    1 y* p; `1 \8 Q
  3. #include "delay.h"6 m7 c  ]& l% R. y
  4. #include "mpu6050.h"
    : R7 q1 D$ L4 r2 }
  5. #include "inv_mpu.h"2 J( e' P* j3 b
  6. #include "inv_mpu_dmp_motion_driver.h"
    4 n0 @3 H; b( i4 _9 o# a
  7. & q2 Y$ ?. l6 w5 B. x/ @6 R$ G, w) h
  8. int main(void)# ]' H. m1 e0 x1 t$ I4 ]
  9. {! g4 T8 {+ t8 ]* ?9 t7 C
  10.         uint8_t x=0;! Q$ n, |. h4 H. P4 _, Y3 N6 G: y
  11.         float pitch,roll,yaw;                 //欧拉角
    ( u2 b9 @3 P- [, u
  12.         short aacx,aacy,aacz;                //加速度传感器原始数据9 z8 }1 H8 S$ ?. }3 _% d8 n) b
  13.         short gyrox,gyroy,gyroz;        //陀螺仪原始数据
    ; U/ E, C* X' ?) X+ R" d8 b: [
  14.         short temp;                                        //温度) q+ ]1 v( G7 q2 O- Q8 v& Z
  15.        
    - b* Z4 Z' |: Z3 _/ Q4 ?
  16.         NVIC_PriorityGroupConfig( 2 );
    : A2 R% J9 c7 v. K7 j
  17.         delay_init();
    ' ?7 u$ |0 g( F5 ^7 O* y: k$ z
  18.         USART1_Init(115200);        $ Q( A$ v' Q" s" A( B7 Y
  19.         printf("程序开始\n");: o/ X. U% n% {7 ~, I4 Z: l
  20.        
    5 g! H% _" i: h. y1 O! F1 h  z
  21.         if( MPU_Init()!=0 )
    ' G# t8 c& _3 K2 R" d4 ]# T: Y7 x* P
  22.         {
    3 \- v- B! W* y; r
  23.                 printf("MPU6050初始化错误!\n");
    / q+ n  q, g8 H. \+ J6 D
  24.                 return 0;
    : B5 j5 k4 Q. q" r( S
  25.         }
    1 m$ G, i3 B) P( X( d* C2 L0 o, m: Q
  26.                 ' M8 W6 G7 J( m- |( X4 O
  27.         if( mpu_dmp_init() )0 a, M$ s5 b, Y" U; [4 i4 h) F
  28.         {
    + x5 R. a+ w0 n1 h" ~! X" E; _
  29.                 printf("DMP初始化错误!\n");
    " ?2 q6 z( P4 b  M2 ]/ u  I8 I
  30.                 return 0;0 O2 E0 |; [# z( B/ F. B8 N
  31.         }
    ! ~( d0 ~' q# M9 |1 X
  32.         while(1)# Z0 z1 @9 p9 k$ l9 p
  33.         {
      Z* U- K& m+ i; O+ T
  34.                 if(mpu_dmp_get_data(&pitch,&roll,&yaw)==0)# v8 B& r& I8 B- t5 Q$ s
  35.                 { / O0 p8 y% O& a1 [
  36.                         temp=MPU_Get_Temperature();        //得到温度值7 ?* s0 y* M4 Y( s6 _) Q# Q
  37.                         MPU_Get_Accelerometer(&aacx,&aacy,&aacz);        //得到加速度传感器数据- }# P/ G" h3 V9 _8 s
  38.                         MPU_Get_Gyroscope(&gyrox,&gyroy,&gyroz);        //得到陀螺仪数据& w: }. U/ U/ S- H) h( h) o" M8 Y
  39.                 }
    , q) \# N( V# [3 [. J: y* e
  40.                 delay_ms(100);
    2 [- U5 A; M- u$ \' @
  41.                 printf("pitch:%02f  roll:%02f  yaw:%02f\n",pitch,roll,yaw);9 y" ]6 w: o! F- Q& S" R0 h
  42.         }
    ! [! _6 T5 t: T2 Y

  43. * |5 r8 B5 r* A9 r& C3 A
  44. }
    ) O2 A# _5 z  r6 K
复制代码
- e4 N3 P( S2 `) n: V: N
这就是我理解的MPU6050,后续做平衡小车的时候要读取欧拉角,先总结一下
8 p* K5 Z! T. s% z3 H————————————————1 N* e) B  k: F$ n: b
版权声明:Aspirant-GQ( a0 C# P$ Q8 w7 ^
如有侵权请联系删除
+ b5 d7 Y& @( ?1 |1 Y$ |
9 T5 R" r: c: m
1 ^% T* u7 B' H
赞 收藏 评论0 发布时间:2023-3-18 12:25

举报

0个回答

所属标签

相似技术帖

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版