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

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

[复制链接]
攻城狮Melo 发布时间:2023-3-18 12:25
一.MPU6050介绍* y7 O$ p8 u5 V$ }2 j
1.MPU6050与陀螺仪、加速度计的关系:
- G% z/ m0 \: f5 L
MPU6050是InvenSense公司推出的一款全球首款的整合性9轴运动处理传感器,其最大的特色就是:消除了陀螺仪和加速度计的误差,将陀螺仪和加速度计组合在一起,而且缩小了空间。6 {& N9 x' |& ?" [

* d& d# h0 b) l8 I, j# U9 u2.整体概括
: V* j* W3 t% A, C* m7 L4 j
MPU6050内部整合了三轴MEMS陀螺仪、三轴MEMS加速度计以及一个可扩展的数字运动处理器DMP,而且还可以连接一个第三方数字传感器(比如:磁力计),这样的话,就可以通过IIC接口输出一个9轴信号。! q6 M) B3 Z- A8 N
更加方便的是,有了DMP,可以结合InvenSense公司提供的运动处理资料库,实现姿态解算。通过自带的DMP,可以通过IIC接口输出9轴融合演算的数据,大大降低了运动处理运算对操作系统的负荷,同时也降低了开发难度。
! J7 a8 l, V: W) A6 D' |" h7 r" O, R$ v; E
特点
: v% f( B2 M' l: O  p3 n1 E4 w① 以数字形式输出 6 轴或 9 轴(需外接磁传感器)的旋转矩阵、四元数(quaternion)、欧
% h1 T1 o3 M' ^* U拉角格式(Euler Angle forma)的融合演算数据(需 DMP 支持)
* T) D* d. b9 ~. }8 s9 x② 具有 131 LSBs/° /sec 敏感度与全格感测范围为±250、±500、±1000 与±2000° /sec
& t, ]# @$ L- W7 m的 3 轴角速度感测器(陀螺仪)" K# B# u1 y3 i
③ 集成可程序控制,范围为±2g、±4g、±8g 和±16g 的 3 轴加速度传感器2 S% m6 B( b% w9 o
④ 移除加速器与陀螺仪轴间敏感度,降低设定给予的影响与感测器的飘移$ J  [9 }, _/ _! o- l1 y0 E: e% L
⑤ 自带数字运动处理(DMP: Digital Motion Processing)引擎可减少 MCU 复杂的融合演算8 A8 q  E& K7 I* b4 B) L  @, E
数据、感测器同步化、姿势感应等的负荷1 ~+ ^$ T) l; N( x9 f! U1 k" }
⑥ 内建运作时间偏差与磁力感测器校正演算技术,免除了客户须另外进行校正的需求/ e6 z/ P) E( B! t7 c+ S' z
⑦ 自带一个数字温度传感器  f6 `: s4 V7 u0 `/ N6 R; F
⑧ 带数字输入同步引脚(Sync pin)支持视频电子影相稳定技术与 GPS2 ~" [4 J8 g9 e0 ]& e
⑨ 可程序控制的中断(interrupt),支持姿势识别、摇摄、画面放大缩小、滚动、快速下降
# B( z# z, ?6 T+ a0 j# c2 z. C中断、 high-G 中断、零动作感应、触击感应、摇动感应功能8 K8 N8 w( t$ `0 z
⑩ VDD 供电电压为 2.5V±5%、 3.0V±5%、 3.3V±5%; VLOGIC 可低至 1.8V± 5%
/ M3 g) i4 t- r- i⑪ 陀螺仪工作电流: 5mA,陀螺仪待机电流: 5uA; 加速器工作电流: 500uA,加速器省: n2 O# a7 p/ H) {9 J- O6 H
电模式电流: 40uA@10Hz
0 H* N; {4 E3 R9 P⑫ 自带 1024 字节 FIFO,有助于降低系统功耗' l. n  ~" \9 h3 w7 v# g$ j
⑬ 高达 400Khz 的 IIC 通信接口+ V  U; C, P2 a3 Y
⑭ 超小封装尺寸: 4x4x0.9mm(QFN)
3 J* ?* y1 A% e4 P$ g1 [
) ]* _3 ~3 G% m3 \
其检测轴如图所示:
  f0 e' T! D& S( ^; u* W7 H2 H
  B6 u4 [8 I1 F4 e1 p6 P
20200215154932517.png
' @7 r+ w1 G  }+ x# }4 X& V/ \) U; C' v2 j* R- Q! G
- p# B; s% y  B3 d. u8 U2 G  _
3.引脚说明* c0 G) ~- F, O+ U" w/ g
5 C! T* B* X& J( M0 M$ `% c
20200215160046383.jpg : c" f$ s6 ~- {- @
% M6 V7 p+ g' b' Z$ m
如图,MPU6050一共有8个引脚,实际上输出六轴数据时,只用了5个:VCC、GND、SCL、SDA、AD0。下面介绍一下引脚:. W0 I. A" i+ p& m
VCC:供电,3.3V即可
, N0 F7 W# K( K" ^9 LGND:接地
: ?1 q. V- z% e, @SCL:连接MCU的IIC时钟接口7 ~! h/ c6 P* D. r" u% p+ y
SAD:连接MCU的IIC数据接口' ^. f# d- \! @/ U! |% c- r3 y
XCL:连接外部设备的IIC时钟接口: m5 K! z# P( p2 s/ C
XAD:连接外部设备的IIC数据接口
( U- X8 l) }5 G7 v1 _AD0:地址控制引脚(控制地址的最低位)9 P7 |6 w2 b# r. d8 B
INT:中断触发接口(不用)
" x% X- h" Q2 M, \8 f3 y; _
XCL、XDA只有在连接外部设备(比如磁力计的时候才用),AD0用来控制MPU6050的地址,如果AD0低电平,地址就是0X68;如果AD0高电平,地址就是0X69。5 n- W/ T- {. U8 W

! R( x1 M1 c- ?. b- \1 O3 B+ i4.基本配置及相关寄存器
+ f  T3 s( m8 X9 x; tMCU与MPU6050的通信是建立在IIC通信机制上的,在IIC的基础上,可以实现对MPU6050的寄存器的操作,而MPU6050的运作就是过对寄存器进行读写。所以,了解相关的寄存器和对寄存器的操作是很有必要的。MPU6050的寄存器相关资料都可以在数据手册中查到,下面介绍一下几个重要的寄存器:
* i; W; ^" W" Q# z: d4 {
( J  Z6 Q( g7 L' k电源管理寄存器1
( I7 v: C* l/ Q6 Y地址:0X68
' i/ f8 N& Y6 J7 i6 @9 e6 |; \, a& p2 N8 s

: z8 H: J2 A$ Y 20200215163434244.png
0 \9 L  S0 K8 x. W( u6 D: l. S$ d+ W+ D0 l' }* _6 l& j
主要位的功能:
7 ~0 c0 F2 g/ a% _# b  m2 H3 vDEVICE_RESET:控制复位,1表示复位,复位后会自动清零;6 Q6 M; Q5 m2 x" [' g
SLEEP:控制MPU6050工作模式,1表示睡眠模式,0表示正常工作模式,复位后改位为1,要手动将改位清零;
4 G5 y# ?, i% X" x. V) q, hTEMP_DIS:使能温度传感器位,0代表使能;" s$ a" \" U& E9 s
CLKSEL[2:0]:选择系统时钟源,一般采用PLL_X轴陀螺作为参考,具体的时钟源选择及相应位的值如图:
5 u. w: ~  ~0 _  ]+ I
( H/ H( U* [8 E4 B8 j% W/ Y

2 S' c( a& E$ \5 E6 _ 20200215164457650.png 2 G3 x+ w8 y0 j
7 _5 g* L, M1 b) ~/ z' V
陀螺仪配置寄存器& N  l& E& c; [8 w% F
地址:0X1B" k# J% s# ]3 M; }1 K9 t
5 C+ X9 V/ i2 G3 R
20200215164757727.png
' I" }: P+ |; d' a

# _+ g, P; D& U' @6 I! x: X主要位的功能:" [7 F1 A% ~' T5 @
FS_SEL[1:0]:设置陀螺仪满量程范围:为0代表±250° /S、为1代表±500° /S、为2代表±1000° /S为3代表±2000° /S;
) K6 V/ Y$ L5 J8 c8 a( S9 X/ Y, W. C4 m' i
陀螺仪的分辨率是16位,所以在最大量程下灵敏度为: 65536/4000=16.4LSB/(° /S)。
+ n0 d) h, n$ B+ p) D6 w1 L
% b) V/ n; @+ l1 J2 G
加速度计配置寄存器
8 G/ p0 m6 {0 l$ Q地址:0X1C" T; g$ S. ], d2 @# P/ l3 [% z
9 b% d. e5 U( G
20200215165411152.png 9 a, Z8 S  C  \  R7 T) Z
  _# j/ t7 b' {, X9 ^7 f% V
主要位的功能:
" n# }" ~* L8 v& Q/ n6 r6 eAFS_SEL[1:0]:设置加速度计满量程范围:为 0代表±2g、为1代表±4g、为 2代表±8g、为 3代表±16g;, M3 q* B! c- Z8 b8 v

6 A- l' F5 k# M6 _, q* O0 h& P
FIFO使能寄存器: o4 ^) d2 e8 c0 T2 ?; q6 Q) @6 ~1 g( j3 R
地址:0X23
; f+ r7 Z  Q* V* N* m) M7 @
0 j/ g- f( w7 u2 D
20200215165816272.png
6 C: J8 n/ u* M( P

" ^, F( C. M/ p" Q; }% b用来控制FIFO功能,相应位对应着相应的传感器FIFO功能,为0代表禁止,为1代表使能。注意:加速度传感器的三个轴的FIFO功能由一个位ACCEL_FIFO_EN控制。在简单读取传感器数据的情况下可以不使用FIFO。, q1 f- N1 b, r4 i
: n0 |: W) ~4 B. {
陀螺仪采样率分频寄存器4 S' ]( U1 f& {
地址:0X19: l% C. G' V3 X0 _6 C

! |' y, ?3 C  A% T* r. u
20200215170242372.png
6 l- O/ c. k7 L3 m
8 n  a7 `. b4 W& ]# x7 ?; u
改寄存器用来设置MPU6050陀螺仪的采样频率,与之相关的是陀螺仪的输出频率,俩者关系是:采样频率 = 陀螺仪输出频率 / (1+SMPLRT_DIV)8 ~  `( K+ x; ~: |+ h% X; A. O7 u  E
陀螺仪输出频率与数字低通滤波器(DLPF)有关,DLPF滤波频率一般设置为采样率的一半。
8 x4 a; x* @# E- l4 @8 K0 W; U

8 d6 C0 F( Y  b/ w! S! \; H' T温度传感器寄存器
$ ~' L" t+ q% ]$ V6 ~- ]  J地址:高八位0X41、低八位0X42
0 V5 J% b; D6 n) K& D2 _直接通过读取寄存器中的值来得到温度数据,温度换算公式为:
7 d1 `( P) V& P" g2 ~+ }Temperature = 36.53 + regval/340
" c6 c) z& ?* N. U2 a

- @! e+ n2 N7 C. Y6 j; a( E& Y* `二.代码详解% r6 J# c( }, @5 f% H6 a
1.框架
+ y. x" i7 V: h" d- q4 n6 D! {8 M
我是用STM32驱动MPU6050,MPU6050输出原始的六轴数据,经过DMP处理(有库)得到四元数,再由四元数算出欧拉角:yaw、roll、pitch。由串口打印在电脑屏幕上。2 J! e. E- g2 p6 s( _( E, X8 o* s
首先,要做底层的IIC驱动,用来和MPU6050建立通信,我在mpu_iic.c中实现了;
7 m+ F' X$ u4 y9 t4 T8 h然后,有了底层的驱动,就要写一些函数来与MPU6050交流了(通过读写寄存器),还可以写入命令、配置MPU6050、读取原始数据等等,这些操作我都写在mpu6050.c中,当然在mpu6050.h头文件中还包含了MPU各寄存器地址和相关指令。, K" T: J6 \6 u
通过mpu6050.c的实现,就可以读出原始六轴数据,下一步就是通过DMP将原始数据转换为四元数,这一步的DMP算法我水平有限,只能移植InvenSense公司提供的例程。关于移植DMP算法,由于DMP算法本质也是对MPU6050的操作,所以我们只需要向移植过来的算法提供:对MPU6050寄存器执行读和写的函数接口即可,最后通过移植过来的函数直接读出四元数!
3 @% L9 ^1 R8 y& k然后,就是将四元数转换为欧拉角了,这个比较简单,一个函数就可以实现。$ U" _" v0 ^0 K9 ^& @: C' ^1 k/ l
最后,打印串口到屏幕。
4 G& v6 w6 S" n+ ?$ \+ o1 E& }9 r/ B* S. r
下面给出各函数文件
! }; D: [6 `: f' L/ N! n
0 L; h( |5 }/ c6 o: _
2.mpu_iic.c/mpu_iic.h3 D* o3 ~2 _* a& z+ M
mpu_iic.h
! ^. m6 @# @( J9 F! W/ e+ B2 m主要是宏定义对引脚电平的操作和进行函数声明。3 {4 p$ z$ {8 W3 ?
  1. #ifndef __MPU_IIC_H8 B. Z3 A8 b% @" M* X3 Q" c
  2. #define __MPU_IIC_H
    2 L1 P! M0 N" Y( i# j3 d! b

  3. - ]0 g8 n( q: N; K! \% @' ]' b: t
  4. #include "stm32f10x.h", T& F' d/ a( e! ?4 \6 j4 R+ d0 d
  5. #include "delay.h"
    , T0 o8 {" V4 ?( t& F6 }4 d

  6. & p# f; n+ W6 V# @- C" j
  7. /* 宏定义引脚电平操作函数 */4 c$ ~% {: e5 A0 B; L/ v4 g( l
  8. #define MPU_SDA_IN()  {GPIOB->CRH&=0XFFFF0FFF;GPIOB->CRH|=8<<12;}
    5 S- C, @* A8 g- y( l' w% H
  9. #define MPU_SDA_OUT() {GPIOB->CRH&=0XFFFF0FFF;GPIOB->CRH|=3<<12;}  $ E& r) W/ c! w7 y2 H& g& I
  10. ; G- K5 J  F+ }: c9 i
  11. ( u0 G: V1 D. I* G! m2 J6 s2 ]
  12. #define MPU_IIC_SDA_1() GPIO_SetBits( GPIOB, GPIO_Pin_11 )
    ! h5 h! W: ]( l2 Q! V; x0 A
  13. #define MPU_IIC_SDA_0() GPIO_ResetBits( GPIOB, GPIO_Pin_11 )
    $ Z: H# Q9 [  E

  14. 3 i# X" e' b' _2 P7 k4 H
  15. #define MPU_IIC_SCL_1() GPIO_SetBits( GPIOB, GPIO_Pin_10 )
    9 h6 B' R& U4 O" B
  16. #define MPU_IIC_SCL_0() GPIO_ResetBits( GPIOB, GPIO_Pin_10 )
    ; ~. c" N# W9 u) p+ s& w
  17. " S7 R* E* G- `
  18. #define MPU_IIC_AD0_1() GPIO_SetBits( GPIOA, GPIO_Pin_15 ), f( e$ F/ U- V: U* H0 a1 N) E
  19. #define MPU_IIC_AD0_0() GPIO_ResetBits( GPIOA, GPIO_Pin_15 )
    , W& h7 B1 [3 I( P, c' W

  20. , ?( k1 f8 @: X% a. V, Z
  21. #define MPU_IIC_SDA_READ() GPIO_ReadInputDataBit( GPIOB, GPIO_Pin_11 )0 P  G7 p4 `) c: `) R3 _! y

  22. . {7 c& T4 f0 S( F" q4 h
  23. #define MPU_IIC_Delay() delay_us(2)3 c( N! W( f  @2 ]3 t
  24. 5 V- k& d( K  V& ?+ e2 ?
  25. /* 函数声明 */: m; G8 p3 b; Z; b9 b' l& s
  26. void MPU_IIC_Init( void );
    ; W2 I. w# L8 r9 g
  27. void MPU_IIC_Start( void );8 u) R" W2 ?, |3 o/ B( S
  28. void MPU_IIC_Stop( void );
    + a$ N' [8 g" ^3 E
  29. uint8_t MPU_IIC_Wait_Ack( void );9 a7 y7 h6 s+ x0 x: U0 P$ m
  30. void MPU_IIC_Ack( void );2 i8 [7 k5 E& [% L4 s4 ~
  31. void MPU_IIC_NAck( void );1 F. k% ^' |+ @
  32. void MPU_IIC_Send_Byte( uint8_t data );
    / C! G# g8 R/ k  W
  33. uint8_t MPU_IIC_Read_Byte( uint8_t ack );" H/ J5 Y. _7 R7 p$ s$ q

  34. ' {" T, p5 ?3 x
  35. #endif9 b9 i2 i1 ^% l% q9 q) K

  36. 1 D8 m$ u+ ]2 ?" g7 c
复制代码
- r; m8 e/ M( U- z9 y/ k
mpu_iic.c+ q: @7 c9 a& d! W! f7 ?3 p/ l" |( |
通过软件模拟IIC的代码,没什么好说的。
# o  L4 Z& p; l. G% Z- @% n
  1. #include "mpu_iic.h"
    & w' H3 g& W; w! D( p/ V9 `: c/ a
  2. #include "usart.h"7 R& s: \6 @, I" Q. G/ k
  3. 7 o6 o1 E5 t5 Y! i+ `- M0 W+ c1 Z
  4. /*
    $ N" f# }: C* d: h' p& a
  5. IIC接口引脚配置- u$ _" }5 w0 M7 k' i; d( T
  6. SDA:PB11% p6 F* b) l6 {5 G( D
  7. SCL:PB106 B( P1 R4 C5 z6 G/ ]2 P+ }. t& Q
  8. AD0:PB28 u. r% U8 l3 N4 k
  9. */  u3 x, i9 q* {! h
  10. void MPU_IIC_Init( void )( e& n( u& w, Z0 }: E2 w; R
  11. {3 B5 @4 `. t# C- o
  12.         GPIO_InitTypeDef  GPIO_InitStruct;2 y7 O3 P/ i* V
  13.         6 S" ~5 d2 z6 v; \' N+ z; f
  14.         RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB, ENABLE );
    ) N9 I# e) L  P+ P; B# C
  15.        
    " I/ }4 p/ h0 i
  16.         GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;/ e7 W* Q" z6 ^7 c# `# P0 J8 R* _) M
  17.         GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;7 D! \' V5 ^) Z2 F: P% |7 r
  18.         GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10|GPIO_Pin_11;6 l1 U$ n' U# D4 b# R* `' K5 L5 V3 G
  19.         GPIO_Init( GPIOB, &GPIO_InitStruct );
    $ r' [! b- Y; }+ |/ R
  20.        
    " L: Q% A3 p" ]' D& R& u$ O
  21.         MPU_IIC_SDA_1();* f/ z( W7 Q/ v# ^$ p* U4 P
  22.         MPU_IIC_SCL_1();
    1 v, @7 E. W3 v& G
  23. 3 I! L9 Y: W& H: w
  24. }
    " x+ v6 ^! S( \9 v7 y( B1 L
  25. $ g3 f* G1 r( v5 _" E; u) x1 e: ~

  26. * t  b) d5 ~0 k
  27. void MPU_IIC_Start( void )) B$ x; I- G6 p8 y2 ^1 w2 D& Y
  28. {6 P8 {9 ?7 W* `7 t" T
  29.         MPU_SDA_OUT();
    . F' P& C8 e5 ~5 e- N
  30.         ) s  w3 w, n7 i; R. }
  31.         MPU_IIC_SDA_1();
    " |+ |) r4 j% h1 d! Z
  32.         MPU_IIC_SCL_1();
    2 A. E" ?9 E4 N5 y' V$ q
  33.         delay_us(2);
      M) W% i' S6 ~  b
  34.         MPU_IIC_SDA_0();' O& Q( F$ s7 `/ E3 l5 J7 O
  35.         delay_us(2);
    5 a5 X* Q. E% e- T9 _
  36.         MPU_IIC_SCL_0();
    2 x9 U' S( H2 D7 s' X( M3 \
  37. }0 H9 W  L8 m; i
  38. + Q* v+ z6 q% Q% ]5 U+ m
  39. void MPU_IIC_Stop( void )
    $ ~! z; k( g  D2 U
  40. {/ U  }" F" R' S# b& G, F
  41.         MPU_SDA_OUT();7 b" f5 }7 f! k1 D: K6 l& Z' m/ b. o
  42.         + k" f9 ~: k6 t$ h/ w+ K% N
  43.         MPU_IIC_SDA_0();
    " W4 [3 R0 i& D6 g" x, G/ Z
  44.         MPU_IIC_SCL_1();; K! s# I1 s5 R3 |& b
  45.         delay_us(2);
    ( U# }" x2 ]2 L9 c3 y4 G% K
  46.         MPU_IIC_SDA_1();
    5 g  x$ y( B. o+ f
  47.         MPU_IIC_SCL_1();
    4 E" I7 j- R9 [0 r3 h
  48.         delay_us(2);
    2 L2 I8 V% L: ^# H! _
  49.         : b* p8 f1 w4 X) B' t
  50. }2 ^+ E) J/ [8 C+ @; \! e! k

  51. . B: P. R! s) _% ?
  52. /* 由从设备在SCL为高电平的时候拉低SDA作为应答 . x" U0 r6 j+ W) M, K& A# x
  53. 返回值:1:未应答# \9 v( M8 Y- U2 @) @
  54.         0:已应答7 Q8 W3 v! j6 c: W5 u4 O; x
  55. */3 [! I4 }6 ~# m* L
  56. uint8_t MPU_IIC_Wait_Ack( void )6 N, V, {# c$ D8 J% h
  57. {. i, n; l( \, `) G
  58.         uint8_t count;  ^2 w/ ]+ Y* ^6 E
  59.         MPU_SDA_IN();7 X# m+ S# N/ f
  60.        
    . t. O2 O: p2 k" G7 b9 o: W
  61.         MPU_IIC_SCL_1();; K+ P7 N, H9 c5 t7 o; F# C- R
  62.         delay_us(2);
    4 h4 G- b& \1 ]4 q3 t
  63.         MPU_IIC_SDA_1();
    4 x% D$ }; Q' X/ B& U
  64.         delay_us(2);( H; n8 w$ R( O1 h
  65.         ) T9 N6 b+ u! z- ~& C. c
  66.         while( MPU_IIC_SDA_READ()==1 )
    % K+ Q' M( Z7 Z! n0 m4 P
  67.         {
    # k, i: s, {' c+ p1 y) M3 O
  68.                 count++;
    - M( h: v; H* F' I
  69.                 if( count>250 )
    4 w0 B3 w$ V: |! b* G
  70.                 {, p, D0 g. {) `: V) Y1 ^+ }/ O. T, N
  71.                         MPU_IIC_Stop();
    : \1 F8 Q% N! h: G/ X
  72.                         return 1;% u1 }  s4 h, s: }% O5 k9 U3 f: u
  73.                 }
    2 b$ H2 E! T; M. Q6 G: d! I
  74.         }          o. o5 ~: v, i) p) S
  75.         MPU_IIC_SCL_0();
    1 F" n. J+ c! N9 P) [
  76.         return 0;, O4 C& a/ r( l2 ]0 r3 k
  77. }( r$ r7 {3 U$ a& q) k. i6 Q( @

  78. 2 ]) A3 Q- d1 r4 x1 X; g
  79. - i: x0 D+ I' Z( j4 R8 U+ \
  80. void MPU_IIC_Ack( void )
    . y' P8 w% v% O+ @. U
  81. {7 C* V3 A/ p3 ?. N. ~4 {1 e
  82.         & F1 y! ]$ x  {! h
  83.         MPU_IIC_SCL_0();
    / B. f& [' L1 J2 d* S
  84.         MPU_SDA_OUT();
    % C* ]0 |1 y2 c; [. \8 W
  85.         MPU_IIC_SDA_0();
    7 r; s/ b" h0 l- S$ d
  86.         delay_us(2);
    9 p. Z9 N  p$ f! q7 _4 ]
  87.         MPU_IIC_SCL_1();* c& n6 m4 z$ c1 g* w* v
  88.         delay_us(2);& N* I# A$ A+ _: v' _
  89.         MPU_IIC_SCL_0();
    9 ~9 U/ Y* }* ~6 J" B
  90.        
    ! w% o. U  P8 z' r3 n1 I* D* y. {) z
  91. }
    6 U5 K5 R$ n! e' o0 c
  92. / I/ d# c* C/ q' z
  93. - y! X/ O- @" p
  94. void MPU_IIC_NAck( void )
    * D+ s' ~$ g6 K, S
  95. {' x* `, a3 \% {) ?4 M
  96.         3 _, p  i& z& u
  97.        
    7 L+ S( p& z9 g' l
  98.         MPU_IIC_SCL_0();( F/ {- y, ]0 T, Y8 x
  99.         MPU_SDA_OUT();
    2 N7 c) G' ]9 P4 {! c0 O! }
  100.         MPU_IIC_SDA_1();
    , q4 B+ \% u' d9 {4 K& z
  101.         delay_us(2);( P4 {3 N7 L4 ^; v$ T
  102.         MPU_IIC_SCL_1();7 v& S8 A8 H5 H* Y0 j6 L
  103.         delay_us(2);9 T3 U' V% }$ u" Y
  104.         MPU_IIC_SCL_0();+ O  U! f1 G) b! {% k# P
  105. }
    & q9 m# f- ]! A' g" Q; t
  106. 8 w% e) T5 I8 g6 e0 q, ^

  107.   a8 r" @$ Q- P' T/ ]' f
  108. /* 发送一个字节数据,高位先行 */& K) Q) s0 l( [/ K  K" Y' {
  109. void MPU_IIC_Send_Byte( uint8_t data )
    + J) n( z# z( y4 U- R" v3 J+ p
  110. {
    ! c3 q) k* p+ D% u& L
  111.         uint8_t t;' f8 S& Y. i4 Z! s/ v
  112.         MPU_SDA_OUT();2 K4 O3 M8 Y, |
  113.           e9 U* o( x0 d! H
  114.         MPU_IIC_SCL_0();! C% \- S% e  @& s9 B2 y2 Q
  115.         for( t=0;t<8;t++ )
    ( h* r/ d( ^0 O
  116.         {: s! y0 ^$ D  l7 A
  117.                 if( ((data&0x80)>>7)==1 ), i7 s9 d* X8 k3 z
  118.                         MPU_IIC_SDA_1();
    4 I( [; N, S0 m6 z
  119.                 else. O9 Y3 u0 @, m  p8 Y( Y
  120.                         MPU_IIC_SDA_0();
    ' b5 X- j. p# S& J
  121.                 data<<=1;7 y! j: M! V; F4 u1 B
  122.                 MPU_IIC_SCL_1();
    - W( U; D$ U+ ^# C, B
  123.                 delay_us(2);! ]# B; M. q; t
  124.                 MPU_IIC_SCL_0();
    ( e9 d) Y/ i, p* H' w, Q6 N
  125.                 delay_us(2);
    * D1 A7 a. c2 B8 e: _
  126.         }, @3 z! d6 W# l5 g' S+ E! ^
  127. }6 Z- O/ A/ V, |& i* A$ G

  128. - P, c0 h7 o! A+ F0 d

  129. & ]; ~7 @. j  D( z" E
  130. /* 读取一个字节,ack=1时,读取完成后主机发送应答 */" ?1 L: I: D0 ?! q& [: E8 y
  131. uint8_t MPU_IIC_Read_Byte( uint8_t ack )
    0 O) q; X9 F: @; @
  132. {
    : a1 s; j. c3 u5 @8 G! B
  133.         uint8_t t,data=0;8 z9 z: d: l. _6 h/ H/ V2 o! Q
  134.         MPU_SDA_IN();
    & o& k) m$ ~8 I7 u8 b
  135.         for( t=0;t<8;t++ )  u& L. {6 D: F6 I: B
  136.         {: Z  c& V% @0 J4 r9 |, X
  137.                 MPU_IIC_SCL_0();+ _2 `# P8 A% ?3 z  }; Q, e7 [
  138.                 delay_us(2);//等待SDA的变化
    ) O! J, H) X7 t9 g. ?
  139.                 MPU_IIC_SCL_1();
      }( M# w5 F/ c3 I
  140.                
    1 D9 x3 e' t" z  P& Q, I9 j# t3 m
  141.                 data<<=1;//必须在读取前面,因为之后一位读取后就不再移位
    : u9 n; ?- F+ _; X
  142.                 if( MPU_IIC_SDA_READ()==1 )9 P6 F. F. @4 c4 I1 |
  143.                         data++;# b  V; J. ~+ Z/ r3 Q% r( \" [) G
  144.                 . u, \' G( [2 M- C6 T7 p, b
  145.                 delay_us(2);//等待SDA的变化& v0 I' t$ b6 y2 h8 U7 p; u
  146.                
    ( [/ t+ R8 t2 _# U" M
  147.         }) \* H, Y2 ~* v

  148. 1 {) ?0 I, {# w! j( e! n. W; o- F, |% w
  149.         if( !ack )* ?# m$ }% o( p2 q: W9 |; Q' A5 N
  150.                 MPU_IIC_NAck();//发送nACK
    ) ]6 Z/ G( a. k( M3 v
  151.     else0 _+ i8 q' v+ e4 s9 \' b
  152.         MPU_IIC_Ack(); //发送ACK
    ( R% H! Q) h( L
  153.         return data;
    ) Y0 n5 D: R; ?/ w( I) m
  154. }- ?4 ^3 D5 a8 f- E

  155. ! P. `3 Z) E! A3 k

  156. - z- G$ U. Q) h
复制代码

- \: y+ S7 \) w# y" D+ G" |# T3.mpu6050.c/mpu6050.h) b, Z8 q7 j# K, |4 r2 s
mpu6050.h2 _1 f2 u- m) X# o+ Y; ]
主要是定义MPU相关寄存器的地址,和进行函数声明。$ t0 U! f) {' a1 q! w: p$ x; X5 Z% T
  1. #ifndef __MPU6050_H
    . j4 @1 a5 |/ Y2 j
  2. #define __MPU6050_H
    ! M# |* \( P! t2 n( Q& W. [: a" K" P

  3. 3 p% y) C5 g3 q, @7 |
  4. #include "stm32f10x.h"% C* K2 h& q* T  `. G8 K7 b
  5. #include "mpu_iic.h"4 e# f4 I0 [6 Y. n! ?, h& N% P

  6. ; t0 H6 ~4 y8 v) r* i$ h
  7. 8 x8 z4 d' C& b: w
  8. /* AD0接地,MPU6050的IIC地址为0x68   接3.3V就为0x69*/
    + i8 a) Z' @+ f+ t: \6 n- A' L
  9. #define MPU_ADDR                                0X68
    7 i" B" R) j  k& }- r3 f, C; e

  10. 4 t8 j) \$ |% S# m; M& c
  11. /************** MPU6050相关寄存器地址 *********************/% i: ~' h+ V* F
  12. #define MPU_ACCEL_OFFS_REG                0X06        //accel_offs寄存器,可读取版本号,寄存器手册未提到4 z1 Z* u: q9 i% ?1 b- f) Q
  13. #define MPU_PROD_ID_REG                        0X0C        //prod id寄存器,在寄存器手册未提到
    7 U4 S- \$ A, j; J' k/ A1 D
  14. #define MPU_SELF_TESTX_REG                0X0D        //自检寄存器X
    " i/ P; \6 o! {" S- J
  15. #define MPU_SELF_TESTY_REG                0X0E        //自检寄存器Y* E  R/ C& h8 a7 C* {! A. J
  16. #define MPU_SELF_TESTZ_REG                0X0F        //自检寄存器Z
    0 T- r" [8 r( r0 A* |
  17. #define MPU_SELF_TESTA_REG                0X10        //自检寄存器A) ]; f: r& {% |5 C* R
  18. #define MPU_SAMPLE_RATE_REG                0X19        //采样频率分频器
    ' M$ r# n- b& y" V+ t$ u; `
  19. #define MPU_CFG_REG                                0X1A        //配置寄存器! c( I: e: A/ U
  20. #define MPU_GYRO_CFG_REG                0X1B        //陀螺仪配置寄存器2 b. V  [8 E0 u4 R, a7 e
  21. #define MPU_ACCEL_CFG_REG                0X1C        //加速度计配置寄存器
    ! o. A# }9 n: @3 B4 R/ ?4 u
  22. #define MPU_MOTION_DET_REG                0X1F        //运动检测阀值设置寄存器. W% s9 _  e2 f7 w: y, U/ Z6 N
  23. #define MPU_FIFO_EN_REG                        0X23        //FIFO使能寄存器
    + l! Y6 u+ l5 A! k6 e5 n/ m
  24. #define MPU_I2CMST_CTRL_REG                0X24        //IIC主机控制寄存器
      j) m! X" e3 b8 i
  25. #define MPU_I2CSLV0_ADDR_REG        0X25        //IIC从机0器件地址寄存器
    . i8 p( h0 j# a; T4 a' P
  26. #define MPU_I2CSLV0_REG                        0X26        //IIC从机0数据地址寄存器
      j0 ]2 E" b' e  y
  27. #define MPU_I2CSLV0_CTRL_REG        0X27        //IIC从机0控制寄存器" C/ J' N6 |& D' g  b3 Q
  28. #define MPU_I2CSLV1_ADDR_REG        0X28        //IIC从机1器件地址寄存器* Y, e- a5 r" y# e$ i" T3 V8 M
  29. #define MPU_I2CSLV1_REG                        0X29        //IIC从机1数据地址寄存器
    . U# @( [( X. l# j) E. c
  30. #define MPU_I2CSLV1_CTRL_REG        0X2A        //IIC从机1控制寄存器
    , t+ N7 J0 a5 L* ?/ `. v
  31. #define MPU_I2CSLV2_ADDR_REG        0X2B        //IIC从机2器件地址寄存器
    9 I. U" Z" u. Q
  32. #define MPU_I2CSLV2_REG                        0X2C        //IIC从机2数据地址寄存器
    / H+ N1 g/ P- R, C8 @1 H& K8 x0 b
  33. #define MPU_I2CSLV2_CTRL_REG        0X2D        //IIC从机2控制寄存器" }5 V1 ]8 |: Z
  34. #define MPU_I2CSLV3_ADDR_REG        0X2E        //IIC从机3器件地址寄存器
    - D  ]5 c$ F* l. D2 S
  35. #define MPU_I2CSLV3_REG                        0X2F        //IIC从机3数据地址寄存器, ?3 D! P2 p8 h( K
  36. #define MPU_I2CSLV3_CTRL_REG        0X30        //IIC从机3控制寄存器
    ( t0 ^4 ]" h" `$ ~1 j! [9 |6 {
  37. #define MPU_I2CSLV4_ADDR_REG        0X31        //IIC从机4器件地址寄存器- g/ N6 ~' C6 V) q1 X  p6 o9 Y
  38. #define MPU_I2CSLV4_REG                        0X32        //IIC从机4数据地址寄存器/ m, B5 g# b# y# V
  39. #define MPU_I2CSLV4_DO_REG                0X33        //IIC从机4写数据寄存器
    . Z7 |0 ~2 x5 T7 S2 U
  40. #define MPU_I2CSLV4_CTRL_REG        0X34        //IIC从机4控制寄存器6 l/ F4 [; E: |
  41. #define MPU_I2CSLV4_DI_REG                0X35        //IIC从机4读数据寄存器
    % M! r7 N$ c6 o6 ^. z/ l% v3 h

  42. + x! q; m9 s2 E' {) i5 ?* {
  43. #define MPU_I2CMST_STA_REG                0X36        //IIC主机状态寄存器$ \" @: \) X2 |$ E8 y* [; l
  44. #define MPU_INTBP_CFG_REG                0X37        //中断/旁路设置寄存器( m- w) h( Q! G0 q  P) w8 N
  45. #define MPU_INT_EN_REG                        0X38        //中断使能寄存器
    ) F5 U; q: M+ T' z1 A  U
  46. #define MPU_INT_STA_REG                        0X3A        //中断状态寄存器
    ) i, T2 E- A8 Q7 D

  47. * V0 E; e* T. [4 ~. b7 f
  48. #define MPU_ACCEL_XOUTH_REG                0X3B        //加速度值,X轴高8位寄存器
    2 [8 R) [, a% f
  49. #define MPU_ACCEL_XOUTL_REG                0X3C        //加速度值,X轴低8位寄存器
    1 q$ [2 F' S. O: |4 |' s
  50. #define MPU_ACCEL_YOUTH_REG                0X3D        //加速度值,Y轴高8位寄存器8 r# ]9 n$ C  P5 p8 D) O" f
  51. #define MPU_ACCEL_YOUTL_REG                0X3E        //加速度值,Y轴低8位寄存器0 M1 {' ~8 ]! t4 U' s3 ?$ n  _: R
  52. #define MPU_ACCEL_ZOUTH_REG                0X3F        //加速度值,Z轴高8位寄存器
    6 K+ D+ j; O- O
  53. #define MPU_ACCEL_ZOUTL_REG                0X40        //加速度值,Z轴低8位寄存器
    6 i( _! L. c9 Z8 _, W( V
  54.   v- k* A* g# Z+ C# |2 G, l
  55. #define MPU_TEMP_OUTH_REG                0X41        //温度值高八位寄存器: H; E. _* F: L/ u5 N
  56. #define MPU_TEMP_OUTL_REG                0X42        //温度值低8位寄存器% |0 R4 S. O/ G: n# P
  57. + r$ ]+ v7 \- u4 I: W& p+ W$ q
  58. #define MPU_GYRO_XOUTH_REG                0X43        //陀螺仪值,X轴高8位寄存器
    $ b! t& v4 Z; f+ k; v: r
  59. #define MPU_GYRO_XOUTL_REG                0X44        //陀螺仪值,X轴低8位寄存器& f% D" [  c8 e$ T' {
  60. #define MPU_GYRO_YOUTH_REG                0X45        //陀螺仪值,Y轴高8位寄存器, ]; @: m3 \1 a$ z4 ~- P) E$ u* I
  61. #define MPU_GYRO_YOUTL_REG                0X46        //陀螺仪值,Y轴低8位寄存器. W- h4 }" l$ f8 W2 U
  62. #define MPU_GYRO_ZOUTH_REG                0X47        //陀螺仪值,Z轴高8位寄存器
    " Z" H  f8 B/ L
  63. #define MPU_GYRO_ZOUTL_REG                0X48        //陀螺仪值,Z轴低8位寄存器7 ]4 }3 |( Q5 |( k6 P' @  F
  64. / u" |- D; t. k8 \+ C3 {
  65. #define MPU_I2CSLV0_DO_REG                0X63        //IIC从机0数据寄存器
    8 k7 c' ~" O, o: e
  66. #define MPU_I2CSLV1_DO_REG                0X64        //IIC从机1数据寄存器
    8 ~- Y+ w( ~( ^- E
  67. #define MPU_I2CSLV2_DO_REG                0X65        //IIC从机2数据寄存器
    ; ]: j% u' E. u% n3 @
  68. #define MPU_I2CSLV3_DO_REG                0X66        //IIC从机3数据寄存器- i+ L$ G+ R# B, v

  69. 3 c9 y/ @, i. O9 p" U
  70. #define MPU_I2CMST_DELAY_REG        0X67        //IIC主机延时管理寄存器
    , a4 n+ z8 v# u2 K( n
  71. #define MPU_SIGPATH_RST_REG                0X68        //信号通道复位寄存器
    1 e2 W2 r4 m. Q# ^2 [- ?9 ]" x
  72. #define MPU_MDETECT_CTRL_REG        0X69        //运动检测控制寄存器8 I$ ^0 J) |7 j; f! g& F! i; Z+ U
  73. #define MPU_USER_CTRL_REG                0X6A        //用户控制寄存器
    ' x5 X, A9 |0 K6 b* h  t- i
  74. #define MPU_PWR_MGMT1_REG                0X6B        //电源管理寄存器1
    / H% G5 }! `" Y* o+ K  z& {
  75. #define MPU_PWR_MGMT2_REG                0X6C        //电源管理寄存器2
    ! k  W5 W- ?8 ^
  76. #define MPU_FIFO_CNTH_REG                0X72        //FIFO计数寄存器高八位
    2 s5 b4 X! @4 t: ^: t, y
  77. #define MPU_FIFO_CNTL_REG                0X73        //FIFO计数寄存器低八位
    5 O& h; [% n9 E7 `' w2 I# Y
  78. #define MPU_FIFO_RW_REG                        0X74        //FIFO读写寄存器
    9 [- }% _6 K; r1 }. X
  79. #define MPU_DEVICE_ID_REG                0X75        //器件ID寄存器
    - X8 f, n+ J* }% z; l! A
  80. ' z$ ^( l& j7 r* d
  81.   p' {" \2 ?6 q

  82. 0 _7 A$ h: ], K# s  E
  83. % B- o9 J4 l: I6 i8 }6 j1 S
  84. /* 函数声明 */
    9 [" n( X4 V( I0 G' G) a. O
  85. uint8_t MPU_Read_Byte( uint8_t reg );
    % u% l' }% }' L1 _2 s# K
  86. uint8_t MPU_Write_Byte( uint8_t reg, uint8_t data );$ D8 h$ L, x, l  o) c' v# y. c6 f4 J
  87. uint8_t MPU_Read_Continue( uint8_t addr, uint8_t reg, uint8_t len, uint8_t *buf );
    1 L' k7 D3 b: k0 H2 J# J4 y
  88. uint8_t MPU_Write_Continue( uint8_t addr, uint8_t reg, uint8_t len, uint8_t *buf );2 t6 A2 t9 r1 P0 W' U* W
  89. 9 J; i  b8 g& G1 ^" s8 S/ m9 y8 [
  90. uint8_t MPU_Init( void );
      w0 a# f0 i5 n; F. D& {+ I# _6 A
  91. : Z; |2 u( `2 o, i! S8 U
  92. . N! z  l* U5 ~7 c  M/ T
  93. uint8_t MPU_Set_Gyro_Fsr( uint8_t fsr );
      F6 d- ?" T- E( w% L
  94. uint8_t MPU_Set_Accel_Fsr( uint8_t fsr );
    ( }, A3 t& w+ h/ I
  95. uint8_t MPU_Set_LPF( uint16_t lpf );6 S6 F: B# t0 t
  96. uint8_t MPU_Set_Rate( uint16_t rate );
    2 Z1 u& n" z  V! ~6 J1 |( ~
  97. short MPU_Get_Temperature( void );$ J, w- S% P( Z8 ]! ^
  98. uint8_t MPU_Get_Gyroscope( short *gx, short *gy, short *gz );/ m( N  V2 R. q
  99. uint8_t MPU_Get_Accelerometer( short *ax, short *ay, short *az );& o( E" G  h! }/ G5 |, @5 }& A

  100. " }6 ~, H+ D) q( F6 [" n5 ?
  101. #endif3 A& y$ z# }& S

  102. * n0 P) i( s+ v" s
复制代码
4 e- H( z, b  x: V) o. ~7 B8 b
mpu6050.c, a# N- Y& x" z. _+ [
最为重要的一部分代码,包括了对MPU6050的一系列基本配置和读取原始数据的操作,代码都注解的很详细了。- F! _5 a$ y" K2 ?9 E
AD0引脚用了PA15,所以要GPIO_Remap_SWJ_JTAGDisable,换个引脚也可以。/ V( T: E  J6 ]) `, |$ l
  1. #ifndef __MPU6050_H5 Y* k3 u6 y, c4 L6 ?
  2. #define __MPU6050_H
    * H* p% v# f% n6 X
  3. $ H1 u5 ?: n! h- H3 ^3 h* F
  4. #include "stm32f10x.h"! I3 l* a" x( X$ G
  5. #include "mpu_iic.h"
    * ~. Q) A6 |8 A( \, o4 P$ A

  6. ' Z- [: N! N+ R" E( D3 q) J+ Y0 D
  7. , _! w9 r+ r" k' f  _# W: b0 K
  8. /* AD0接地,MPU6050的IIC地址为0x68   接3.3V就为0x69*/
    ) a' `# \4 ~/ M, d3 p+ X% k( }
  9. #define MPU_ADDR                                0X68  F7 o* w! h3 J2 O
  10. ' f0 d7 ~& [. b+ k+ F
  11. /************** MPU6050相关寄存器地址 *********************/9 `' t: G9 c* U! V
  12. #define MPU_ACCEL_OFFS_REG                0X06        //accel_offs寄存器,可读取版本号,寄存器手册未提到
    % D3 j% ?7 v% v# W7 ^3 g
  13. #define MPU_PROD_ID_REG                        0X0C        //prod id寄存器,在寄存器手册未提到
    - ?" b! ?) u) _5 o5 b: x
  14. #define MPU_SELF_TESTX_REG                0X0D        //自检寄存器X
    # ^  R3 N4 s( r
  15. #define MPU_SELF_TESTY_REG                0X0E        //自检寄存器Y
    & P2 u& q7 ~/ @
  16. #define MPU_SELF_TESTZ_REG                0X0F        //自检寄存器Z
    4 D1 n5 @) Y$ A6 M7 Q5 J! w. p0 h
  17. #define MPU_SELF_TESTA_REG                0X10        //自检寄存器A
    # q8 Y/ v; b( _1 x4 Q; h' _
  18. #define MPU_SAMPLE_RATE_REG                0X19        //采样频率分频器
    ) {% ^! F1 I! c/ d, z9 y2 E% S
  19. #define MPU_CFG_REG                                0X1A        //配置寄存器
    . x2 l" s" M, v. h6 X0 P
  20. #define MPU_GYRO_CFG_REG                0X1B        //陀螺仪配置寄存器& W  W* e) o/ _1 I
  21. #define MPU_ACCEL_CFG_REG                0X1C        //加速度计配置寄存器7 M/ P) Q2 X* \/ n1 {
  22. #define MPU_MOTION_DET_REG                0X1F        //运动检测阀值设置寄存器
    * F) S- Q7 K' l: m; e* w
  23. #define MPU_FIFO_EN_REG                        0X23        //FIFO使能寄存器
    ! V1 H+ K6 N+ S
  24. #define MPU_I2CMST_CTRL_REG                0X24        //IIC主机控制寄存器
    7 s! r0 J) u! R5 O! ~
  25. #define MPU_I2CSLV0_ADDR_REG        0X25        //IIC从机0器件地址寄存器+ c; Z! W- B% }
  26. #define MPU_I2CSLV0_REG                        0X26        //IIC从机0数据地址寄存器: g6 t0 z5 ^# c0 X4 S
  27. #define MPU_I2CSLV0_CTRL_REG        0X27        //IIC从机0控制寄存器# W; _2 C) B3 {+ T4 O
  28. #define MPU_I2CSLV1_ADDR_REG        0X28        //IIC从机1器件地址寄存器
    2 x8 V: R* S- c% y* z2 {
  29. #define MPU_I2CSLV1_REG                        0X29        //IIC从机1数据地址寄存器
    " _8 v; w" H( I8 `0 f
  30. #define MPU_I2CSLV1_CTRL_REG        0X2A        //IIC从机1控制寄存器4 Q- N3 a/ j; S
  31. #define MPU_I2CSLV2_ADDR_REG        0X2B        //IIC从机2器件地址寄存器4 A8 D0 G/ F1 ^! p+ H2 t; F5 ^; r
  32. #define MPU_I2CSLV2_REG                        0X2C        //IIC从机2数据地址寄存器6 K: C" g4 l7 b' G0 }; N) {
  33. #define MPU_I2CSLV2_CTRL_REG        0X2D        //IIC从机2控制寄存器; g4 B4 r; e/ m6 X+ j- G* k: T
  34. #define MPU_I2CSLV3_ADDR_REG        0X2E        //IIC从机3器件地址寄存器
    7 ~* C& K' r( X  r6 ~
  35. #define MPU_I2CSLV3_REG                        0X2F        //IIC从机3数据地址寄存器4 B) \/ g: {# L+ j2 H4 y
  36. #define MPU_I2CSLV3_CTRL_REG        0X30        //IIC从机3控制寄存器
    2 Y3 p+ r- H; B+ B# t7 \$ Y; u
  37. #define MPU_I2CSLV4_ADDR_REG        0X31        //IIC从机4器件地址寄存器9 ?' p1 o7 r0 B  Y  W
  38. #define MPU_I2CSLV4_REG                        0X32        //IIC从机4数据地址寄存器
    ! ^0 l' y& _. T6 M, d
  39. #define MPU_I2CSLV4_DO_REG                0X33        //IIC从机4写数据寄存器+ S. H1 q* b9 ^& G( M3 M& l
  40. #define MPU_I2CSLV4_CTRL_REG        0X34        //IIC从机4控制寄存器3 A  }. s( ~' G8 I
  41. #define MPU_I2CSLV4_DI_REG                0X35        //IIC从机4读数据寄存器
    7 r* d. q, D' t/ M

  42. 1 o7 [% S5 @- ^  Q
  43. #define MPU_I2CMST_STA_REG                0X36        //IIC主机状态寄存器
    6 k0 `7 g& n5 R2 O4 B- X# u  s
  44. #define MPU_INTBP_CFG_REG                0X37        //中断/旁路设置寄存器2 `$ X( q# ~6 P) ^/ N
  45. #define MPU_INT_EN_REG                        0X38        //中断使能寄存器, n( r9 z1 C3 U1 c2 R- L
  46. #define MPU_INT_STA_REG                        0X3A        //中断状态寄存器+ Q* P% r1 T; d$ c% j. Z

  47. , j" |: Q; J/ X
  48. #define MPU_ACCEL_XOUTH_REG                0X3B        //加速度值,X轴高8位寄存器
    ! t: s( F# f- ^  n; W
  49. #define MPU_ACCEL_XOUTL_REG                0X3C        //加速度值,X轴低8位寄存器
    ( t8 W. H. e/ ?. o: I* p
  50. #define MPU_ACCEL_YOUTH_REG                0X3D        //加速度值,Y轴高8位寄存器
    ' y4 f/ F6 j& j" R. k8 z" F6 x
  51. #define MPU_ACCEL_YOUTL_REG                0X3E        //加速度值,Y轴低8位寄存器. T9 M4 O6 s' ]  B
  52. #define MPU_ACCEL_ZOUTH_REG                0X3F        //加速度值,Z轴高8位寄存器1 A6 X" z5 L4 W* I0 |$ I
  53. #define MPU_ACCEL_ZOUTL_REG                0X40        //加速度值,Z轴低8位寄存器
    7 c& x  u7 l8 X/ p/ |
  54. ; k9 b( c8 |0 r& Y; W6 h
  55. #define MPU_TEMP_OUTH_REG                0X41        //温度值高八位寄存器8 [% u5 R$ v  q5 h- r+ d3 U* @
  56. #define MPU_TEMP_OUTL_REG                0X42        //温度值低8位寄存器
    6 h) Q' }7 R+ M2 \2 s% p, c# h, j! K

  57. ( m/ Y& \  m- T
  58. #define MPU_GYRO_XOUTH_REG                0X43        //陀螺仪值,X轴高8位寄存器1 U# W$ R( x+ J6 `, k9 v8 l; U7 i
  59. #define MPU_GYRO_XOUTL_REG                0X44        //陀螺仪值,X轴低8位寄存器
    9 g  ^# T: [& H. U3 F$ J: P
  60. #define MPU_GYRO_YOUTH_REG                0X45        //陀螺仪值,Y轴高8位寄存器+ s/ U) G0 g0 K5 E: O4 Y
  61. #define MPU_GYRO_YOUTL_REG                0X46        //陀螺仪值,Y轴低8位寄存器
    2 h# p/ h' M" b/ D( y9 }; {! L
  62. #define MPU_GYRO_ZOUTH_REG                0X47        //陀螺仪值,Z轴高8位寄存器8 v/ c% {/ s/ f" n
  63. #define MPU_GYRO_ZOUTL_REG                0X48        //陀螺仪值,Z轴低8位寄存器
    & N% n) [8 ?; e# d) |
  64. - ]) B+ u5 b+ z7 Z' W
  65. #define MPU_I2CSLV0_DO_REG                0X63        //IIC从机0数据寄存器
    2 E$ ?( F+ g% |0 k9 q* e
  66. #define MPU_I2CSLV1_DO_REG                0X64        //IIC从机1数据寄存器
    5 Q% O% i7 @: t7 i; q( K
  67. #define MPU_I2CSLV2_DO_REG                0X65        //IIC从机2数据寄存器
    , z: t& b9 B! `$ G1 C6 o
  68. #define MPU_I2CSLV3_DO_REG                0X66        //IIC从机3数据寄存器
    - h( G, L: o" D1 @7 U/ k) c
  69. * B' m9 [% F3 }- b% v9 w) w0 S; s
  70. #define MPU_I2CMST_DELAY_REG        0X67        //IIC主机延时管理寄存器
    & h* x+ P1 i; V  F' m
  71. #define MPU_SIGPATH_RST_REG                0X68        //信号通道复位寄存器( \7 D5 Z9 [7 i4 @! `
  72. #define MPU_MDETECT_CTRL_REG        0X69        //运动检测控制寄存器  x$ W7 b0 E- K1 f# h
  73. #define MPU_USER_CTRL_REG                0X6A        //用户控制寄存器1 A. ^& e$ s. e: o) K% ~6 x
  74. #define MPU_PWR_MGMT1_REG                0X6B        //电源管理寄存器12 C3 u) ^' w+ l
  75. #define MPU_PWR_MGMT2_REG                0X6C        //电源管理寄存器2 8 B2 e/ h& l+ P: D
  76. #define MPU_FIFO_CNTH_REG                0X72        //FIFO计数寄存器高八位6 t. h2 S, R$ ]- {7 f' p: X2 U
  77. #define MPU_FIFO_CNTL_REG                0X73        //FIFO计数寄存器低八位! o0 p+ N4 H1 i9 m3 D# z
  78. #define MPU_FIFO_RW_REG                        0X74        //FIFO读写寄存器
    " m1 c0 G- N- ~1 ~
  79. #define MPU_DEVICE_ID_REG                0X75        //器件ID寄存器! n& q- U8 I  x# V* B+ O

  80. ! ^7 a% s& s4 L% o  L

  81. " ~3 N! t, f% b; x; J
  82. 6 y2 d1 B+ @6 w( n, |9 [

  83. - w* W4 C0 b7 }$ S- Y
  84. /* 函数声明 */
    3 V% @8 f2 R+ W* e
  85. uint8_t MPU_Read_Byte( uint8_t reg );
    9 {. N! j. c" m
  86. uint8_t MPU_Write_Byte( uint8_t reg, uint8_t data );
    1 z4 C4 a& i& K  U, v) t: [- g
  87. uint8_t MPU_Read_Continue( uint8_t addr, uint8_t reg, uint8_t len, uint8_t *buf );
    7 |) o# N6 Y) ~  {( z/ |
  88. uint8_t MPU_Write_Continue( uint8_t addr, uint8_t reg, uint8_t len, uint8_t *buf );. ?5 n3 d) t* Y
  89. / C# t. }/ r7 S7 X9 F7 c: L
  90. uint8_t MPU_Init( void );
    3 ~" r6 u% o, q; o9 E
  91. & b. a; V1 e0 [: ]  _7 y
  92. ' G6 ^% w% h7 O# w# E/ u
  93. uint8_t MPU_Set_Gyro_Fsr( uint8_t fsr );% O* ?4 z, ^% z9 U* _  o1 ^9 B) H" |7 i7 Q
  94. uint8_t MPU_Set_Accel_Fsr( uint8_t fsr );; p# T# S) {2 [4 ~; k7 p$ x. r
  95. uint8_t MPU_Set_LPF( uint16_t lpf );( A0 o5 m1 b4 o' f: S
  96. uint8_t MPU_Set_Rate( uint16_t rate );
    ! R4 X' o: y! T, N9 H+ Q
  97. short MPU_Get_Temperature( void );
    . w0 `* z( p- R2 p1 k
  98. uint8_t MPU_Get_Gyroscope( short *gx, short *gy, short *gz );6 k7 r, v$ U# `" v3 ~
  99. uint8_t MPU_Get_Accelerometer( short *ax, short *ay, short *az );
    " p( {  B3 v; F

  100. ( P  |" [. E8 W. m4 c, _& a
  101. #endif
    ' Y' f, J& d% Y" F. j
  102. ! H  G. `4 b6 ^- z' _
复制代码
& g4 Z) b& g& G& x
4.DMP相关代码* {% N2 U1 s6 _: l% }- e" h' a
要想使用DMP求欧拉角的代码,包含下面这几个文件即可,下面列出接口函数,到时候使用时直接使用接口函数即可。
  p) ?' B- I, U3 Z) B- d
" J* T/ {, c% s
20200215175340295.png & s6 h/ o- O! _/ @# A
* h0 U' I$ |/ Z, G/ D
向DMP算法提供的接口宏定义
$ O. B1 D* w+ T5 `5 p) a! X只需要提供:对MPU6050的读写操作函数和延时函数即可
, [5 T2 d' W1 K) M+ a
  1. #define i2c_write   MPU_Write_Continue
    ) j6 R7 i5 ]7 C5 O& M# G! d
  2. #define i2c_read    MPU_Read_Continue
    0 n, v, g! `0 ^$ A& a
  3. #define delay_ms    delay_ms
    6 Z% I6 n( _+ E. g6 O* Q+ g
复制代码
: h0 D0 `+ O% o* d# j
DMP初始化
/ T8 l" o8 f1 i- f2 \* p" l% I
  1. //mpu6050,dmp初始化2 C, ^  l: [6 ?$ w
  2. //返回值:0,正常" n9 [0 q  [( U% {: R3 @
  3. //    其他,失败
    4 ~: \) `0 b/ }+ c
  4. uint8_t mpu_dmp_init(void)
    % _  @7 u% [; P3 A5 A
  5. {- \$ x0 |) _2 [
  6.         uint8_t res=0;* X1 a8 P3 y4 G0 V; r2 g6 ^
  7.         MPU_IIC_Init();         //初始化IIC总线
    3 C: u% i% Q& \$ x1 H0 p
  8.         if(mpu_init()==0)        //初始化MPU6050
    0 k" j7 l# j. ?. A. @! e
  9.         {         
    6 l( C/ F* D  b8 ?! z3 W) @$ Q* Z
  10.                 res=mpu_set_sensors(INV_XYZ_GYRO|INV_XYZ_ACCEL);//设置所需要的传感器7 d8 ]1 \" R" }$ ]- L
  11.                 if(res)return 1; , d3 S1 U- v: |9 Y4 W
  12.                 res=mpu_configure_fifo(INV_XYZ_GYRO|INV_XYZ_ACCEL);//设置FIFO
      i, G/ d% V' N6 q) {3 }
  13.                 if(res)return 2;
    2 \6 W' O5 ]! S. P4 \, V
  14.                 res=mpu_set_sample_rate(DEFAULT_MPU_HZ);        //设置采样率
    , G: ?" I8 s6 j; Q8 h/ J9 m, {
  15.                 if(res)return 3; 9 L; U' g# u7 w3 t6 |" X3 U
  16.                 res=dmp_load_motion_driver_firmware();                //加载dmp固件
    % q  \$ A+ P2 y) A9 s
  17.                 if(res)return 4;
    - \1 L. v) }+ {( }
  18.                 res=dmp_set_orientation(inv_orientation_matrix_to_scalar(gyro_orientation));//设置陀螺仪方向
    9 @4 t  N0 O2 J
  19.                 if(res)return 5; ' l& I5 n" h1 e- s' d- E; X- ^
  20.                 res=dmp_enable_feature(DMP_FEATURE_6X_LP_QUAT|DMP_FEATURE_TAP|        //设置dmp功能+ F1 e6 u0 C5 H# v
  21.                     DMP_FEATURE_ANDROID_ORIENT|DMP_FEATURE_SEND_RAW_ACCEL|DMP_FEATURE_SEND_CAL_GYRO|
    ( `5 H! t& E$ z* I- V/ Q7 K
  22.                     DMP_FEATURE_GYRO_CAL);
    + s' x3 o% N- r# f: L) o0 y3 L7 }
  23.                 if(res)return 6;
    % p8 f7 W+ w8 \+ q' n2 P6 |' |
  24.                 res=dmp_set_fifo_rate(DEFAULT_MPU_HZ);        //设置DMP输出速率(最大不超过200Hz)% u9 R+ I2 {# @; l
  25.                 if(res)return 7;   
    % a* o- h; L! W( E4 q; K
  26.                 res=run_self_test();                //自检
    3 F* k4 m3 x: G( `$ V
  27.                 if(res)return 8;    ; L* Q0 J7 L4 @
  28.                 res=mpu_set_dmp_state(1);        //使能DMP6 h& y! {! a8 f' P, \
  29.                 if(res)return 9;     " u  L( _( A; h
  30.         }else return 10;9 K* z9 L# Y$ Y8 D
  31.         return 0;
    ; k- _! ~" u7 I  b
  32. }
    * w9 p6 b# F) {& ?
复制代码

" k7 w0 T: C# u- r. k2 _: X获取欧拉角9 H8 ]9 l$ |5 q' F9 w8 f  F- @. E% D
  1. //得到dmp处理后的数据(注意,本函数需要比较多堆栈,局部变量有点多)
    # d9 f& L# B4 m. ?
  2. //pitch:俯仰角 精度:0.1°   范围:-90.0° <---> +90.0°
    ' {8 ^- f+ F1 R7 o6 z
  3. //roll:横滚角  精度:0.1°   范围:-180.0°<---> +180.0°6 C  s! c' p* Y% ~3 S7 L3 X: O
  4. //yaw:航向角   精度:0.1°   范围:-180.0°<---> +180.0°
    ( O' f1 P6 v+ _+ V; w
  5. //返回值:0,正常- I/ i9 K7 h. h1 A; E$ J
  6. //    其他,失败# g/ z# g' @3 R2 w, x( F
  7. uint8_t mpu_dmp_get_data(float *pitch,float *roll,float *yaw)
    4 f. C6 `$ E( _
  8. {$ p" i' X; Z5 d4 a3 ]9 P  Z
  9.         float q0=1.0f,q1=0.0f,q2=0.0f,q3=0.0f;
    . y# o7 _( s# X- `
  10.         unsigned long sensor_timestamp;' x, ^$ A/ O. E
  11.         short gyro[3], accel[3], sensors;9 d% ~# H2 m$ W# ]6 v
  12.         unsigned char more;" \# t+ T+ @, `8 M/ Y% J1 N7 J
  13.         long quat[4];
    ; n7 K* O! @% O0 G" G/ N
  14.         if(dmp_read_fifo(gyro, accel, quat, &sensor_timestamp, &sensors,&more))return 1;         
    : N* u% N$ p) \8 y
  15.         /* Gyro and accel data are written to the FIFO by the DMP in chip frame and hardware units.
    / f0 h& b5 t9 J, M  h+ ~
  16.          * This behavior is convenient because it keeps the gyro and accel outputs of dmp_read_fifo and mpu_read_fifo consistent.
    % }6 |* Y9 ]( t2 i
  17.         **/
    - X. g1 C% \" |6 p& W& j4 @/ ~
  18.         /*if (sensors & INV_XYZ_GYRO )
    , R  \% P, g! c5 R& \
  19.         send_packet(PACKET_TYPE_GYRO, gyro);
    , e8 `3 A" v( r7 n
  20.         if (sensors & INV_XYZ_ACCEL)
    8 M$ o! v, B  _: }* @2 A
  21.         send_packet(PACKET_TYPE_ACCEL, accel); */
    9 q3 `, i' Q: p
  22.         /* Unlike gyro and accel, quaternions are written to the FIFO in the body frame, q30.
    ! R$ M- b9 |1 I% e
  23.          * The orientation is set by the scalar passed to dmp_set_orientation during initialization.
    0 D$ d" ]) h# I
  24.         **/$ q! y8 X, n( I" m  i
  25.         if(sensors&INV_WXYZ_QUAT)
    - _: g. o% r* h' S! q0 V
  26.         {
    7 m2 i! m; W8 O1 a
  27.                 q0 = quat[0] / q30;        //q30格式转换为浮点数/ B6 H# U# w# s
  28.                 q1 = quat[1] / q30;
    % q! B. d8 T- v1 @4 p7 _% R, v. m5 R
  29.                 q2 = quat[2] / q30;7 d7 b  P& J9 ]; Q+ ?! Q* ?9 k
  30.                 q3 = quat[3] / q30; 4 h3 d7 v1 ?4 T8 |% ]9 \  ~
  31.                 //计算得到俯仰角/横滚角/航向角; b3 d: U% z# x# W0 c
  32.                 *pitch = asin(-2 * q1 * q3 + 2 * q0* q2)* 57.3;        // pitch
    . _9 |( Q5 d0 y1 N1 h: F
  33.                 *roll  = atan2(2 * q2 * q3 + 2 * q0 * q1, -2 * q1 * q1 - 2 * q2* q2 + 1)* 57.3;        // roll
    & A: S$ M; ]: K& S0 H
  34.                 *yaw   = atan2(2*(q1*q2 + q0*q3),q0*q0+q1*q1-q2*q2-q3*q3) * 57.3;        //yaw* D: p) D1 z& j4 b$ Q- c
  35.         }else return 2;( Z, q  U/ _. C3 l6 m8 H
  36.         return 0;
    * w! W3 j* N6 y4 X
  37. }
    2 P% z5 \, t* W; K' x$ t! I& a' O# B
  38. * y. @* D! ~/ O. O: B& X
复制代码
. t0 i4 q3 b  a! A
5.mian()函数
" y: O! @7 I! o0 Q2 a3 {7 _' S% k主函数中对MPU6050进行初始化后,对DMP也进行初始化,然后就可以直接使用mpu_dmp_get_data()获取欧拉角,还可以获取温度值。
4 O4 B! p5 b8 o4 d
  1. #include "stm32f10x.h"   
    : \2 F( R2 n/ i( B$ A
  2. #include "usart.h": d/ t+ _( i/ i3 A" e# b
  3. #include "delay.h"" m  i6 N6 Z) f6 P1 u+ b
  4. #include "mpu6050.h"
    % h7 S- j6 j/ O% w
  5. #include "inv_mpu.h"
    ' V% F- x) h. o3 `. L$ O7 L
  6. #include "inv_mpu_dmp_motion_driver.h" # l8 o9 ^! V+ o! I" U
  7. * q2 P7 M' E9 h0 r  @
  8. int main(void)
    7 a' R$ n/ n5 n0 C) F
  9. {
    4 W  X4 `& g# `
  10.         uint8_t x=0;5 ?6 _  R. }+ i$ Z0 b* c. J
  11.         float pitch,roll,yaw;                 //欧拉角
    9 W+ V2 O  p3 m/ N' j! [0 i; l( s  v
  12.         short aacx,aacy,aacz;                //加速度传感器原始数据
    2 p, H, f5 @& m- K4 y% G
  13.         short gyrox,gyroy,gyroz;        //陀螺仪原始数据+ U4 ?9 g6 r( |% z4 I
  14.         short temp;                                        //温度; k9 v7 M; @4 b; U
  15.        
    # D0 C/ Q8 S6 Y7 i  Y5 x5 _
  16.         NVIC_PriorityGroupConfig( 2 );. Y( M% c9 M. b
  17.         delay_init();
    9 _* w5 J6 {8 }( I% ?
  18.         USART1_Init(115200);       
    ( v" D0 J/ }! G2 {7 C
  19.         printf("程序开始\n");
    6 i& G2 D* ^! X- G
  20.        
    ( r  H/ v" Q" |* v* [' m- ?
  21.         if( MPU_Init()!=0 ), E' X9 |0 {" m
  22.         {* I/ {0 l$ C0 R- @
  23.                 printf("MPU6050初始化错误!\n");
    6 z2 |7 ?+ @+ J% g- }
  24.                 return 0;
    / m' [3 _4 M4 p" h+ X: K! w& t
  25.         }/ M* P& Y, O# b8 @/ Q& L% b' h
  26.                
    ) Q( Z3 \2 b) K) U0 i; E
  27.         if( mpu_dmp_init() )  T8 Z5 y& u8 c) h) H
  28.         {2 ^; ^$ u$ b, q8 H) M8 T
  29.                 printf("DMP初始化错误!\n");
    - \+ C$ ]# h$ _5 \5 _/ R8 X
  30.                 return 0;( W# R& q* U: P6 c% j2 {( p/ q' D
  31.         }/ Q/ A4 Z& ]5 ]9 d  @9 ^$ P
  32.         while(1)
    . ^  E- H4 P; c* l, c& a
  33.         {
    9 [1 f% }3 y2 l* s: v
  34.                 if(mpu_dmp_get_data(&pitch,&roll,&yaw)==0)
      N' L, b4 u: g
  35.                 {
    ! R/ C; d; ]1 b, l$ M! X8 T0 p
  36.                         temp=MPU_Get_Temperature();        //得到温度值6 h' C/ c- ]7 I1 y' E7 R
  37.                         MPU_Get_Accelerometer(&aacx,&aacy,&aacz);        //得到加速度传感器数据
    * ?9 @1 w1 F) k3 P
  38.                         MPU_Get_Gyroscope(&gyrox,&gyroy,&gyroz);        //得到陀螺仪数据
    0 ~5 l; l* q( L: K& p4 a( Y) Q
  39.                 }1 R; q! f0 I) X; K6 b. H( G
  40.                 delay_ms(100);
    - Q% Q3 A( q1 e* C
  41.                 printf("pitch:%02f  roll:%02f  yaw:%02f\n",pitch,roll,yaw);
    ; A1 A8 r# R9 ]. Q$ x
  42.         }
    # b! ?& A& g9 A7 g9 W

  43. / g) f; W& Y# X
  44. }, A( H& w8 S" B# ]6 R0 d
复制代码
( R- s" g* b& ]: v. A
这就是我理解的MPU6050,后续做平衡小车的时候要读取欧拉角,先总结一下0 f+ n9 z6 C9 _
————————————————; [/ C, _& E6 M0 ?* }
版权声明:Aspirant-GQ
. C: J- D' T' l4 _* l) s3 f如有侵权请联系删除- V( N! ]; l: ?6 G0 V3 e: I7 o

9 m; j% o4 K# C' h1 B8 b0 x9 Z* `8 G9 E7 O2 U6 ^2 Z
收藏 评论0 发布时间:2023-3-18 12:25

举报

0个回答

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版