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

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

[复制链接]
攻城狮Melo 发布时间:2023-3-18 12:25
一.MPU6050介绍  m" l) J, U( ]- g
1.MPU6050与陀螺仪、加速度计的关系:

6 g" w/ m) Q% OMPU6050是InvenSense公司推出的一款全球首款的整合性9轴运动处理传感器,其最大的特色就是:消除了陀螺仪和加速度计的误差,将陀螺仪和加速度计组合在一起,而且缩小了空间。
8 ^$ _- b! U, h# ~

; X9 R4 r2 U: o/ [. Y6 E0 `2.整体概括

5 k; I7 Z5 v2 d( L6 O* eMPU6050内部整合了三轴MEMS陀螺仪、三轴MEMS加速度计以及一个可扩展的数字运动处理器DMP,而且还可以连接一个第三方数字传感器(比如:磁力计),这样的话,就可以通过IIC接口输出一个9轴信号。
) {5 P  ^4 o( r3 K2 @7 J更加方便的是,有了DMP,可以结合InvenSense公司提供的运动处理资料库,实现姿态解算。通过自带的DMP,可以通过IIC接口输出9轴融合演算的数据,大大降低了运动处理运算对操作系统的负荷,同时也降低了开发难度。4 y- `$ H- P9 n$ R# c$ W
6 s/ o* k$ L& N6 Y* h9 E& K7 o
特点
% W9 k  x# D* M9 K0 _, t① 以数字形式输出 6 轴或 9 轴(需外接磁传感器)的旋转矩阵、四元数(quaternion)、欧
, d7 J4 i% A6 ~* p2 U! P拉角格式(Euler Angle forma)的融合演算数据(需 DMP 支持)
/ \6 [* @0 _) x2 l1 c② 具有 131 LSBs/° /sec 敏感度与全格感测范围为±250、±500、±1000 与±2000° /sec; r1 `# L1 \; w" L1 r
的 3 轴角速度感测器(陀螺仪)/ U3 y& z2 r# q
③ 集成可程序控制,范围为±2g、±4g、±8g 和±16g 的 3 轴加速度传感器% I. y! f- N0 W; H$ T. x, h
④ 移除加速器与陀螺仪轴间敏感度,降低设定给予的影响与感测器的飘移; R, u/ p+ {: I; l
⑤ 自带数字运动处理(DMP: Digital Motion Processing)引擎可减少 MCU 复杂的融合演算
0 G, M8 B6 n4 X: m  D" \' R数据、感测器同步化、姿势感应等的负荷4 f: r$ F; Q& a/ [
⑥ 内建运作时间偏差与磁力感测器校正演算技术,免除了客户须另外进行校正的需求
, i5 d. b' H# ~5 \. P, [1 o⑦ 自带一个数字温度传感器
/ W7 g3 c) A4 ?! d: _& v4 E⑧ 带数字输入同步引脚(Sync pin)支持视频电子影相稳定技术与 GPS
9 q; @" }" G& H; ~: j" V! u/ e" m⑨ 可程序控制的中断(interrupt),支持姿势识别、摇摄、画面放大缩小、滚动、快速下降
) \( y+ C/ V- k# _% q5 }% E中断、 high-G 中断、零动作感应、触击感应、摇动感应功能
4 i# g2 k& O0 Y" f" m⑩ VDD 供电电压为 2.5V±5%、 3.0V±5%、 3.3V±5%; VLOGIC 可低至 1.8V± 5%2 b' Y8 @9 S8 c( |; D: g. j
⑪ 陀螺仪工作电流: 5mA,陀螺仪待机电流: 5uA; 加速器工作电流: 500uA,加速器省
( T1 f% [1 W; C电模式电流: 40uA@10Hz+ S4 |) T3 O8 Z0 L+ L- K( u
⑫ 自带 1024 字节 FIFO,有助于降低系统功耗) V. V4 o( \4 G( r
⑬ 高达 400Khz 的 IIC 通信接口- k2 j$ z/ d: c, _1 [* h" [* {
⑭ 超小封装尺寸: 4x4x0.9mm(QFN)0 c. W7 l  F& r$ |  r6 k
) F+ H. v: `! @) j# N1 {) c
其检测轴如图所示:
+ I0 S  k4 I( J( F# P( N8 i' }. v- M
20200215154932517.png
+ v: H& W) a% u$ |" F2 u/ I7 u3 g9 u
; g2 Q1 |6 h: y" G9 {- O- Y9 o
3.引脚说明8 e, G8 _/ J( z7 ^2 V) l1 V
- I7 m. K7 e  x3 G; @3 E
20200215160046383.jpg * a8 Q. t' a. C" E

9 x/ |1 G" S. U0 `* h, T如图,MPU6050一共有8个引脚,实际上输出六轴数据时,只用了5个:VCC、GND、SCL、SDA、AD0。下面介绍一下引脚:# h. X. B) m: L1 }
VCC:供电,3.3V即可, U; Y3 }$ k5 l6 U8 B
GND:接地3 T! ?. n3 i$ ?
SCL:连接MCU的IIC时钟接口& j" w7 [0 Q- ?8 @( Q- ~, ]
SAD:连接MCU的IIC数据接口4 L! @# r' u, K( G3 |+ r
XCL:连接外部设备的IIC时钟接口
4 r+ M/ Y2 h# Z' wXAD:连接外部设备的IIC数据接口9 C5 F" m# m* @
AD0:地址控制引脚(控制地址的最低位)
% R: h1 i0 y: n; d5 SINT:中断触发接口(不用)
* @  W$ G: B9 W' J  g5 y
XCL、XDA只有在连接外部设备(比如磁力计的时候才用),AD0用来控制MPU6050的地址,如果AD0低电平,地址就是0X68;如果AD0高电平,地址就是0X69。
) Z$ m7 [6 s- ~. j
: I) ^7 i  m. p9 y9 r4.基本配置及相关寄存器
& q$ [& J3 n" K! \5 P& F3 r7 ZMCU与MPU6050的通信是建立在IIC通信机制上的,在IIC的基础上,可以实现对MPU6050的寄存器的操作,而MPU6050的运作就是过对寄存器进行读写。所以,了解相关的寄存器和对寄存器的操作是很有必要的。MPU6050的寄存器相关资料都可以在数据手册中查到,下面介绍一下几个重要的寄存器:& q" v: p7 P5 c
% {; M5 u! w' y8 K) A
电源管理寄存器17 V4 {' k# x, Y' V
地址:0X68) M  ~6 }; j( _& q9 z/ Z
1 l; B- p1 Z1 V' J7 I# V" y- U' \
) }: I5 {; m4 w; A+ B7 h
20200215163434244.png ( t& A/ x* F3 L8 n+ Z
# ^7 h! Z6 O; {; N# ]
主要位的功能:
: {+ W% O4 P8 W) R; Q* zDEVICE_RESET:控制复位,1表示复位,复位后会自动清零;/ _2 v, k+ P' [/ [5 e0 j6 {( L* `
SLEEP:控制MPU6050工作模式,1表示睡眠模式,0表示正常工作模式,复位后改位为1,要手动将改位清零;
' P& T; n1 x0 Z. Y4 lTEMP_DIS:使能温度传感器位,0代表使能;
% ~$ I  `1 _2 f8 M9 z, i/ S4 o, i( Q, ~CLKSEL[2:0]:选择系统时钟源,一般采用PLL_X轴陀螺作为参考,具体的时钟源选择及相应位的值如图:
. \- B/ W2 Z( y  W5 j2 D
- S4 f# x' _4 w/ z8 Y+ q

! v6 e3 J% ~! l) h 20200215164457650.png 0 l9 U" Q1 k" N$ J

/ C% b; L- q2 x% W& {- ?
陀螺仪配置寄存器
+ t& ^: s: E1 P* W4 W地址:0X1B
. o: g! y, a& U* R  f0 [5 I  U* K, \
' C) o8 W( Q3 }2 K) G8 y4 k( `  k
20200215164757727.png & H* a9 a6 T/ U
' _4 l/ [/ w- Z9 z% m
主要位的功能:
9 i3 ~+ \+ \+ Q# \* W- V; H8 qFS_SEL[1:0]:设置陀螺仪满量程范围:为0代表±250° /S、为1代表±500° /S、为2代表±1000° /S为3代表±2000° /S;
8 H% N5 i5 p8 K1 Q$ t8 f7 m6 ~; A+ e
陀螺仪的分辨率是16位,所以在最大量程下灵敏度为: 65536/4000=16.4LSB/(° /S)。0 G2 D7 _+ X4 a
6 w8 {  s6 D# b
加速度计配置寄存器
  t. N) L  a" P2 u1 w地址:0X1C  ~' X) [" h+ P, x$ X, @! t

1 Z' A2 r1 t+ E3 u; W
20200215165411152.png
% a( z$ J; M/ u

: i4 D6 B+ V3 d$ s# _) a9 \( v主要位的功能:
2 c4 ~3 K4 i8 @/ }& m/ |AFS_SEL[1:0]:设置加速度计满量程范围:为 0代表±2g、为1代表±4g、为 2代表±8g、为 3代表±16g;( ^  |9 d: P% [' M% E
9 e; o' I1 m: o: Q8 |7 q0 o
FIFO使能寄存器
3 k  O; ?! X% n6 L) O地址:0X23
: X7 M" [6 c0 \' N
3 {6 T) n/ x) a$ ~2 ?9 X
20200215165816272.png
' v8 b% I9 r7 w. k! `. K% p

5 }! l/ q2 w6 F# {用来控制FIFO功能,相应位对应着相应的传感器FIFO功能,为0代表禁止,为1代表使能。注意:加速度传感器的三个轴的FIFO功能由一个位ACCEL_FIFO_EN控制。在简单读取传感器数据的情况下可以不使用FIFO。
0 _2 E# ^9 V4 H# `- Z3 W) @9 s
5 R: [, {8 g/ R* Q  I1 j
陀螺仪采样率分频寄存器
6 V  N5 {& Z# E& d1 a8 `, j( U地址:0X19
& ?# h/ m% B. Y, X$ c0 o0 H( \" d+ I% J- H; M1 b
20200215170242372.png + \" d- w- p% N& `: X, ?7 M

, m% f. H% |1 V改寄存器用来设置MPU6050陀螺仪的采样频率,与之相关的是陀螺仪的输出频率,俩者关系是:采样频率 = 陀螺仪输出频率 / (1+SMPLRT_DIV)
- z( A- r0 T, k) ]陀螺仪输出频率与数字低通滤波器(DLPF)有关,DLPF滤波频率一般设置为采样率的一半。
: c( x0 J) U0 i) d1 k/ j3 ]

1 c4 M. P5 z) O8 I+ R温度传感器寄存器3 }" J  X9 ]) N3 X0 @% T  t; C
地址:高八位0X41、低八位0X429 w  M, [2 |( D7 U  R& q) n
直接通过读取寄存器中的值来得到温度数据,温度换算公式为:
. z3 U5 S( f; g. Y/ X% \Temperature = 36.53 + regval/340# Q% g* H# v; ~* N5 E5 d, Z
/ }( w) e/ i! {2 o( I
二.代码详解
5 C4 M6 F4 h' U8 Y0 P1 X1.框架

( X% I% L; L3 U* F$ E) m- d我是用STM32驱动MPU6050,MPU6050输出原始的六轴数据,经过DMP处理(有库)得到四元数,再由四元数算出欧拉角:yaw、roll、pitch。由串口打印在电脑屏幕上。
5 c$ E3 F6 t# c0 X7 j; z首先,要做底层的IIC驱动,用来和MPU6050建立通信,我在mpu_iic.c中实现了;
: p' a8 }3 W$ t! B+ }; E然后,有了底层的驱动,就要写一些函数来与MPU6050交流了(通过读写寄存器),还可以写入命令、配置MPU6050、读取原始数据等等,这些操作我都写在mpu6050.c中,当然在mpu6050.h头文件中还包含了MPU各寄存器地址和相关指令。9 P" R: i9 t# B  y" P5 _2 j7 a
通过mpu6050.c的实现,就可以读出原始六轴数据,下一步就是通过DMP将原始数据转换为四元数,这一步的DMP算法我水平有限,只能移植InvenSense公司提供的例程。关于移植DMP算法,由于DMP算法本质也是对MPU6050的操作,所以我们只需要向移植过来的算法提供:对MPU6050寄存器执行读和写的函数接口即可,最后通过移植过来的函数直接读出四元数!$ {" r  Y3 C4 [4 e2 o
然后,就是将四元数转换为欧拉角了,这个比较简单,一个函数就可以实现。
; A3 C* O2 {/ P: K7 x最后,打印串口到屏幕。
! l! X, ]9 H  a  e1 H/ x/ O$ I2 b7 ~$ e7 j- q
下面给出各函数文件. s0 J! u0 k/ _8 N8 l

# j$ X/ r4 |; _4 r2.mpu_iic.c/mpu_iic.h
* C" d* h5 ~4 y* C8 Empu_iic.h
9 z  M$ _# U9 F1 F4 E8 K主要是宏定义对引脚电平的操作和进行函数声明。
% C8 f. l+ y* v7 G1 G& a; f
  1. #ifndef __MPU_IIC_H0 ?- V- f  ?2 y9 Q/ I$ z3 z' ~/ U
  2. #define __MPU_IIC_H. O& m% Y& v0 j  a! t

  3. 1 \  m, e$ s: ^* P& _; @
  4. #include "stm32f10x.h"
    2 n+ O& y+ A5 o% E; W& ?& R
  5. #include "delay.h"
      \4 Y" L7 O- ]$ I) Y& Q
  6. 3 D% a/ \# ?$ y; `# J
  7. /* 宏定义引脚电平操作函数 */% j! D: C7 s9 f, ?, G1 t* l# c) X
  8. #define MPU_SDA_IN()  {GPIOB->CRH&=0XFFFF0FFF;GPIOB->CRH|=8<<12;}
    ) r1 Y+ {/ ^9 A0 w
  9. #define MPU_SDA_OUT() {GPIOB->CRH&=0XFFFF0FFF;GPIOB->CRH|=3<<12;}  
    8 d6 B7 G6 H4 P% s8 U# V7 i
  10. 3 y- A+ \' s- X8 s, Q; e$ w

  11. 9 S- h) y3 |  g
  12. #define MPU_IIC_SDA_1() GPIO_SetBits( GPIOB, GPIO_Pin_11 )5 ^" z) ~& [9 m% ~6 k% ^# V% H
  13. #define MPU_IIC_SDA_0() GPIO_ResetBits( GPIOB, GPIO_Pin_11 )
    7 i. Z3 [4 c! O( K% y# c

  14. 0 ]% k" h" J, S
  15. #define MPU_IIC_SCL_1() GPIO_SetBits( GPIOB, GPIO_Pin_10 )
    / t! B- j: [, b' P) Y# \) X+ q
  16. #define MPU_IIC_SCL_0() GPIO_ResetBits( GPIOB, GPIO_Pin_10 )
    ! C% r# ]+ N7 v. k0 P
  17. - x$ V& M/ S7 J% L1 b
  18. #define MPU_IIC_AD0_1() GPIO_SetBits( GPIOA, GPIO_Pin_15 )
    % ~3 f3 p+ ~& C4 ^1 G
  19. #define MPU_IIC_AD0_0() GPIO_ResetBits( GPIOA, GPIO_Pin_15 )
    " p0 c7 j; t9 G
  20. ! a* l0 n, r; L" q7 M- B
  21. #define MPU_IIC_SDA_READ() GPIO_ReadInputDataBit( GPIOB, GPIO_Pin_11 )' D* u$ |% P. g+ d) L

  22. 1 Y) a( }. Z0 M' L% I! ^
  23. #define MPU_IIC_Delay() delay_us(2)9 t  L7 Y! x6 B: q+ ^

  24. 6 E- @' m/ M: R: M, A2 l
  25. /* 函数声明 */
    . y: N* v4 h8 e! m+ `' p
  26. void MPU_IIC_Init( void );
    " g2 i- I- [( {* e* U) ^" A* B/ H7 B" ?
  27. void MPU_IIC_Start( void );& E. [7 |2 a9 I0 s; n
  28. void MPU_IIC_Stop( void );
    / d- D4 I, i4 w) O$ ]- r
  29. uint8_t MPU_IIC_Wait_Ack( void );% L8 w9 Q- `' @/ S
  30. void MPU_IIC_Ack( void );
      G4 v+ y/ B3 p
  31. void MPU_IIC_NAck( void );1 }. I4 V" ?" G! t/ a; W7 T& f9 k
  32. void MPU_IIC_Send_Byte( uint8_t data );
    % g: v# x  p2 G0 T5 j* k
  33. uint8_t MPU_IIC_Read_Byte( uint8_t ack );
    ! z- a% t$ I4 A* n
  34. 1 z; h6 u; z' i7 G8 r. o
  35. #endif3 I& G/ O2 @7 H$ A$ W% a7 F' ~6 O, u

  36. 8 J$ Z4 r" a; e9 q' O3 g' p2 {$ M
复制代码

  _, y8 k+ f3 Z, zmpu_iic.c
2 p5 @& k/ o: t$ H. ^3 C4 G通过软件模拟IIC的代码,没什么好说的。  F( t) ?4 y0 t  _6 p* R
  1. #include "mpu_iic.h"
    . G# Y& p4 w8 N# W6 z
  2. #include "usart.h"' H2 \* [0 U7 u7 x; G

  3. , m! n' [0 f# i8 e+ u5 h
  4. /*
    ' o: z7 d% M0 p) B
  5. IIC接口引脚配置7 E: G& r; v2 o: S5 Z; c
  6. SDA:PB11
    2 M9 g. i9 T5 m8 r
  7. SCL:PB104 a+ p: h2 J% O( f: U/ S% K
  8. AD0:PB2
    ) T3 c' _0 b0 m; m, k  Q0 g, a
  9. */
    . S1 \8 c$ W' U4 U& i
  10. void MPU_IIC_Init( void )& f  S- [" O' Y2 W$ F
  11. {2 ]+ U- I+ D# X8 [( F& U3 d
  12.         GPIO_InitTypeDef  GPIO_InitStruct;0 w6 ?6 }8 Y$ {* t, ^) e' y# Z! W( G1 r
  13.         , R0 \5 b5 V& n8 g: w
  14.         RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB, ENABLE );+ C, g! G* R) F( {0 S( x* d* E
  15.         ( N4 ~* [/ m, k2 {" P
  16.         GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
    0 ^; s9 v5 j1 L) H3 M
  17.         GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
    2 D1 Y5 S# O8 t6 z- R' U) ]0 g
  18.         GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10|GPIO_Pin_11;
    4 Z  x1 a0 D) t  E' ^5 p0 X
  19.         GPIO_Init( GPIOB, &GPIO_InitStruct );5 Q: P. w- I2 |" d# I, L
  20.        
    8 G9 \; p+ q; R9 h# B! [
  21.         MPU_IIC_SDA_1();7 @1 b% T6 y- n$ t
  22.         MPU_IIC_SCL_1();1 j' W) v. J8 `& v: w' |/ V8 J1 J
  23. 7 _0 y- P7 R0 k3 T) S$ r' t4 O
  24. }
      z& d; O/ Y0 ?2 t% s' t; S
  25.   c& Y6 w1 W) {. h' b  @, N
  26. / a6 G0 b* L  J# X$ R4 v
  27. void MPU_IIC_Start( void )8 P4 J( A! |/ \& j  `/ L/ [
  28. {
    1 J% W  J6 s6 R: {8 m3 n
  29.         MPU_SDA_OUT();
    7 @" {+ _" @! K4 e( u9 H# g4 U
  30.         3 q0 i2 t8 Z. Z+ R4 F& i9 q
  31.         MPU_IIC_SDA_1();
    1 t2 n! l' Q! z; M; n
  32.         MPU_IIC_SCL_1();9 Z1 f8 D1 [. {1 P3 v
  33.         delay_us(2);2 b, R9 q* l& W% d3 T/ ?, e' r: l
  34.         MPU_IIC_SDA_0();
    . x6 o& c: E5 Q8 \" L
  35.         delay_us(2);4 T$ ]+ L5 T, t6 J6 a
  36.         MPU_IIC_SCL_0();8 D, C: ]: i$ z$ ^$ o8 _
  37. }
    : A$ d# @# S* l5 _% `9 D: O

  38. 2 p, w% V+ @9 z8 t( _
  39. void MPU_IIC_Stop( void )2 B$ J5 a8 c' k1 S9 n
  40. {
    2 L" b0 h" I' {
  41.         MPU_SDA_OUT();! ^$ O- J" J# M( d$ `9 f( t' i
  42.        
    ) p6 @  ~8 i0 ?. s' T; [0 q
  43.         MPU_IIC_SDA_0();
    - i- y- k/ L' S; ~
  44.         MPU_IIC_SCL_1();
    " d6 j3 b* N) P2 o/ V3 A
  45.         delay_us(2);+ L8 t- Z0 ^8 o# D& j
  46.         MPU_IIC_SDA_1();
    6 P- r' |: ^) \1 m
  47.         MPU_IIC_SCL_1();
    ! k- l; |4 g9 Y& C
  48.         delay_us(2);1 N/ E7 D" Z& p. H" }8 O2 m
  49.         % U4 |& O8 _- V5 P
  50. }' a( P, K) [1 K# k5 ^+ w
  51. 0 J9 _& |6 {0 Z% s# k! y  \
  52. /* 由从设备在SCL为高电平的时候拉低SDA作为应答
    ! \9 [5 G; q6 H/ Y; `
  53. 返回值:1:未应答
    4 |  j  E2 A/ \* L7 z. P8 b7 T
  54.         0:已应答' [9 |; w; w- y; H' u
  55. */7 r/ {8 P8 c& c7 k# u% U
  56. uint8_t MPU_IIC_Wait_Ack( void )( E6 F% L+ b" h' Q! g
  57. {3 p& u8 [0 F$ p# E& T' ]
  58.         uint8_t count;
      E. ~' t+ v5 W1 Q- O5 ^- P
  59.         MPU_SDA_IN();1 ]* H7 t; x" X7 U  u
  60.         " w9 ^; ]+ t. F. G* Y2 _
  61.         MPU_IIC_SCL_1();
      C' y1 T) m' k' G/ L& ^6 x
  62.         delay_us(2);
    9 ~  ~& e- ]0 H% R
  63.         MPU_IIC_SDA_1();
    + w: d+ }3 c% _, [1 u: d: P
  64.         delay_us(2);
    / B' n; Q6 g, o  {! I3 O! z, ~
  65.         6 \- S) t: Y  v( y' @* _
  66.         while( MPU_IIC_SDA_READ()==1 )
    8 p# ^, E& m1 Z) K' T
  67.         {7 u  j% \. K* l% b% G- E  U  |( p
  68.                 count++;+ s$ c$ p( F. i/ R
  69.                 if( count>250 )
    9 o/ `) y# p7 q5 U: H* z/ t( [7 U( F
  70.                 {# W1 R: t3 ~% ^; n
  71.                         MPU_IIC_Stop();
    & m* M( |8 p% Q' H
  72.                         return 1;
    0 E! p6 L; M1 `% A$ ]# W+ L  A
  73.                 }
    3 c  o0 K2 R$ k% `' z9 C* H0 D
  74.         }        ! H  z! s3 I+ Z) c3 t- v, B( x
  75.         MPU_IIC_SCL_0();
    6 G, u" _0 L" C/ S8 J
  76.         return 0;
    8 [+ v3 w, x) l! k5 N
  77. }8 p0 J& e5 K# x/ e+ g, z  x

  78. 1 R! D1 d! [  f
  79. # V8 T9 C. A* t) s: {
  80. void MPU_IIC_Ack( void )7 U# d9 |/ n5 X9 a; ~. b. g
  81. {
    2 h) P. z  K, H" z
  82.         ) D# G: ?9 f, R" G3 r. }0 i
  83.         MPU_IIC_SCL_0();  S4 t: h  Z3 F
  84.         MPU_SDA_OUT();
    5 f4 }- E( l+ f( Y  W4 p
  85.         MPU_IIC_SDA_0();1 C$ B$ l5 M" k" r1 e
  86.         delay_us(2);
    ' P9 e+ {/ w( }, W2 D+ z, x+ d
  87.         MPU_IIC_SCL_1();6 _$ p- T8 v0 ~: p5 ~
  88.         delay_us(2);: B; k+ N+ R6 S7 h( h
  89.         MPU_IIC_SCL_0();
    7 Z$ U; f: a! s3 G; n
  90.        
    4 G& k/ @% w( \# e9 z, J
  91. }* G1 |7 G: k% k  |: O" \* M

  92. * F3 _. X# b* {2 p6 O/ ?

  93. & U+ I8 a" L  ?8 b
  94. void MPU_IIC_NAck( void )
    ; ~) u* O  ~$ ]: M
  95. {, h9 M7 x0 {3 ?& D* d
  96.         ) W) T: d* x) X/ N9 p5 ~3 L
  97.        
    4 w" P+ ]5 G8 X$ Q: h* [
  98.         MPU_IIC_SCL_0();
    * m! A- \2 T& P+ C! y
  99.         MPU_SDA_OUT();
    7 @: M( L7 T! F2 C2 ?) ?0 b
  100.         MPU_IIC_SDA_1();
    # G$ ~# m' d/ ~/ I- [
  101.         delay_us(2);
    . Z+ Q2 N9 O) O" K% a& J/ u
  102.         MPU_IIC_SCL_1();9 B+ P: H9 b& H& d# a, h
  103.         delay_us(2);! |& ]4 Q1 \0 p- j% }0 Q" h3 A
  104.         MPU_IIC_SCL_0();2 s$ e4 R2 h; a2 o& D9 T9 \! A: ^3 g
  105. }
    7 @+ c- o# b$ I2 _' }+ O: ^

  106. # I  \9 L# S  m- [+ c0 e

  107. 8 Q4 G8 l: k. @$ h4 [( Q: l+ G
  108. /* 发送一个字节数据,高位先行 */
    ! N1 v2 L; F1 b+ ]) }9 R$ n/ D$ l  u
  109. void MPU_IIC_Send_Byte( uint8_t data )
    8 }2 \& V2 }* O
  110. {) h- K8 y+ \% c1 x5 x( s. h, z' x( B
  111.         uint8_t t;  S1 R8 G% e; {5 Q
  112.         MPU_SDA_OUT();
    ! X1 h* O3 G7 M3 z) s( j. B
  113.         + R6 Q5 N# |  w
  114.         MPU_IIC_SCL_0();
    - M' g8 r6 c  e9 {9 K  S
  115.         for( t=0;t<8;t++ )
    1 k8 n: z" H7 e
  116.         {4 [0 `% h2 v: C, O* x6 O
  117.                 if( ((data&0x80)>>7)==1 )6 ?* P1 Q, E) g% o0 O. N2 q, M, [5 Y
  118.                         MPU_IIC_SDA_1();2 m1 v; c  v8 M  Z
  119.                 else% M' M3 K& W+ {& ^& e
  120.                         MPU_IIC_SDA_0();
    , Q  `- |) ]7 G! i( o- k$ v
  121.                 data<<=1;
    / b1 x% [' r8 `% F. |# f/ ~" |
  122.                 MPU_IIC_SCL_1();$ j! k2 {  B* {4 B! W9 d# L0 F
  123.                 delay_us(2);
    $ L) L, x: `- R. s: o" m$ f$ g; n
  124.                 MPU_IIC_SCL_0();& z& {% T; g! P/ r* G
  125.                 delay_us(2);
    * ~) P/ h; \- r3 k  f$ h
  126.         }; M+ o! j% ^  Q! e) {4 F8 ?& n8 I
  127. }
    6 z# ?9 x$ b" Z1 p( w' E
  128. ; X( h2 ~( N, d& Y# W
  129. 8 T4 o3 ^$ J+ H, V1 a7 Y, t
  130. /* 读取一个字节,ack=1时,读取完成后主机发送应答 */* g  U3 |) x6 h7 [, ?, P( j9 ~: D; n
  131. uint8_t MPU_IIC_Read_Byte( uint8_t ack )
    . C' {- S* K  W- U+ _/ }  T
  132. {
    5 @) y6 O# ]" P  y$ a" F8 b4 [
  133.         uint8_t t,data=0;6 X* Y% _. s( l4 p/ r* O* Q
  134.         MPU_SDA_IN();
    . w9 M$ U. U) P3 n
  135.         for( t=0;t<8;t++ )  q& b1 l2 f' J
  136.         {! i1 U, A0 E0 X8 q9 ^: s: {7 G
  137.                 MPU_IIC_SCL_0();
    . i$ H& ?$ K& b
  138.                 delay_us(2);//等待SDA的变化
    ' B4 H1 }0 h) J9 ?
  139.                 MPU_IIC_SCL_1();
    & `# Y/ r# a! A" {. g3 ^: a
  140.                 7 t- s( ^# E. {. S3 K: O5 n
  141.                 data<<=1;//必须在读取前面,因为之后一位读取后就不再移位
      ~7 {4 m% q0 m7 v8 {$ l  ?
  142.                 if( MPU_IIC_SDA_READ()==1 )
    6 k! B) g& i: N& H0 M" A
  143.                         data++;
    3 r; W! U$ n  s
  144.                
    ( s0 Q6 q8 I% a, {% R- |
  145.                 delay_us(2);//等待SDA的变化
    * o- Z& f( A" j6 |
  146.                
    + ^  D8 b/ Y/ j# F# {7 `/ T0 g
  147.         }# ?: `! U4 I. V' v2 u& C. F

  148. % S( |4 b4 ^  F8 Z" q
  149.         if( !ack )
    5 b4 S; n4 Q% G# l/ V, B: f0 \3 `
  150.                 MPU_IIC_NAck();//发送nACK
    3 M9 J+ J0 `* T3 A
  151.     else
    ' }! z2 c3 j$ _- O6 V; N6 z
  152.         MPU_IIC_Ack(); //发送ACK & P! @; }( ?, p
  153.         return data;6 _# J* \4 O$ n( F$ B0 H3 P$ `) a
  154. }- _" h( b# z5 ?! P# ~

  155. . M( f) s* Q$ s. m% U

  156. 8 d' R- Y7 A( y2 D4 j, y3 t7 W
复制代码

7 w, Y6 ?$ b& O& ~9 V4 W3.mpu6050.c/mpu6050.h
1 c; j; P' J5 k4 {$ Vmpu6050.h
; C5 f: ?' {5 f2 c; W& }1 c: ?主要是定义MPU相关寄存器的地址,和进行函数声明。
4 B! L6 b2 ^; l7 t! \4 B
  1. #ifndef __MPU6050_H5 i, H3 T) ]/ d$ ^3 x
  2. #define __MPU6050_H
    . ?( _8 o" r2 Q3 C. j4 B9 h# G
  3. . R7 j0 l5 }) j7 f4 G
  4. #include "stm32f10x.h"6 B$ B9 Z7 }; l- ?
  5. #include "mpu_iic.h"
    0 I! H' ^1 T0 i  _# d  O+ V
  6. ( X5 `8 R6 @6 t

  7. * @3 I8 L; G6 R- |$ F- ?
  8. /* AD0接地,MPU6050的IIC地址为0x68   接3.3V就为0x69*/
    6 z( l) g4 d+ o/ U6 U
  9. #define MPU_ADDR                                0X68
    4 k9 P) d3 n0 b+ M1 k- \5 o- g

  10. ! X) T3 l# f( h8 G% ?) A7 n# x8 {
  11. /************** MPU6050相关寄存器地址 *********************/
    7 }7 S/ F. z8 Y
  12. #define MPU_ACCEL_OFFS_REG                0X06        //accel_offs寄存器,可读取版本号,寄存器手册未提到' D& z, `* S% N; z2 n8 Z. w+ _
  13. #define MPU_PROD_ID_REG                        0X0C        //prod id寄存器,在寄存器手册未提到0 q4 z2 N1 ]6 i& N: ]  b! ~
  14. #define MPU_SELF_TESTX_REG                0X0D        //自检寄存器X
    " A  P+ }. _8 G. ^
  15. #define MPU_SELF_TESTY_REG                0X0E        //自检寄存器Y
    . F6 u! b6 [( _  z+ b. _0 E. T
  16. #define MPU_SELF_TESTZ_REG                0X0F        //自检寄存器Z7 w" N$ @: a* Y1 r, t! T. R
  17. #define MPU_SELF_TESTA_REG                0X10        //自检寄存器A
    0 W$ a" f6 h) M4 i
  18. #define MPU_SAMPLE_RATE_REG                0X19        //采样频率分频器
    ; _% z1 D2 F; C! \4 ^2 d3 A: b7 F) Q
  19. #define MPU_CFG_REG                                0X1A        //配置寄存器9 i! b  m: M& H( g1 v" M5 i  h
  20. #define MPU_GYRO_CFG_REG                0X1B        //陀螺仪配置寄存器8 H) P  {$ q+ z$ k
  21. #define MPU_ACCEL_CFG_REG                0X1C        //加速度计配置寄存器
    # b" A. |" r1 b3 w0 ]- X6 k0 `  l/ H
  22. #define MPU_MOTION_DET_REG                0X1F        //运动检测阀值设置寄存器8 }  l! T4 M* @1 M6 K  T5 O
  23. #define MPU_FIFO_EN_REG                        0X23        //FIFO使能寄存器
    $ Z! n9 g. e2 G2 H8 r
  24. #define MPU_I2CMST_CTRL_REG                0X24        //IIC主机控制寄存器
    3 k2 t2 d+ n5 J2 w/ o: ]( H& }- H; S
  25. #define MPU_I2CSLV0_ADDR_REG        0X25        //IIC从机0器件地址寄存器
    3 B% O9 T" y0 D. y3 f6 S
  26. #define MPU_I2CSLV0_REG                        0X26        //IIC从机0数据地址寄存器, O- s4 N, @: |$ p$ G# v1 Y
  27. #define MPU_I2CSLV0_CTRL_REG        0X27        //IIC从机0控制寄存器
    * k5 C: y8 X' }3 a9 S) R) O8 T! l  n
  28. #define MPU_I2CSLV1_ADDR_REG        0X28        //IIC从机1器件地址寄存器
    4 x* g$ u% O4 n' K5 K( S
  29. #define MPU_I2CSLV1_REG                        0X29        //IIC从机1数据地址寄存器6 b" B9 g" F" H
  30. #define MPU_I2CSLV1_CTRL_REG        0X2A        //IIC从机1控制寄存器
    9 q  p4 Q- P" J, o
  31. #define MPU_I2CSLV2_ADDR_REG        0X2B        //IIC从机2器件地址寄存器- ?+ E4 Z7 s) Y, P- U5 o
  32. #define MPU_I2CSLV2_REG                        0X2C        //IIC从机2数据地址寄存器/ Z0 o, k# s$ P. ?' A) w
  33. #define MPU_I2CSLV2_CTRL_REG        0X2D        //IIC从机2控制寄存器6 ^5 C# E5 ^0 P3 S8 h4 {
  34. #define MPU_I2CSLV3_ADDR_REG        0X2E        //IIC从机3器件地址寄存器  j2 z# `6 z9 Y. ~/ |7 d
  35. #define MPU_I2CSLV3_REG                        0X2F        //IIC从机3数据地址寄存器, Y. g. o" \$ }0 V9 M3 E$ x
  36. #define MPU_I2CSLV3_CTRL_REG        0X30        //IIC从机3控制寄存器
    3 d- s+ r; Q$ n2 p
  37. #define MPU_I2CSLV4_ADDR_REG        0X31        //IIC从机4器件地址寄存器) P# I) b* R1 U' d; ]  s  A/ ]: e8 s
  38. #define MPU_I2CSLV4_REG                        0X32        //IIC从机4数据地址寄存器) S, d( ?& g  W
  39. #define MPU_I2CSLV4_DO_REG                0X33        //IIC从机4写数据寄存器! {6 ^$ @( C, i& m7 r& p1 C0 ?: T4 J
  40. #define MPU_I2CSLV4_CTRL_REG        0X34        //IIC从机4控制寄存器
    3 |+ U! ], p* m! r& g( W* _3 g% @
  41. #define MPU_I2CSLV4_DI_REG                0X35        //IIC从机4读数据寄存器
    5 ?6 n& D0 L, s" ~- @

  42. ! k/ @. l- m+ t
  43. #define MPU_I2CMST_STA_REG                0X36        //IIC主机状态寄存器) ^* y$ I8 X( w& X' _6 z
  44. #define MPU_INTBP_CFG_REG                0X37        //中断/旁路设置寄存器# R& n( K) ~2 q& E9 h
  45. #define MPU_INT_EN_REG                        0X38        //中断使能寄存器
    0 N5 Q) u+ t: X2 g- U. Z
  46. #define MPU_INT_STA_REG                        0X3A        //中断状态寄存器
    . y  x: |# h1 @* j3 J0 w/ n/ U

  47. 6 s  z1 C  [0 }4 B, u
  48. #define MPU_ACCEL_XOUTH_REG                0X3B        //加速度值,X轴高8位寄存器" [2 [( G" @8 l/ b: z6 D
  49. #define MPU_ACCEL_XOUTL_REG                0X3C        //加速度值,X轴低8位寄存器% y* t. S- z3 x) t8 a" ^
  50. #define MPU_ACCEL_YOUTH_REG                0X3D        //加速度值,Y轴高8位寄存器  ~; c- j( ]% @/ Z
  51. #define MPU_ACCEL_YOUTL_REG                0X3E        //加速度值,Y轴低8位寄存器
      E/ Q, M  s+ l
  52. #define MPU_ACCEL_ZOUTH_REG                0X3F        //加速度值,Z轴高8位寄存器2 p) \, U5 d/ r4 Q
  53. #define MPU_ACCEL_ZOUTL_REG                0X40        //加速度值,Z轴低8位寄存器
    / G8 l0 o% E  H, [4 j7 i% p

  54. 7 W' [$ p! u0 q# M2 G5 e
  55. #define MPU_TEMP_OUTH_REG                0X41        //温度值高八位寄存器
    & C& }. u) M8 b# O
  56. #define MPU_TEMP_OUTL_REG                0X42        //温度值低8位寄存器7 n/ A% H3 `& j3 U' O

  57. ( @$ w3 n% o+ {& m! q) I
  58. #define MPU_GYRO_XOUTH_REG                0X43        //陀螺仪值,X轴高8位寄存器
    ( b* l3 e' N/ j) A9 e3 A
  59. #define MPU_GYRO_XOUTL_REG                0X44        //陀螺仪值,X轴低8位寄存器# `2 F% D/ o: n  t) \5 K3 C
  60. #define MPU_GYRO_YOUTH_REG                0X45        //陀螺仪值,Y轴高8位寄存器( o9 C/ v! H$ v7 q1 w6 y
  61. #define MPU_GYRO_YOUTL_REG                0X46        //陀螺仪值,Y轴低8位寄存器" b. X1 U3 X6 t
  62. #define MPU_GYRO_ZOUTH_REG                0X47        //陀螺仪值,Z轴高8位寄存器) n% L: i+ Q+ L+ p: r2 \6 J. {) I: ?
  63. #define MPU_GYRO_ZOUTL_REG                0X48        //陀螺仪值,Z轴低8位寄存器" C6 G6 q7 S) f3 S. E

  64. 9 @" a% M5 B7 o, z( h) ^7 J
  65. #define MPU_I2CSLV0_DO_REG                0X63        //IIC从机0数据寄存器0 q# h/ N: w5 [0 [
  66. #define MPU_I2CSLV1_DO_REG                0X64        //IIC从机1数据寄存器
    ' X7 _* N- a+ Y" D9 z0 B
  67. #define MPU_I2CSLV2_DO_REG                0X65        //IIC从机2数据寄存器; G% F# e8 k6 v  M
  68. #define MPU_I2CSLV3_DO_REG                0X66        //IIC从机3数据寄存器9 T: X8 P/ V8 {: |2 C
  69. $ M% \% c* x* n. Y; o8 k0 y. I  E
  70. #define MPU_I2CMST_DELAY_REG        0X67        //IIC主机延时管理寄存器
    - l0 P) J. S' [% O6 G  x: Q/ b* ~
  71. #define MPU_SIGPATH_RST_REG                0X68        //信号通道复位寄存器
    ; v" T- I, _8 H8 j5 t# y1 m) `  K
  72. #define MPU_MDETECT_CTRL_REG        0X69        //运动检测控制寄存器3 D$ C- r1 g! f; ?
  73. #define MPU_USER_CTRL_REG                0X6A        //用户控制寄存器
    % U* F6 z" T% p) P# d
  74. #define MPU_PWR_MGMT1_REG                0X6B        //电源管理寄存器1
    5 a4 j2 D' U5 t$ F0 g. G  q
  75. #define MPU_PWR_MGMT2_REG                0X6C        //电源管理寄存器2 5 k7 |- ?# b7 M; A2 ^
  76. #define MPU_FIFO_CNTH_REG                0X72        //FIFO计数寄存器高八位
    4 J4 D& b& J& [4 b/ c" l
  77. #define MPU_FIFO_CNTL_REG                0X73        //FIFO计数寄存器低八位# l2 }/ k* y0 C* l- G
  78. #define MPU_FIFO_RW_REG                        0X74        //FIFO读写寄存器1 l7 U' C: u9 B1 U1 u0 e/ v
  79. #define MPU_DEVICE_ID_REG                0X75        //器件ID寄存器% R3 p  q! [4 i, H

  80. $ Y* u' h- w# R. H2 S

  81. ! c' v) Y. c! c6 a  q+ J

  82. 1 q$ ?4 d! |1 c6 K" o- a/ a

  83. 0 J1 c* s) t' C% f. S! a
  84. /* 函数声明 */( o! R5 v0 K. [6 L+ H  X9 ^
  85. uint8_t MPU_Read_Byte( uint8_t reg );9 }! j# i: k( G) U1 {6 h
  86. uint8_t MPU_Write_Byte( uint8_t reg, uint8_t data );
    0 [7 v8 v7 x% f! o
  87. uint8_t MPU_Read_Continue( uint8_t addr, uint8_t reg, uint8_t len, uint8_t *buf );, L) V3 G; F7 P* ]- v6 _* a9 l
  88. uint8_t MPU_Write_Continue( uint8_t addr, uint8_t reg, uint8_t len, uint8_t *buf );
    7 g* p, e5 ]" ?. |% f

  89. 2 R% j* p* l# ~0 Q, a
  90. uint8_t MPU_Init( void );
    ) [- R( o; }4 P, y  h  g7 C$ V
  91. . b6 ~4 B# ~2 e7 L
  92. 0 o+ s* F# Z( \5 ]  |5 {' E
  93. uint8_t MPU_Set_Gyro_Fsr( uint8_t fsr );9 t4 L/ d( F9 T
  94. uint8_t MPU_Set_Accel_Fsr( uint8_t fsr );
    : f; K( U3 I2 D0 h
  95. uint8_t MPU_Set_LPF( uint16_t lpf );
    % A+ j" ~% h  y( x2 w9 N
  96. uint8_t MPU_Set_Rate( uint16_t rate );
    6 _. \- E5 O) i1 X( n$ N
  97. short MPU_Get_Temperature( void );+ f% V- N( V% m: t; _8 o
  98. uint8_t MPU_Get_Gyroscope( short *gx, short *gy, short *gz );
    6 z# r. G5 S0 N) s# p
  99. uint8_t MPU_Get_Accelerometer( short *ax, short *ay, short *az );$ Z0 {, l! v9 D" i: I
  100. 9 J7 Q/ x4 C' V+ a, ?% c# I/ R
  101. #endif
    ) P. R1 @6 G! S3 E6 Z% E
  102. 1 |0 u; Z" e- [5 ]
复制代码

' d( f' C8 i7 T5 Z! r  [mpu6050.c
0 Z+ \) m, M% T, m最为重要的一部分代码,包括了对MPU6050的一系列基本配置和读取原始数据的操作,代码都注解的很详细了。. R% |) |2 j3 T( ?1 J$ S. l7 x
AD0引脚用了PA15,所以要GPIO_Remap_SWJ_JTAGDisable,换个引脚也可以。
: q5 z: i; x* e* S  ~6 L
  1. #ifndef __MPU6050_H
    1 i& E& O' q/ y! }7 }- K2 j
  2. #define __MPU6050_H
    . F9 I& e1 f" |, q" k

  3. ; M0 P, I3 L" K: K4 J
  4. #include "stm32f10x.h"0 L7 H( K, _9 i! f
  5. #include "mpu_iic.h"
    # G# F' s4 c: m' h* D) q6 {
  6. 0 e* U0 J+ O5 \3 p8 t( ^0 R: P; h

  7. 3 B+ ?) b2 J* V3 }! U# Y' x
  8. /* AD0接地,MPU6050的IIC地址为0x68   接3.3V就为0x69*/& s$ B% e( K& _, ]6 r8 V: V
  9. #define MPU_ADDR                                0X68  z0 D) u& l% C( P" e

  10. % c! T, K- ~9 T1 P8 P
  11. /************** MPU6050相关寄存器地址 *********************/
    * x/ C6 E: C  E9 s  q9 L
  12. #define MPU_ACCEL_OFFS_REG                0X06        //accel_offs寄存器,可读取版本号,寄存器手册未提到
    / F9 J! B/ i6 w3 k/ \' {3 M
  13. #define MPU_PROD_ID_REG                        0X0C        //prod id寄存器,在寄存器手册未提到
    % P  T5 R, C/ e) Y1 Z1 x
  14. #define MPU_SELF_TESTX_REG                0X0D        //自检寄存器X8 q. F1 e% b1 P6 G% e1 q
  15. #define MPU_SELF_TESTY_REG                0X0E        //自检寄存器Y+ Q" L0 z3 ]& X
  16. #define MPU_SELF_TESTZ_REG                0X0F        //自检寄存器Z
    0 R3 j9 h9 t3 _5 b- q6 V6 U
  17. #define MPU_SELF_TESTA_REG                0X10        //自检寄存器A: {- S9 J( j# u: a
  18. #define MPU_SAMPLE_RATE_REG                0X19        //采样频率分频器% ?; P' N/ }0 c4 P) B0 m9 U
  19. #define MPU_CFG_REG                                0X1A        //配置寄存器: ]' A1 w3 y6 Q
  20. #define MPU_GYRO_CFG_REG                0X1B        //陀螺仪配置寄存器
    0 ]( K% _' w  M7 v6 h& w  [
  21. #define MPU_ACCEL_CFG_REG                0X1C        //加速度计配置寄存器+ v5 V$ D4 E# d: P1 R
  22. #define MPU_MOTION_DET_REG                0X1F        //运动检测阀值设置寄存器- w$ T/ d* v4 k9 V! r; y: t  P9 _$ w+ T
  23. #define MPU_FIFO_EN_REG                        0X23        //FIFO使能寄存器. P/ I  }9 u! g& m+ ]
  24. #define MPU_I2CMST_CTRL_REG                0X24        //IIC主机控制寄存器
    + v$ |6 f0 @+ u0 N4 R
  25. #define MPU_I2CSLV0_ADDR_REG        0X25        //IIC从机0器件地址寄存器
    ! j, z- T- g; l* Z# d9 ?* L
  26. #define MPU_I2CSLV0_REG                        0X26        //IIC从机0数据地址寄存器
    : Z  U' R# j" K1 h# G8 y3 d
  27. #define MPU_I2CSLV0_CTRL_REG        0X27        //IIC从机0控制寄存器
    2 X# l2 D! s+ U
  28. #define MPU_I2CSLV1_ADDR_REG        0X28        //IIC从机1器件地址寄存器; h' r" C( M0 r5 G. o
  29. #define MPU_I2CSLV1_REG                        0X29        //IIC从机1数据地址寄存器% s/ v: O4 d% J; c* F- [9 K
  30. #define MPU_I2CSLV1_CTRL_REG        0X2A        //IIC从机1控制寄存器% M$ l( f2 d# {6 U& L- l+ S
  31. #define MPU_I2CSLV2_ADDR_REG        0X2B        //IIC从机2器件地址寄存器2 I: r: x# T3 t: Y7 Q7 m- n
  32. #define MPU_I2CSLV2_REG                        0X2C        //IIC从机2数据地址寄存器
    2 _. _& U7 X+ y& M+ e9 n( x
  33. #define MPU_I2CSLV2_CTRL_REG        0X2D        //IIC从机2控制寄存器
    1 U$ ?+ e# V# a7 l! }& I8 q
  34. #define MPU_I2CSLV3_ADDR_REG        0X2E        //IIC从机3器件地址寄存器2 ^5 A: G6 x! K0 `" @; U
  35. #define MPU_I2CSLV3_REG                        0X2F        //IIC从机3数据地址寄存器% Q$ p* x- m5 m+ I4 N% `
  36. #define MPU_I2CSLV3_CTRL_REG        0X30        //IIC从机3控制寄存器
    9 m  d! S) f. Y( Z
  37. #define MPU_I2CSLV4_ADDR_REG        0X31        //IIC从机4器件地址寄存器* D/ H+ `% i( s; s: q8 v
  38. #define MPU_I2CSLV4_REG                        0X32        //IIC从机4数据地址寄存器' M$ @9 T5 f8 V5 b- A/ V: D! X
  39. #define MPU_I2CSLV4_DO_REG                0X33        //IIC从机4写数据寄存器! T# d6 S0 S  A+ E% o7 t3 E
  40. #define MPU_I2CSLV4_CTRL_REG        0X34        //IIC从机4控制寄存器* S& B2 k$ P/ K, ?' J
  41. #define MPU_I2CSLV4_DI_REG                0X35        //IIC从机4读数据寄存器
    . X  f8 M2 f" _( f! ]) w- m
  42. # ~  o7 }) V- Z. ~
  43. #define MPU_I2CMST_STA_REG                0X36        //IIC主机状态寄存器9 v, [9 U0 q0 P' K, Z1 O( `
  44. #define MPU_INTBP_CFG_REG                0X37        //中断/旁路设置寄存器0 i$ j( u" _0 g2 I& @7 Q* S
  45. #define MPU_INT_EN_REG                        0X38        //中断使能寄存器/ A1 {7 O  V9 K' }
  46. #define MPU_INT_STA_REG                        0X3A        //中断状态寄存器
    3 B8 c, m6 f7 `2 Z

  47. . O) q# E5 U, R$ M! v  Z
  48. #define MPU_ACCEL_XOUTH_REG                0X3B        //加速度值,X轴高8位寄存器* O4 P! n# D/ `$ _! `/ `4 ]5 z
  49. #define MPU_ACCEL_XOUTL_REG                0X3C        //加速度值,X轴低8位寄存器
    % p' v) P2 O7 I0 A& d
  50. #define MPU_ACCEL_YOUTH_REG                0X3D        //加速度值,Y轴高8位寄存器
    5 g) `4 r& G2 t' b' ^. C  d. p
  51. #define MPU_ACCEL_YOUTL_REG                0X3E        //加速度值,Y轴低8位寄存器) C& ?- T4 Q& a# a; u- B
  52. #define MPU_ACCEL_ZOUTH_REG                0X3F        //加速度值,Z轴高8位寄存器
    2 h' n2 ?1 N" Y$ P7 L
  53. #define MPU_ACCEL_ZOUTL_REG                0X40        //加速度值,Z轴低8位寄存器
    ) t! [- o# {" y

  54. : V) \9 _/ n6 p+ x( O9 p
  55. #define MPU_TEMP_OUTH_REG                0X41        //温度值高八位寄存器, z! q  y* `9 h" |
  56. #define MPU_TEMP_OUTL_REG                0X42        //温度值低8位寄存器. C: A( y5 p) E2 ?  n) ?7 ?

  57. - Y9 r- r: M' ]1 X  `7 o0 d+ B
  58. #define MPU_GYRO_XOUTH_REG                0X43        //陀螺仪值,X轴高8位寄存器0 r. G, Q/ N+ u: N1 n, P8 A+ }; I
  59. #define MPU_GYRO_XOUTL_REG                0X44        //陀螺仪值,X轴低8位寄存器
    3 e3 j6 }1 j+ _
  60. #define MPU_GYRO_YOUTH_REG                0X45        //陀螺仪值,Y轴高8位寄存器6 v; w$ O, _, y  @9 U2 g2 k
  61. #define MPU_GYRO_YOUTL_REG                0X46        //陀螺仪值,Y轴低8位寄存器
    - }( f  J7 Y2 s( N5 j2 U4 W2 Q' q
  62. #define MPU_GYRO_ZOUTH_REG                0X47        //陀螺仪值,Z轴高8位寄存器
    0 h5 t  n% M# @) m; m7 G
  63. #define MPU_GYRO_ZOUTL_REG                0X48        //陀螺仪值,Z轴低8位寄存器
    1 M# J# U2 ^! X) C( `2 {

  64. % v) p. i: M: A& g1 Y1 N; j
  65. #define MPU_I2CSLV0_DO_REG                0X63        //IIC从机0数据寄存器
    , x  c# @7 i, c* N, {. q
  66. #define MPU_I2CSLV1_DO_REG                0X64        //IIC从机1数据寄存器3 A: J5 |" D7 |" V+ M' S
  67. #define MPU_I2CSLV2_DO_REG                0X65        //IIC从机2数据寄存器
    + N3 c" a+ j" y( ]5 e4 ^$ q6 ?( [
  68. #define MPU_I2CSLV3_DO_REG                0X66        //IIC从机3数据寄存器6 L. H+ j: J5 P

  69. : u# l7 v4 V+ p/ s
  70. #define MPU_I2CMST_DELAY_REG        0X67        //IIC主机延时管理寄存器( _. d. D" I1 r) d' H* e, g2 o
  71. #define MPU_SIGPATH_RST_REG                0X68        //信号通道复位寄存器
    : K" Y4 L, [# m/ n
  72. #define MPU_MDETECT_CTRL_REG        0X69        //运动检测控制寄存器5 m/ J2 q, r- F, k
  73. #define MPU_USER_CTRL_REG                0X6A        //用户控制寄存器# A; g3 Z8 V( L" J5 Y5 b  g
  74. #define MPU_PWR_MGMT1_REG                0X6B        //电源管理寄存器1
    5 v& a2 W9 {$ v+ m7 w7 p, w
  75. #define MPU_PWR_MGMT2_REG                0X6C        //电源管理寄存器2
    1 R& V4 b) e% `; Q$ c& S
  76. #define MPU_FIFO_CNTH_REG                0X72        //FIFO计数寄存器高八位
    # i% o" d; S/ U$ f7 g. w% K4 @( P, H
  77. #define MPU_FIFO_CNTL_REG                0X73        //FIFO计数寄存器低八位
    & ^0 J; `$ T: D* P+ G7 v
  78. #define MPU_FIFO_RW_REG                        0X74        //FIFO读写寄存器9 Y# ^* B  d- c5 L  x2 Q
  79. #define MPU_DEVICE_ID_REG                0X75        //器件ID寄存器
    " g, T# ?( Z7 d1 U3 ?
  80. 1 O! J3 B& X% H. I) C- N7 B
  81. ) ^+ W& t# E, y1 G+ X2 P$ z, `
  82. 2 _# x6 \+ B8 v4 m! X

  83. * O& m" v/ i' j! J8 B' u8 l
  84. /* 函数声明 */3 |7 U- a5 P- B, e' S* H! j) {3 v4 j
  85. uint8_t MPU_Read_Byte( uint8_t reg );2 Q7 ^7 Y5 J5 Y! ]& I/ n
  86. uint8_t MPU_Write_Byte( uint8_t reg, uint8_t data );
    2 }/ ?6 u5 Q% l+ q2 d
  87. uint8_t MPU_Read_Continue( uint8_t addr, uint8_t reg, uint8_t len, uint8_t *buf );. j- E$ y8 }+ [9 C+ q! b8 M9 k
  88. uint8_t MPU_Write_Continue( uint8_t addr, uint8_t reg, uint8_t len, uint8_t *buf );
    6 z3 u4 `8 q5 W7 b7 {6 L( q
  89. : q" S& ~& X4 W( D/ [" R) ~  i
  90. uint8_t MPU_Init( void );
    ' A% i9 v% Q( p7 u+ a+ @( c
  91. 6 v8 j! \4 d- t+ G4 F

  92. ( ]* n. a" s$ s, j1 Q) G7 l
  93. uint8_t MPU_Set_Gyro_Fsr( uint8_t fsr );
    8 W+ ?) z/ _: H* f7 d
  94. uint8_t MPU_Set_Accel_Fsr( uint8_t fsr );
    # l1 f; M' C% R+ ^  F3 j3 J
  95. uint8_t MPU_Set_LPF( uint16_t lpf );
    8 A3 c' \1 G, b* G* x, |( x
  96. uint8_t MPU_Set_Rate( uint16_t rate );
    $ ~* H7 ?  d4 C7 U$ v7 D3 X. y/ @
  97. short MPU_Get_Temperature( void );
    3 H5 t  I" F! ?% b5 X) s/ n
  98. uint8_t MPU_Get_Gyroscope( short *gx, short *gy, short *gz );
    9 O. ?( ^$ {) ^6 O
  99. uint8_t MPU_Get_Accelerometer( short *ax, short *ay, short *az );
      Y/ [6 y/ W5 i: m+ ?. F
  100. 0 q- ]& z" j# u' P) ?" n
  101. #endif
    ( f3 X6 ?0 J% A2 n  U7 w
  102. 8 U4 ]4 d6 _4 ?
复制代码

! C+ _8 @8 I, J0 M/ c3 @, u4.DMP相关代码+ T# G1 [7 _, H& u  t0 L
要想使用DMP求欧拉角的代码,包含下面这几个文件即可,下面列出接口函数,到时候使用时直接使用接口函数即可。: R- c0 b! I+ M& O

5 b0 {+ y1 q( Q' U- I: X6 B
20200215175340295.png 9 o- X1 U+ w/ V& H" p- B# F' _& q

; _, g' f8 N: \0 g: B6 c) s向DMP算法提供的接口宏定义
6 t4 H7 Q( q6 r) A% m) o只需要提供:对MPU6050的读写操作函数和延时函数即可: r2 U/ ~/ O) u- U7 _
  1. #define i2c_write   MPU_Write_Continue
    5 m/ }2 U5 K; A# h5 [9 v
  2. #define i2c_read    MPU_Read_Continue- m  T" ?6 f- O3 p6 E: _
  3. #define delay_ms    delay_ms
    - G$ v$ w3 f. u: Z! v+ d. j, {
复制代码

, k" U0 B6 h) {+ d9 c; ADMP初始化
: Z& V# \" T) |$ T/ Y. Y( J
  1. //mpu6050,dmp初始化, r) V8 h* B4 Q. z
  2. //返回值:0,正常
    0 U9 E( F% E& ]0 n+ S
  3. //    其他,失败/ P2 l: f, e  T" z4 D
  4. uint8_t mpu_dmp_init(void)  I! V( G+ m& e* n& e$ @
  5. {
    : \/ ]. G$ G' C: m  N/ N' J
  6.         uint8_t res=0;
    ; t1 j# q. `8 d( H
  7.         MPU_IIC_Init();         //初始化IIC总线2 z1 c  ?8 E: ~- B* k" H6 E
  8.         if(mpu_init()==0)        //初始化MPU6050' G. ~! T# J6 r+ {
  9.         {         , x5 C9 M- K/ _* `1 y0 V/ `8 [% T
  10.                 res=mpu_set_sensors(INV_XYZ_GYRO|INV_XYZ_ACCEL);//设置所需要的传感器' `, p' L$ v- [* n0 n' E
  11.                 if(res)return 1;
    6 P  ~9 g% p/ a! l7 _
  12.                 res=mpu_configure_fifo(INV_XYZ_GYRO|INV_XYZ_ACCEL);//设置FIFO9 M/ a" f& g) Z' g4 ], G5 p: y
  13.                 if(res)return 2;
    & Z: r$ C9 `+ R0 U$ Z% V
  14.                 res=mpu_set_sample_rate(DEFAULT_MPU_HZ);        //设置采样率; N- D1 t  m- Y" X
  15.                 if(res)return 3; . G/ @, Y) K+ W' i
  16.                 res=dmp_load_motion_driver_firmware();                //加载dmp固件
    ) ~5 e+ T* U% S, T
  17.                 if(res)return 4; ; q0 `- T( f7 r  J6 f
  18.                 res=dmp_set_orientation(inv_orientation_matrix_to_scalar(gyro_orientation));//设置陀螺仪方向
    2 x, Z% z7 }8 e( m. C
  19.                 if(res)return 5;
    8 K# n5 n8 _1 z% W) m, e& }
  20.                 res=dmp_enable_feature(DMP_FEATURE_6X_LP_QUAT|DMP_FEATURE_TAP|        //设置dmp功能( Y3 s9 l  @" Z
  21.                     DMP_FEATURE_ANDROID_ORIENT|DMP_FEATURE_SEND_RAW_ACCEL|DMP_FEATURE_SEND_CAL_GYRO|
    % T/ W* N" ]$ f# ]2 i
  22.                     DMP_FEATURE_GYRO_CAL);
    3 Y- ]* K1 x& T" K  p9 j5 L
  23.                 if(res)return 6; " D% x& b6 U* ?" W8 l4 x! n/ N0 P
  24.                 res=dmp_set_fifo_rate(DEFAULT_MPU_HZ);        //设置DMP输出速率(最大不超过200Hz)
    $ c; \, ?6 A' `* f  ~6 {- W8 _8 t
  25.                 if(res)return 7;   5 t9 U5 ~3 \8 z! _7 Z8 I$ U
  26.                 res=run_self_test();                //自检
    8 F5 a8 e" Z+ r4 w' f: L# V6 t9 \# H3 i
  27.                 if(res)return 8;    & h9 A( l, U" g/ C
  28.                 res=mpu_set_dmp_state(1);        //使能DMP
    8 S, O8 [3 m3 _/ Y* `* f3 i& E  D; u* M
  29.                 if(res)return 9;     
    % x+ h1 C! ?! P# b- w$ n2 G7 h+ p
  30.         }else return 10;+ D' H9 b2 C, ?7 q
  31.         return 0;
    & a; S5 l! H/ S9 g7 E: q6 a
  32. }, H) X, c/ {5 a* N
复制代码
; x. }6 a5 k4 ]% Z6 U0 h6 p
获取欧拉角
* u) M8 K# v/ f8 G7 g- ^) k# w
  1. //得到dmp处理后的数据(注意,本函数需要比较多堆栈,局部变量有点多)0 G, [/ B- {4 q4 E7 r  e; }
  2. //pitch:俯仰角 精度:0.1°   范围:-90.0° <---> +90.0°7 l; {( [* L4 Y5 P8 Z: ?1 @8 w  O
  3. //roll:横滚角  精度:0.1°   范围:-180.0°<---> +180.0°8 C3 M  Z; G( v1 t
  4. //yaw:航向角   精度:0.1°   范围:-180.0°<---> +180.0°' Z6 u1 H7 r$ p& A' J
  5. //返回值:0,正常4 v7 M( Q  u& ?1 n% z8 h
  6. //    其他,失败$ N- [, @8 T! h  i& D6 X4 L% _# P
  7. uint8_t mpu_dmp_get_data(float *pitch,float *roll,float *yaw)7 ]/ b( L# `) s- Z+ T
  8. {% I( M2 J4 K) b: C8 e
  9.         float q0=1.0f,q1=0.0f,q2=0.0f,q3=0.0f;+ L: c+ ^- b& z+ s/ i
  10.         unsigned long sensor_timestamp;; c. }3 s) ?# o; ]' L1 W! H
  11.         short gyro[3], accel[3], sensors;1 Z* R4 [, h, p- @9 Z7 }
  12.         unsigned char more;8 T) N6 \/ U- t
  13.         long quat[4]; 9 u: o4 n9 ^6 Z% l! z( T7 l/ f! W
  14.         if(dmp_read_fifo(gyro, accel, quat, &sensor_timestamp, &sensors,&more))return 1;         
    0 Y7 `8 R0 J! q/ _1 Q( L
  15.         /* Gyro and accel data are written to the FIFO by the DMP in chip frame and hardware units., w! E- b/ w( j7 X, X) F
  16.          * This behavior is convenient because it keeps the gyro and accel outputs of dmp_read_fifo and mpu_read_fifo consistent.
    9 Y' X1 l* o  M- L6 r; y$ L
  17.         **/
    & X* @& M# {  C/ ]/ ]! R
  18.         /*if (sensors & INV_XYZ_GYRO ): w" a% l7 B9 Y+ O7 [9 s
  19.         send_packet(PACKET_TYPE_GYRO, gyro);3 w  {, o9 a4 x2 O
  20.         if (sensors & INV_XYZ_ACCEL)# v) Y8 Z: t0 f/ r$ H- B
  21.         send_packet(PACKET_TYPE_ACCEL, accel); *// V  b7 {1 L" ~5 Y7 o" w7 A
  22.         /* Unlike gyro and accel, quaternions are written to the FIFO in the body frame, q30.
    : n( N$ O* B3 ^5 ~; k3 d
  23.          * The orientation is set by the scalar passed to dmp_set_orientation during initialization. * {. A% w. C0 x) V6 p! U( B  |
  24.         **/
    ; N! g3 B% `4 a. ?% {+ v
  25.         if(sensors&INV_WXYZ_QUAT) 5 B' b7 q) g9 e) Y
  26.         {
    6 \' d( e) X$ o* \5 r3 e
  27.                 q0 = quat[0] / q30;        //q30格式转换为浮点数
    8 f% D- o7 [4 \! }, g  c- M# [" N' D
  28.                 q1 = quat[1] / q30;2 |' B# r+ k, W2 Q4 \
  29.                 q2 = quat[2] / q30;
    + ]+ U1 ^9 ^/ k% M& O) @
  30.                 q3 = quat[3] / q30;
    $ d. }: O, D5 W  O
  31.                 //计算得到俯仰角/横滚角/航向角
    2 S" V4 d" Y- a, u9 H, |
  32.                 *pitch = asin(-2 * q1 * q3 + 2 * q0* q2)* 57.3;        // pitch
    9 Q+ f) M# r2 n
  33.                 *roll  = atan2(2 * q2 * q3 + 2 * q0 * q1, -2 * q1 * q1 - 2 * q2* q2 + 1)* 57.3;        // roll
    , [! b1 g: C0 n& F
  34.                 *yaw   = atan2(2*(q1*q2 + q0*q3),q0*q0+q1*q1-q2*q2-q3*q3) * 57.3;        //yaw
    / r% ]5 R: N4 T$ [. a1 E0 s$ `! ~
  35.         }else return 2;" v6 e5 A* s9 _# q" n
  36.         return 0;  k2 N. r9 |& G8 s! C! Z; O
  37. }
    . L( a* k$ R  M" g6 D/ E
  38. / z; d3 ~+ C! a" n
复制代码

0 P! \" t$ _) r# p5.mian()函数& j: ^. w$ V0 P* j- u; `! @2 T6 l) S/ C
主函数中对MPU6050进行初始化后,对DMP也进行初始化,然后就可以直接使用mpu_dmp_get_data()获取欧拉角,还可以获取温度值。
: |* ]! P4 N2 v  E' O3 |  k" Y4 Q
  1. #include "stm32f10x.h"   , c+ M( g, ^6 D; K
  2. #include "usart.h"
    % w# g# i& n1 [: ^, H( H
  3. #include "delay.h"
      R% `7 Y. ~' U' w# N( [* a8 r
  4. #include "mpu6050.h"
    8 v: T2 y2 j( p( g- W- i  y" Q/ Z
  5. #include "inv_mpu.h"/ W' p' t$ d9 n( u  q
  6. #include "inv_mpu_dmp_motion_driver.h"
    4 T/ H; W5 J- l6 O' o# t

  7. 6 o- z! @: I! P4 j: k# B
  8. int main(void)
    4 P2 e# T7 @% a1 D; z7 L% [
  9. {
    # H! `- E' G, i- w9 A; _8 B- Q% f
  10.         uint8_t x=0;
    * r+ c# Y8 a* ~) R$ M
  11.         float pitch,roll,yaw;                 //欧拉角
    . o6 Z5 i+ q1 A) i7 C) g
  12.         short aacx,aacy,aacz;                //加速度传感器原始数据
    " l3 f5 u8 _, ?5 M. e) I
  13.         short gyrox,gyroy,gyroz;        //陀螺仪原始数据9 ^! P! Y9 F: \# w' i0 J1 s0 O
  14.         short temp;                                        //温度# k! K& ?$ C1 T& s( b( s6 l
  15.        
    / x; b/ f. M" ]
  16.         NVIC_PriorityGroupConfig( 2 );
    7 Q; o. \, X% _$ b
  17.         delay_init();
    & }- Q9 S( l- g' X( Y4 L! M
  18.         USART1_Init(115200);        8 Q6 N7 U/ a6 D$ ^8 O
  19.         printf("程序开始\n");
    : E6 ]% W* ]4 P' B& j
  20.         $ z0 f7 b9 j. k: S/ o4 O
  21.         if( MPU_Init()!=0 )
    + J4 l3 w  j: z; p: t# v, j
  22.         {
    " e; w0 L' w5 Z* r# J, O- E$ U) |
  23.                 printf("MPU6050初始化错误!\n");
    + @6 ^0 H( b0 a5 q/ _9 {
  24.                 return 0;8 E' P" s1 R7 a9 }& j+ {+ J, m" ^
  25.         }
    ) |5 ?: g9 e) K
  26.                
    4 @- i. c. I$ n& u; ]+ e8 U! {
  27.         if( mpu_dmp_init() )
    6 @& P1 b# Z8 t# a  T8 r& C
  28.         {
    , G- Y; {: |3 t9 J, C9 I
  29.                 printf("DMP初始化错误!\n");2 i( M# Q, S1 P& C8 g' ]5 D0 {! A
  30.                 return 0;
    ( `/ L! C+ L' I3 K% O. G& @
  31.         }/ l6 k6 g, Q+ m) c% ?
  32.         while(1)
    * g/ e6 L# m3 Q6 A, k8 B
  33.         {& |  X' {4 x% D( K
  34.                 if(mpu_dmp_get_data(&pitch,&roll,&yaw)==0)
    ( h5 `, v# Y  A
  35.                 {
    5 F/ n; x& D! F0 A2 ^- m* p
  36.                         temp=MPU_Get_Temperature();        //得到温度值
    " y2 I1 o& v* ^( y; t
  37.                         MPU_Get_Accelerometer(&aacx,&aacy,&aacz);        //得到加速度传感器数据: _* d/ u' d. G5 c
  38.                         MPU_Get_Gyroscope(&gyrox,&gyroy,&gyroz);        //得到陀螺仪数据
    0 P% c' Q7 E. X+ |
  39.                 }6 Y+ k5 v5 B( G4 b7 K5 c$ o, T
  40.                 delay_ms(100);! N' X( W6 X7 N7 T8 E' b
  41.                 printf("pitch:%02f  roll:%02f  yaw:%02f\n",pitch,roll,yaw);
    & D1 Z  P0 }$ Q) T. s! i
  42.         }
      q: U5 a$ E1 c) z

  43. * M; l0 O- B. i* Y2 p6 o
  44. }
    1 ^: q! l. f  M
复制代码
$ g: M' {5 N) u5 q( o
这就是我理解的MPU6050,后续做平衡小车的时候要读取欧拉角,先总结一下
7 ]1 ]' W$ w! Q4 |' {% T  B. f" H————————————————
# X& x" J) z3 F8 ]& ?版权声明:Aspirant-GQ- d2 i/ h) |- u% Q& n5 d6 }
如有侵权请联系删除* n% a  _; c6 }" C+ T) T! |
0 `3 W; Q, @; w/ j$ l2 W! k9 Z

, B  J# _6 M. s. D5 u
收藏 评论0 发布时间:2023-3-18 12:25

举报

0个回答

所属标签

相似分享

官网相关资源

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