一.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
+ 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
* 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 yXCL、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
( 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
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
& 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
% 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
' 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 s5 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
+ \" 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- #ifndef __MPU_IIC_H0 ?- V- f ?2 y9 Q/ I$ z3 z' ~/ U
- #define __MPU_IIC_H. O& m% Y& v0 j a! t
1 \ m, e$ s: ^* P& _; @- #include "stm32f10x.h"
2 n+ O& y+ A5 o% E; W& ?& R - #include "delay.h"
\4 Y" L7 O- ]$ I) Y& Q - 3 D% a/ \# ?$ y; `# J
- /* 宏定义引脚电平操作函数 */% j! D: C7 s9 f, ?, G1 t* l# c) X
- #define MPU_SDA_IN() {GPIOB->CRH&=0XFFFF0FFF;GPIOB->CRH|=8<<12;}
) r1 Y+ {/ ^9 A0 w - #define MPU_SDA_OUT() {GPIOB->CRH&=0XFFFF0FFF;GPIOB->CRH|=3<<12;}
8 d6 B7 G6 H4 P% s8 U# V7 i - 3 y- A+ \' s- X8 s, Q; e$ w
9 S- h) y3 | g- #define MPU_IIC_SDA_1() GPIO_SetBits( GPIOB, GPIO_Pin_11 )5 ^" z) ~& [9 m% ~6 k% ^# V% H
- #define MPU_IIC_SDA_0() GPIO_ResetBits( GPIOB, GPIO_Pin_11 )
7 i. Z3 [4 c! O( K% y# c
0 ]% k" h" J, S- #define MPU_IIC_SCL_1() GPIO_SetBits( GPIOB, GPIO_Pin_10 )
/ t! B- j: [, b' P) Y# \) X+ q - #define MPU_IIC_SCL_0() GPIO_ResetBits( GPIOB, GPIO_Pin_10 )
! C% r# ]+ N7 v. k0 P - - x$ V& M/ S7 J% L1 b
- #define MPU_IIC_AD0_1() GPIO_SetBits( GPIOA, GPIO_Pin_15 )
% ~3 f3 p+ ~& C4 ^1 G - #define MPU_IIC_AD0_0() GPIO_ResetBits( GPIOA, GPIO_Pin_15 )
" p0 c7 j; t9 G - ! a* l0 n, r; L" q7 M- B
- #define MPU_IIC_SDA_READ() GPIO_ReadInputDataBit( GPIOB, GPIO_Pin_11 )' D* u$ |% P. g+ d) L
1 Y) a( }. Z0 M' L% I! ^- #define MPU_IIC_Delay() delay_us(2)9 t L7 Y! x6 B: q+ ^
6 E- @' m/ M: R: M, A2 l- /* 函数声明 */
. y: N* v4 h8 e! m+ `' p - void MPU_IIC_Init( void );
" g2 i- I- [( {* e* U) ^" A* B/ H7 B" ? - void MPU_IIC_Start( void );& E. [7 |2 a9 I0 s; n
- void MPU_IIC_Stop( void );
/ d- D4 I, i4 w) O$ ]- r - uint8_t MPU_IIC_Wait_Ack( void );% L8 w9 Q- `' @/ S
- void MPU_IIC_Ack( void );
G4 v+ y/ B3 p - void MPU_IIC_NAck( void );1 }. I4 V" ?" G! t/ a; W7 T& f9 k
- void MPU_IIC_Send_Byte( uint8_t data );
% g: v# x p2 G0 T5 j* k - uint8_t MPU_IIC_Read_Byte( uint8_t ack );
! z- a% t$ I4 A* n - 1 z; h6 u; z' i7 G8 r. o
- #endif3 I& G/ O2 @7 H$ A$ W% a7 F' ~6 O, u
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
- #include "mpu_iic.h"
. G# Y& p4 w8 N# W6 z - #include "usart.h"' H2 \* [0 U7 u7 x; G
, m! n' [0 f# i8 e+ u5 h- /*
' o: z7 d% M0 p) B - IIC接口引脚配置7 E: G& r; v2 o: S5 Z; c
- SDA:PB11
2 M9 g. i9 T5 m8 r - SCL:PB104 a+ p: h2 J% O( f: U/ S% K
- AD0:PB2
) T3 c' _0 b0 m; m, k Q0 g, a - */
. S1 \8 c$ W' U4 U& i - void MPU_IIC_Init( void )& f S- [" O' Y2 W$ F
- {2 ]+ U- I+ D# X8 [( F& U3 d
- GPIO_InitTypeDef GPIO_InitStruct;0 w6 ?6 }8 Y$ {* t, ^) e' y# Z! W( G1 r
- , R0 \5 b5 V& n8 g: w
- RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB, ENABLE );+ C, g! G* R) F( {0 S( x* d* E
- ( N4 ~* [/ m, k2 {" P
- GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
0 ^; s9 v5 j1 L) H3 M - GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
2 D1 Y5 S# O8 t6 z- R' U) ]0 g - GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10|GPIO_Pin_11;
4 Z x1 a0 D) t E' ^5 p0 X - GPIO_Init( GPIOB, &GPIO_InitStruct );5 Q: P. w- I2 |" d# I, L
-
8 G9 \; p+ q; R9 h# B! [ - MPU_IIC_SDA_1();7 @1 b% T6 y- n$ t
- MPU_IIC_SCL_1();1 j' W) v. J8 `& v: w' |/ V8 J1 J
- 7 _0 y- P7 R0 k3 T) S$ r' t4 O
- }
z& d; O/ Y0 ?2 t% s' t; S - c& Y6 w1 W) {. h' b @, N
- / a6 G0 b* L J# X$ R4 v
- void MPU_IIC_Start( void )8 P4 J( A! |/ \& j `/ L/ [
- {
1 J% W J6 s6 R: {8 m3 n - MPU_SDA_OUT();
7 @" {+ _" @! K4 e( u9 H# g4 U - 3 q0 i2 t8 Z. Z+ R4 F& i9 q
- MPU_IIC_SDA_1();
1 t2 n! l' Q! z; M; n - MPU_IIC_SCL_1();9 Z1 f8 D1 [. {1 P3 v
- delay_us(2);2 b, R9 q* l& W% d3 T/ ?, e' r: l
- MPU_IIC_SDA_0();
. x6 o& c: E5 Q8 \" L - delay_us(2);4 T$ ]+ L5 T, t6 J6 a
- MPU_IIC_SCL_0();8 D, C: ]: i$ z$ ^$ o8 _
- }
: A$ d# @# S* l5 _% `9 D: O
2 p, w% V+ @9 z8 t( _- void MPU_IIC_Stop( void )2 B$ J5 a8 c' k1 S9 n
- {
2 L" b0 h" I' { - MPU_SDA_OUT();! ^$ O- J" J# M( d$ `9 f( t' i
-
) p6 @ ~8 i0 ?. s' T; [0 q - MPU_IIC_SDA_0();
- i- y- k/ L' S; ~ - MPU_IIC_SCL_1();
" d6 j3 b* N) P2 o/ V3 A - delay_us(2);+ L8 t- Z0 ^8 o# D& j
- MPU_IIC_SDA_1();
6 P- r' |: ^) \1 m - MPU_IIC_SCL_1();
! k- l; |4 g9 Y& C - delay_us(2);1 N/ E7 D" Z& p. H" }8 O2 m
- % U4 |& O8 _- V5 P
- }' a( P, K) [1 K# k5 ^+ w
- 0 J9 _& |6 {0 Z% s# k! y \
- /* 由从设备在SCL为高电平的时候拉低SDA作为应答
! \9 [5 G; q6 H/ Y; ` - 返回值:1:未应答
4 | j E2 A/ \* L7 z. P8 b7 T - 0:已应答' [9 |; w; w- y; H' u
- */7 r/ {8 P8 c& c7 k# u% U
- uint8_t MPU_IIC_Wait_Ack( void )( E6 F% L+ b" h' Q! g
- {3 p& u8 [0 F$ p# E& T' ]
- uint8_t count;
E. ~' t+ v5 W1 Q- O5 ^- P - MPU_SDA_IN();1 ]* H7 t; x" X7 U u
- " w9 ^; ]+ t. F. G* Y2 _
- MPU_IIC_SCL_1();
C' y1 T) m' k' G/ L& ^6 x - delay_us(2);
9 ~ ~& e- ]0 H% R - MPU_IIC_SDA_1();
+ w: d+ }3 c% _, [1 u: d: P - delay_us(2);
/ B' n; Q6 g, o {! I3 O! z, ~ - 6 \- S) t: Y v( y' @* _
- while( MPU_IIC_SDA_READ()==1 )
8 p# ^, E& m1 Z) K' T - {7 u j% \. K* l% b% G- E U |( p
- count++;+ s$ c$ p( F. i/ R
- if( count>250 )
9 o/ `) y# p7 q5 U: H* z/ t( [7 U( F - {# W1 R: t3 ~% ^; n
- MPU_IIC_Stop();
& m* M( |8 p% Q' H - return 1;
0 E! p6 L; M1 `% A$ ]# W+ L A - }
3 c o0 K2 R$ k% `' z9 C* H0 D - } ! H z! s3 I+ Z) c3 t- v, B( x
- MPU_IIC_SCL_0();
6 G, u" _0 L" C/ S8 J - return 0;
8 [+ v3 w, x) l! k5 N - }8 p0 J& e5 K# x/ e+ g, z x
1 R! D1 d! [ f- # V8 T9 C. A* t) s: {
- void MPU_IIC_Ack( void )7 U# d9 |/ n5 X9 a; ~. b. g
- {
2 h) P. z K, H" z - ) D# G: ?9 f, R" G3 r. }0 i
- MPU_IIC_SCL_0(); S4 t: h Z3 F
- MPU_SDA_OUT();
5 f4 }- E( l+ f( Y W4 p - MPU_IIC_SDA_0();1 C$ B$ l5 M" k" r1 e
- delay_us(2);
' P9 e+ {/ w( }, W2 D+ z, x+ d - MPU_IIC_SCL_1();6 _$ p- T8 v0 ~: p5 ~
- delay_us(2);: B; k+ N+ R6 S7 h( h
- MPU_IIC_SCL_0();
7 Z$ U; f: a! s3 G; n -
4 G& k/ @% w( \# e9 z, J - }* G1 |7 G: k% k |: O" \* M
* F3 _. X# b* {2 p6 O/ ?
& U+ I8 a" L ?8 b- void MPU_IIC_NAck( void )
; ~) u* O ~$ ]: M - {, h9 M7 x0 {3 ?& D* d
- ) W) T: d* x) X/ N9 p5 ~3 L
-
4 w" P+ ]5 G8 X$ Q: h* [ - MPU_IIC_SCL_0();
* m! A- \2 T& P+ C! y - MPU_SDA_OUT();
7 @: M( L7 T! F2 C2 ?) ?0 b - MPU_IIC_SDA_1();
# G$ ~# m' d/ ~/ I- [ - delay_us(2);
. Z+ Q2 N9 O) O" K% a& J/ u - MPU_IIC_SCL_1();9 B+ P: H9 b& H& d# a, h
- delay_us(2);! |& ]4 Q1 \0 p- j% }0 Q" h3 A
- MPU_IIC_SCL_0();2 s$ e4 R2 h; a2 o& D9 T9 \! A: ^3 g
- }
7 @+ c- o# b$ I2 _' }+ O: ^
# I \9 L# S m- [+ c0 e
8 Q4 G8 l: k. @$ h4 [( Q: l+ G- /* 发送一个字节数据,高位先行 */
! N1 v2 L; F1 b+ ]) }9 R$ n/ D$ l u - void MPU_IIC_Send_Byte( uint8_t data )
8 }2 \& V2 }* O - {) h- K8 y+ \% c1 x5 x( s. h, z' x( B
- uint8_t t; S1 R8 G% e; {5 Q
- MPU_SDA_OUT();
! X1 h* O3 G7 M3 z) s( j. B - + R6 Q5 N# | w
- MPU_IIC_SCL_0();
- M' g8 r6 c e9 {9 K S - for( t=0;t<8;t++ )
1 k8 n: z" H7 e - {4 [0 `% h2 v: C, O* x6 O
- if( ((data&0x80)>>7)==1 )6 ?* P1 Q, E) g% o0 O. N2 q, M, [5 Y
- MPU_IIC_SDA_1();2 m1 v; c v8 M Z
- else% M' M3 K& W+ {& ^& e
- MPU_IIC_SDA_0();
, Q `- |) ]7 G! i( o- k$ v - data<<=1;
/ b1 x% [' r8 `% F. |# f/ ~" | - MPU_IIC_SCL_1();$ j! k2 { B* {4 B! W9 d# L0 F
- delay_us(2);
$ L) L, x: `- R. s: o" m$ f$ g; n - MPU_IIC_SCL_0();& z& {% T; g! P/ r* G
- delay_us(2);
* ~) P/ h; \- r3 k f$ h - }; M+ o! j% ^ Q! e) {4 F8 ?& n8 I
- }
6 z# ?9 x$ b" Z1 p( w' E - ; X( h2 ~( N, d& Y# W
- 8 T4 o3 ^$ J+ H, V1 a7 Y, t
- /* 读取一个字节,ack=1时,读取完成后主机发送应答 */* g U3 |) x6 h7 [, ?, P( j9 ~: D; n
- uint8_t MPU_IIC_Read_Byte( uint8_t ack )
. C' {- S* K W- U+ _/ } T - {
5 @) y6 O# ]" P y$ a" F8 b4 [ - uint8_t t,data=0;6 X* Y% _. s( l4 p/ r* O* Q
- MPU_SDA_IN();
. w9 M$ U. U) P3 n - for( t=0;t<8;t++ ) q& b1 l2 f' J
- {! i1 U, A0 E0 X8 q9 ^: s: {7 G
- MPU_IIC_SCL_0();
. i$ H& ?$ K& b - delay_us(2);//等待SDA的变化
' B4 H1 }0 h) J9 ? - MPU_IIC_SCL_1();
& `# Y/ r# a! A" {. g3 ^: a - 7 t- s( ^# E. {. S3 K: O5 n
- data<<=1;//必须在读取前面,因为之后一位读取后就不再移位
~7 {4 m% q0 m7 v8 {$ l ? - if( MPU_IIC_SDA_READ()==1 )
6 k! B) g& i: N& H0 M" A - data++;
3 r; W! U$ n s -
( s0 Q6 q8 I% a, {% R- | - delay_us(2);//等待SDA的变化
* o- Z& f( A" j6 | -
+ ^ D8 b/ Y/ j# F# {7 `/ T0 g - }# ?: `! U4 I. V' v2 u& C. F
% S( |4 b4 ^ F8 Z" q- if( !ack )
5 b4 S; n4 Q% G# l/ V, B: f0 \3 ` - MPU_IIC_NAck();//发送nACK
3 M9 J+ J0 `* T3 A - else
' }! z2 c3 j$ _- O6 V; N6 z - MPU_IIC_Ack(); //发送ACK & P! @; }( ?, p
- return data;6 _# J* \4 O$ n( F$ B0 H3 P$ `) a
- }- _" h( b# z5 ?! P# ~
. M( f) s* Q$ s. m% U
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- #ifndef __MPU6050_H5 i, H3 T) ]/ d$ ^3 x
- #define __MPU6050_H
. ?( _8 o" r2 Q3 C. j4 B9 h# G - . R7 j0 l5 }) j7 f4 G
- #include "stm32f10x.h"6 B$ B9 Z7 }; l- ?
- #include "mpu_iic.h"
0 I! H' ^1 T0 i _# d O+ V - ( X5 `8 R6 @6 t
* @3 I8 L; G6 R- |$ F- ?- /* AD0接地,MPU6050的IIC地址为0x68 接3.3V就为0x69*/
6 z( l) g4 d+ o/ U6 U - #define MPU_ADDR 0X68
4 k9 P) d3 n0 b+ M1 k- \5 o- g
! X) T3 l# f( h8 G% ?) A7 n# x8 {- /************** MPU6050相关寄存器地址 *********************/
7 }7 S/ F. z8 Y - #define MPU_ACCEL_OFFS_REG 0X06 //accel_offs寄存器,可读取版本号,寄存器手册未提到' D& z, `* S% N; z2 n8 Z. w+ _
- #define MPU_PROD_ID_REG 0X0C //prod id寄存器,在寄存器手册未提到0 q4 z2 N1 ]6 i& N: ] b! ~
- #define MPU_SELF_TESTX_REG 0X0D //自检寄存器X
" A P+ }. _8 G. ^ - #define MPU_SELF_TESTY_REG 0X0E //自检寄存器Y
. F6 u! b6 [( _ z+ b. _0 E. T - #define MPU_SELF_TESTZ_REG 0X0F //自检寄存器Z7 w" N$ @: a* Y1 r, t! T. R
- #define MPU_SELF_TESTA_REG 0X10 //自检寄存器A
0 W$ a" f6 h) M4 i - #define MPU_SAMPLE_RATE_REG 0X19 //采样频率分频器
; _% z1 D2 F; C! \4 ^2 d3 A: b7 F) Q - #define MPU_CFG_REG 0X1A //配置寄存器9 i! b m: M& H( g1 v" M5 i h
- #define MPU_GYRO_CFG_REG 0X1B //陀螺仪配置寄存器8 H) P {$ q+ z$ k
- #define MPU_ACCEL_CFG_REG 0X1C //加速度计配置寄存器
# b" A. |" r1 b3 w0 ]- X6 k0 ` l/ H - #define MPU_MOTION_DET_REG 0X1F //运动检测阀值设置寄存器8 } l! T4 M* @1 M6 K T5 O
- #define MPU_FIFO_EN_REG 0X23 //FIFO使能寄存器
$ Z! n9 g. e2 G2 H8 r - #define MPU_I2CMST_CTRL_REG 0X24 //IIC主机控制寄存器
3 k2 t2 d+ n5 J2 w/ o: ]( H& }- H; S - #define MPU_I2CSLV0_ADDR_REG 0X25 //IIC从机0器件地址寄存器
3 B% O9 T" y0 D. y3 f6 S - #define MPU_I2CSLV0_REG 0X26 //IIC从机0数据地址寄存器, O- s4 N, @: |$ p$ G# v1 Y
- #define MPU_I2CSLV0_CTRL_REG 0X27 //IIC从机0控制寄存器
* k5 C: y8 X' }3 a9 S) R) O8 T! l n - #define MPU_I2CSLV1_ADDR_REG 0X28 //IIC从机1器件地址寄存器
4 x* g$ u% O4 n' K5 K( S - #define MPU_I2CSLV1_REG 0X29 //IIC从机1数据地址寄存器6 b" B9 g" F" H
- #define MPU_I2CSLV1_CTRL_REG 0X2A //IIC从机1控制寄存器
9 q p4 Q- P" J, o - #define MPU_I2CSLV2_ADDR_REG 0X2B //IIC从机2器件地址寄存器- ?+ E4 Z7 s) Y, P- U5 o
- #define MPU_I2CSLV2_REG 0X2C //IIC从机2数据地址寄存器/ Z0 o, k# s$ P. ?' A) w
- #define MPU_I2CSLV2_CTRL_REG 0X2D //IIC从机2控制寄存器6 ^5 C# E5 ^0 P3 S8 h4 {
- #define MPU_I2CSLV3_ADDR_REG 0X2E //IIC从机3器件地址寄存器 j2 z# `6 z9 Y. ~/ |7 d
- #define MPU_I2CSLV3_REG 0X2F //IIC从机3数据地址寄存器, Y. g. o" \$ }0 V9 M3 E$ x
- #define MPU_I2CSLV3_CTRL_REG 0X30 //IIC从机3控制寄存器
3 d- s+ r; Q$ n2 p - #define MPU_I2CSLV4_ADDR_REG 0X31 //IIC从机4器件地址寄存器) P# I) b* R1 U' d; ] s A/ ]: e8 s
- #define MPU_I2CSLV4_REG 0X32 //IIC从机4数据地址寄存器) S, d( ?& g W
- #define MPU_I2CSLV4_DO_REG 0X33 //IIC从机4写数据寄存器! {6 ^$ @( C, i& m7 r& p1 C0 ?: T4 J
- #define MPU_I2CSLV4_CTRL_REG 0X34 //IIC从机4控制寄存器
3 |+ U! ], p* m! r& g( W* _3 g% @ - #define MPU_I2CSLV4_DI_REG 0X35 //IIC从机4读数据寄存器
5 ?6 n& D0 L, s" ~- @
! k/ @. l- m+ t- #define MPU_I2CMST_STA_REG 0X36 //IIC主机状态寄存器) ^* y$ I8 X( w& X' _6 z
- #define MPU_INTBP_CFG_REG 0X37 //中断/旁路设置寄存器# R& n( K) ~2 q& E9 h
- #define MPU_INT_EN_REG 0X38 //中断使能寄存器
0 N5 Q) u+ t: X2 g- U. Z - #define MPU_INT_STA_REG 0X3A //中断状态寄存器
. y x: |# h1 @* j3 J0 w/ n/ U
6 s z1 C [0 }4 B, u- #define MPU_ACCEL_XOUTH_REG 0X3B //加速度值,X轴高8位寄存器" [2 [( G" @8 l/ b: z6 D
- #define MPU_ACCEL_XOUTL_REG 0X3C //加速度值,X轴低8位寄存器% y* t. S- z3 x) t8 a" ^
- #define MPU_ACCEL_YOUTH_REG 0X3D //加速度值,Y轴高8位寄存器 ~; c- j( ]% @/ Z
- #define MPU_ACCEL_YOUTL_REG 0X3E //加速度值,Y轴低8位寄存器
E/ Q, M s+ l - #define MPU_ACCEL_ZOUTH_REG 0X3F //加速度值,Z轴高8位寄存器2 p) \, U5 d/ r4 Q
- #define MPU_ACCEL_ZOUTL_REG 0X40 //加速度值,Z轴低8位寄存器
/ G8 l0 o% E H, [4 j7 i% p
7 W' [$ p! u0 q# M2 G5 e- #define MPU_TEMP_OUTH_REG 0X41 //温度值高八位寄存器
& C& }. u) M8 b# O - #define MPU_TEMP_OUTL_REG 0X42 //温度值低8位寄存器7 n/ A% H3 `& j3 U' O
( @$ w3 n% o+ {& m! q) I- #define MPU_GYRO_XOUTH_REG 0X43 //陀螺仪值,X轴高8位寄存器
( b* l3 e' N/ j) A9 e3 A - #define MPU_GYRO_XOUTL_REG 0X44 //陀螺仪值,X轴低8位寄存器# `2 F% D/ o: n t) \5 K3 C
- #define MPU_GYRO_YOUTH_REG 0X45 //陀螺仪值,Y轴高8位寄存器( o9 C/ v! H$ v7 q1 w6 y
- #define MPU_GYRO_YOUTL_REG 0X46 //陀螺仪值,Y轴低8位寄存器" b. X1 U3 X6 t
- #define MPU_GYRO_ZOUTH_REG 0X47 //陀螺仪值,Z轴高8位寄存器) n% L: i+ Q+ L+ p: r2 \6 J. {) I: ?
- #define MPU_GYRO_ZOUTL_REG 0X48 //陀螺仪值,Z轴低8位寄存器" C6 G6 q7 S) f3 S. E
9 @" a% M5 B7 o, z( h) ^7 J- #define MPU_I2CSLV0_DO_REG 0X63 //IIC从机0数据寄存器0 q# h/ N: w5 [0 [
- #define MPU_I2CSLV1_DO_REG 0X64 //IIC从机1数据寄存器
' X7 _* N- a+ Y" D9 z0 B - #define MPU_I2CSLV2_DO_REG 0X65 //IIC从机2数据寄存器; G% F# e8 k6 v M
- #define MPU_I2CSLV3_DO_REG 0X66 //IIC从机3数据寄存器9 T: X8 P/ V8 {: |2 C
- $ M% \% c* x* n. Y; o8 k0 y. I E
- #define MPU_I2CMST_DELAY_REG 0X67 //IIC主机延时管理寄存器
- l0 P) J. S' [% O6 G x: Q/ b* ~ - #define MPU_SIGPATH_RST_REG 0X68 //信号通道复位寄存器
; v" T- I, _8 H8 j5 t# y1 m) ` K - #define MPU_MDETECT_CTRL_REG 0X69 //运动检测控制寄存器3 D$ C- r1 g! f; ?
- #define MPU_USER_CTRL_REG 0X6A //用户控制寄存器
% U* F6 z" T% p) P# d - #define MPU_PWR_MGMT1_REG 0X6B //电源管理寄存器1
5 a4 j2 D' U5 t$ F0 g. G q - #define MPU_PWR_MGMT2_REG 0X6C //电源管理寄存器2 5 k7 |- ?# b7 M; A2 ^
- #define MPU_FIFO_CNTH_REG 0X72 //FIFO计数寄存器高八位
4 J4 D& b& J& [4 b/ c" l - #define MPU_FIFO_CNTL_REG 0X73 //FIFO计数寄存器低八位# l2 }/ k* y0 C* l- G
- #define MPU_FIFO_RW_REG 0X74 //FIFO读写寄存器1 l7 U' C: u9 B1 U1 u0 e/ v
- #define MPU_DEVICE_ID_REG 0X75 //器件ID寄存器% R3 p q! [4 i, H
$ Y* u' h- w# R. H2 S
! c' v) Y. c! c6 a q+ J
1 q$ ?4 d! |1 c6 K" o- a/ a
0 J1 c* s) t' C% f. S! a- /* 函数声明 */( o! R5 v0 K. [6 L+ H X9 ^
- uint8_t MPU_Read_Byte( uint8_t reg );9 }! j# i: k( G) U1 {6 h
- uint8_t MPU_Write_Byte( uint8_t reg, uint8_t data );
0 [7 v8 v7 x% f! o - 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
- uint8_t MPU_Write_Continue( uint8_t addr, uint8_t reg, uint8_t len, uint8_t *buf );
7 g* p, e5 ]" ?. |% f
2 R% j* p* l# ~0 Q, a- uint8_t MPU_Init( void );
) [- R( o; }4 P, y h g7 C$ V - . b6 ~4 B# ~2 e7 L
- 0 o+ s* F# Z( \5 ] |5 {' E
- uint8_t MPU_Set_Gyro_Fsr( uint8_t fsr );9 t4 L/ d( F9 T
- uint8_t MPU_Set_Accel_Fsr( uint8_t fsr );
: f; K( U3 I2 D0 h - uint8_t MPU_Set_LPF( uint16_t lpf );
% A+ j" ~% h y( x2 w9 N - uint8_t MPU_Set_Rate( uint16_t rate );
6 _. \- E5 O) i1 X( n$ N - short MPU_Get_Temperature( void );+ f% V- N( V% m: t; _8 o
- uint8_t MPU_Get_Gyroscope( short *gx, short *gy, short *gz );
6 z# r. G5 S0 N) s# p - uint8_t MPU_Get_Accelerometer( short *ax, short *ay, short *az );$ Z0 {, l! v9 D" i: I
- 9 J7 Q/ x4 C' V+ a, ?% c# I/ R
- #endif
) P. R1 @6 G! S3 E6 Z% E - 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- #ifndef __MPU6050_H
1 i& E& O' q/ y! }7 }- K2 j - #define __MPU6050_H
. F9 I& e1 f" |, q" k
; M0 P, I3 L" K: K4 J- #include "stm32f10x.h"0 L7 H( K, _9 i! f
- #include "mpu_iic.h"
# G# F' s4 c: m' h* D) q6 { - 0 e* U0 J+ O5 \3 p8 t( ^0 R: P; h
3 B+ ?) b2 J* V3 }! U# Y' x- /* AD0接地,MPU6050的IIC地址为0x68 接3.3V就为0x69*/& s$ B% e( K& _, ]6 r8 V: V
- #define MPU_ADDR 0X68 z0 D) u& l% C( P" e
% c! T, K- ~9 T1 P8 P- /************** MPU6050相关寄存器地址 *********************/
* x/ C6 E: C E9 s q9 L - #define MPU_ACCEL_OFFS_REG 0X06 //accel_offs寄存器,可读取版本号,寄存器手册未提到
/ F9 J! B/ i6 w3 k/ \' {3 M - #define MPU_PROD_ID_REG 0X0C //prod id寄存器,在寄存器手册未提到
% P T5 R, C/ e) Y1 Z1 x - #define MPU_SELF_TESTX_REG 0X0D //自检寄存器X8 q. F1 e% b1 P6 G% e1 q
- #define MPU_SELF_TESTY_REG 0X0E //自检寄存器Y+ Q" L0 z3 ]& X
- #define MPU_SELF_TESTZ_REG 0X0F //自检寄存器Z
0 R3 j9 h9 t3 _5 b- q6 V6 U - #define MPU_SELF_TESTA_REG 0X10 //自检寄存器A: {- S9 J( j# u: a
- #define MPU_SAMPLE_RATE_REG 0X19 //采样频率分频器% ?; P' N/ }0 c4 P) B0 m9 U
- #define MPU_CFG_REG 0X1A //配置寄存器: ]' A1 w3 y6 Q
- #define MPU_GYRO_CFG_REG 0X1B //陀螺仪配置寄存器
0 ]( K% _' w M7 v6 h& w [ - #define MPU_ACCEL_CFG_REG 0X1C //加速度计配置寄存器+ v5 V$ D4 E# d: P1 R
- #define MPU_MOTION_DET_REG 0X1F //运动检测阀值设置寄存器- w$ T/ d* v4 k9 V! r; y: t P9 _$ w+ T
- #define MPU_FIFO_EN_REG 0X23 //FIFO使能寄存器. P/ I }9 u! g& m+ ]
- #define MPU_I2CMST_CTRL_REG 0X24 //IIC主机控制寄存器
+ v$ |6 f0 @+ u0 N4 R - #define MPU_I2CSLV0_ADDR_REG 0X25 //IIC从机0器件地址寄存器
! j, z- T- g; l* Z# d9 ?* L - #define MPU_I2CSLV0_REG 0X26 //IIC从机0数据地址寄存器
: Z U' R# j" K1 h# G8 y3 d - #define MPU_I2CSLV0_CTRL_REG 0X27 //IIC从机0控制寄存器
2 X# l2 D! s+ U - #define MPU_I2CSLV1_ADDR_REG 0X28 //IIC从机1器件地址寄存器; h' r" C( M0 r5 G. o
- #define MPU_I2CSLV1_REG 0X29 //IIC从机1数据地址寄存器% s/ v: O4 d% J; c* F- [9 K
- #define MPU_I2CSLV1_CTRL_REG 0X2A //IIC从机1控制寄存器% M$ l( f2 d# {6 U& L- l+ S
- #define MPU_I2CSLV2_ADDR_REG 0X2B //IIC从机2器件地址寄存器2 I: r: x# T3 t: Y7 Q7 m- n
- #define MPU_I2CSLV2_REG 0X2C //IIC从机2数据地址寄存器
2 _. _& U7 X+ y& M+ e9 n( x - #define MPU_I2CSLV2_CTRL_REG 0X2D //IIC从机2控制寄存器
1 U$ ?+ e# V# a7 l! }& I8 q - #define MPU_I2CSLV3_ADDR_REG 0X2E //IIC从机3器件地址寄存器2 ^5 A: G6 x! K0 `" @; U
- #define MPU_I2CSLV3_REG 0X2F //IIC从机3数据地址寄存器% Q$ p* x- m5 m+ I4 N% `
- #define MPU_I2CSLV3_CTRL_REG 0X30 //IIC从机3控制寄存器
9 m d! S) f. Y( Z - #define MPU_I2CSLV4_ADDR_REG 0X31 //IIC从机4器件地址寄存器* D/ H+ `% i( s; s: q8 v
- #define MPU_I2CSLV4_REG 0X32 //IIC从机4数据地址寄存器' M$ @9 T5 f8 V5 b- A/ V: D! X
- #define MPU_I2CSLV4_DO_REG 0X33 //IIC从机4写数据寄存器! T# d6 S0 S A+ E% o7 t3 E
- #define MPU_I2CSLV4_CTRL_REG 0X34 //IIC从机4控制寄存器* S& B2 k$ P/ K, ?' J
- #define MPU_I2CSLV4_DI_REG 0X35 //IIC从机4读数据寄存器
. X f8 M2 f" _( f! ]) w- m - # ~ o7 }) V- Z. ~
- #define MPU_I2CMST_STA_REG 0X36 //IIC主机状态寄存器9 v, [9 U0 q0 P' K, Z1 O( `
- #define MPU_INTBP_CFG_REG 0X37 //中断/旁路设置寄存器0 i$ j( u" _0 g2 I& @7 Q* S
- #define MPU_INT_EN_REG 0X38 //中断使能寄存器/ A1 {7 O V9 K' }
- #define MPU_INT_STA_REG 0X3A //中断状态寄存器
3 B8 c, m6 f7 `2 Z
. O) q# E5 U, R$ M! v Z- #define MPU_ACCEL_XOUTH_REG 0X3B //加速度值,X轴高8位寄存器* O4 P! n# D/ `$ _! `/ `4 ]5 z
- #define MPU_ACCEL_XOUTL_REG 0X3C //加速度值,X轴低8位寄存器
% p' v) P2 O7 I0 A& d - #define MPU_ACCEL_YOUTH_REG 0X3D //加速度值,Y轴高8位寄存器
5 g) `4 r& G2 t' b' ^. C d. p - #define MPU_ACCEL_YOUTL_REG 0X3E //加速度值,Y轴低8位寄存器) C& ?- T4 Q& a# a; u- B
- #define MPU_ACCEL_ZOUTH_REG 0X3F //加速度值,Z轴高8位寄存器
2 h' n2 ?1 N" Y$ P7 L - #define MPU_ACCEL_ZOUTL_REG 0X40 //加速度值,Z轴低8位寄存器
) t! [- o# {" y
: V) \9 _/ n6 p+ x( O9 p- #define MPU_TEMP_OUTH_REG 0X41 //温度值高八位寄存器, z! q y* `9 h" |
- #define MPU_TEMP_OUTL_REG 0X42 //温度值低8位寄存器. C: A( y5 p) E2 ? n) ?7 ?
- Y9 r- r: M' ]1 X `7 o0 d+ B- #define MPU_GYRO_XOUTH_REG 0X43 //陀螺仪值,X轴高8位寄存器0 r. G, Q/ N+ u: N1 n, P8 A+ }; I
- #define MPU_GYRO_XOUTL_REG 0X44 //陀螺仪值,X轴低8位寄存器
3 e3 j6 }1 j+ _ - #define MPU_GYRO_YOUTH_REG 0X45 //陀螺仪值,Y轴高8位寄存器6 v; w$ O, _, y @9 U2 g2 k
- #define MPU_GYRO_YOUTL_REG 0X46 //陀螺仪值,Y轴低8位寄存器
- }( f J7 Y2 s( N5 j2 U4 W2 Q' q - #define MPU_GYRO_ZOUTH_REG 0X47 //陀螺仪值,Z轴高8位寄存器
0 h5 t n% M# @) m; m7 G - #define MPU_GYRO_ZOUTL_REG 0X48 //陀螺仪值,Z轴低8位寄存器
1 M# J# U2 ^! X) C( `2 {
% v) p. i: M: A& g1 Y1 N; j- #define MPU_I2CSLV0_DO_REG 0X63 //IIC从机0数据寄存器
, x c# @7 i, c* N, {. q - #define MPU_I2CSLV1_DO_REG 0X64 //IIC从机1数据寄存器3 A: J5 |" D7 |" V+ M' S
- #define MPU_I2CSLV2_DO_REG 0X65 //IIC从机2数据寄存器
+ N3 c" a+ j" y( ]5 e4 ^$ q6 ?( [ - #define MPU_I2CSLV3_DO_REG 0X66 //IIC从机3数据寄存器6 L. H+ j: J5 P
: u# l7 v4 V+ p/ s- #define MPU_I2CMST_DELAY_REG 0X67 //IIC主机延时管理寄存器( _. d. D" I1 r) d' H* e, g2 o
- #define MPU_SIGPATH_RST_REG 0X68 //信号通道复位寄存器
: K" Y4 L, [# m/ n - #define MPU_MDETECT_CTRL_REG 0X69 //运动检测控制寄存器5 m/ J2 q, r- F, k
- #define MPU_USER_CTRL_REG 0X6A //用户控制寄存器# A; g3 Z8 V( L" J5 Y5 b g
- #define MPU_PWR_MGMT1_REG 0X6B //电源管理寄存器1
5 v& a2 W9 {$ v+ m7 w7 p, w - #define MPU_PWR_MGMT2_REG 0X6C //电源管理寄存器2
1 R& V4 b) e% `; Q$ c& S - #define MPU_FIFO_CNTH_REG 0X72 //FIFO计数寄存器高八位
# i% o" d; S/ U$ f7 g. w% K4 @( P, H - #define MPU_FIFO_CNTL_REG 0X73 //FIFO计数寄存器低八位
& ^0 J; `$ T: D* P+ G7 v - #define MPU_FIFO_RW_REG 0X74 //FIFO读写寄存器9 Y# ^* B d- c5 L x2 Q
- #define MPU_DEVICE_ID_REG 0X75 //器件ID寄存器
" g, T# ?( Z7 d1 U3 ? - 1 O! J3 B& X% H. I) C- N7 B
- ) ^+ W& t# E, y1 G+ X2 P$ z, `
- 2 _# x6 \+ B8 v4 m! X
* O& m" v/ i' j! J8 B' u8 l- /* 函数声明 */3 |7 U- a5 P- B, e' S* H! j) {3 v4 j
- uint8_t MPU_Read_Byte( uint8_t reg );2 Q7 ^7 Y5 J5 Y! ]& I/ n
- uint8_t MPU_Write_Byte( uint8_t reg, uint8_t data );
2 }/ ?6 u5 Q% l+ q2 d - 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
- 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 - : q" S& ~& X4 W( D/ [" R) ~ i
- uint8_t MPU_Init( void );
' A% i9 v% Q( p7 u+ a+ @( c - 6 v8 j! \4 d- t+ G4 F
( ]* n. a" s$ s, j1 Q) G7 l- uint8_t MPU_Set_Gyro_Fsr( uint8_t fsr );
8 W+ ?) z/ _: H* f7 d - uint8_t MPU_Set_Accel_Fsr( uint8_t fsr );
# l1 f; M' C% R+ ^ F3 j3 J - uint8_t MPU_Set_LPF( uint16_t lpf );
8 A3 c' \1 G, b* G* x, |( x - uint8_t MPU_Set_Rate( uint16_t rate );
$ ~* H7 ? d4 C7 U$ v7 D3 X. y/ @ - short MPU_Get_Temperature( void );
3 H5 t I" F! ?% b5 X) s/ n - uint8_t MPU_Get_Gyroscope( short *gx, short *gy, short *gz );
9 O. ?( ^$ {) ^6 O - uint8_t MPU_Get_Accelerometer( short *ax, short *ay, short *az );
Y/ [6 y/ W5 i: m+ ?. F - 0 q- ]& z" j# u' P) ?" n
- #endif
( f3 X6 ?0 J% A2 n U7 w - 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
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 _
- #define i2c_write MPU_Write_Continue
5 m/ }2 U5 K; A# h5 [9 v - #define i2c_read MPU_Read_Continue- m T" ?6 f- O3 p6 E: _
- #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- //mpu6050,dmp初始化, r) V8 h* B4 Q. z
- //返回值:0,正常
0 U9 E( F% E& ]0 n+ S - // 其他,失败/ P2 l: f, e T" z4 D
- uint8_t mpu_dmp_init(void) I! V( G+ m& e* n& e$ @
- {
: \/ ]. G$ G' C: m N/ N' J - uint8_t res=0;
; t1 j# q. `8 d( H - MPU_IIC_Init(); //初始化IIC总线2 z1 c ?8 E: ~- B* k" H6 E
- if(mpu_init()==0) //初始化MPU6050' G. ~! T# J6 r+ {
- { , x5 C9 M- K/ _* `1 y0 V/ `8 [% T
- res=mpu_set_sensors(INV_XYZ_GYRO|INV_XYZ_ACCEL);//设置所需要的传感器' `, p' L$ v- [* n0 n' E
- if(res)return 1;
6 P ~9 g% p/ a! l7 _ - res=mpu_configure_fifo(INV_XYZ_GYRO|INV_XYZ_ACCEL);//设置FIFO9 M/ a" f& g) Z' g4 ], G5 p: y
- if(res)return 2;
& Z: r$ C9 `+ R0 U$ Z% V - res=mpu_set_sample_rate(DEFAULT_MPU_HZ); //设置采样率; N- D1 t m- Y" X
- if(res)return 3; . G/ @, Y) K+ W' i
- res=dmp_load_motion_driver_firmware(); //加载dmp固件
) ~5 e+ T* U% S, T - if(res)return 4; ; q0 `- T( f7 r J6 f
- res=dmp_set_orientation(inv_orientation_matrix_to_scalar(gyro_orientation));//设置陀螺仪方向
2 x, Z% z7 }8 e( m. C - if(res)return 5;
8 K# n5 n8 _1 z% W) m, e& } - res=dmp_enable_feature(DMP_FEATURE_6X_LP_QUAT|DMP_FEATURE_TAP| //设置dmp功能( Y3 s9 l @" Z
- DMP_FEATURE_ANDROID_ORIENT|DMP_FEATURE_SEND_RAW_ACCEL|DMP_FEATURE_SEND_CAL_GYRO|
% T/ W* N" ]$ f# ]2 i - DMP_FEATURE_GYRO_CAL);
3 Y- ]* K1 x& T" K p9 j5 L - if(res)return 6; " D% x& b6 U* ?" W8 l4 x! n/ N0 P
- res=dmp_set_fifo_rate(DEFAULT_MPU_HZ); //设置DMP输出速率(最大不超过200Hz)
$ c; \, ?6 A' `* f ~6 {- W8 _8 t - if(res)return 7; 5 t9 U5 ~3 \8 z! _7 Z8 I$ U
- res=run_self_test(); //自检
8 F5 a8 e" Z+ r4 w' f: L# V6 t9 \# H3 i - if(res)return 8; & h9 A( l, U" g/ C
- res=mpu_set_dmp_state(1); //使能DMP
8 S, O8 [3 m3 _/ Y* `* f3 i& E D; u* M - if(res)return 9;
% x+ h1 C! ?! P# b- w$ n2 G7 h+ p - }else return 10;+ D' H9 b2 C, ?7 q
- return 0;
& a; S5 l! H/ S9 g7 E: q6 a - }, H) X, c/ {5 a* N
复制代码 ; x. }6 a5 k4 ]% Z6 U0 h6 p
获取欧拉角
* u) M8 K# v/ f8 G7 g- ^) k# w- //得到dmp处理后的数据(注意,本函数需要比较多堆栈,局部变量有点多)0 G, [/ B- {4 q4 E7 r e; }
- //pitch:俯仰角 精度:0.1° 范围:-90.0° <---> +90.0°7 l; {( [* L4 Y5 P8 Z: ?1 @8 w O
- //roll:横滚角 精度:0.1° 范围:-180.0°<---> +180.0°8 C3 M Z; G( v1 t
- //yaw:航向角 精度:0.1° 范围:-180.0°<---> +180.0°' Z6 u1 H7 r$ p& A' J
- //返回值:0,正常4 v7 M( Q u& ?1 n% z8 h
- // 其他,失败$ N- [, @8 T! h i& D6 X4 L% _# P
- uint8_t mpu_dmp_get_data(float *pitch,float *roll,float *yaw)7 ]/ b( L# `) s- Z+ T
- {% I( M2 J4 K) b: C8 e
- float q0=1.0f,q1=0.0f,q2=0.0f,q3=0.0f;+ L: c+ ^- b& z+ s/ i
- unsigned long sensor_timestamp;; c. }3 s) ?# o; ]' L1 W! H
- short gyro[3], accel[3], sensors;1 Z* R4 [, h, p- @9 Z7 }
- unsigned char more;8 T) N6 \/ U- t
- long quat[4]; 9 u: o4 n9 ^6 Z% l! z( T7 l/ f! W
- if(dmp_read_fifo(gyro, accel, quat, &sensor_timestamp, &sensors,&more))return 1;
0 Y7 `8 R0 J! q/ _1 Q( L - /* 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
- * 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 - **/
& X* @& M# { C/ ]/ ]! R - /*if (sensors & INV_XYZ_GYRO ): w" a% l7 B9 Y+ O7 [9 s
- send_packet(PACKET_TYPE_GYRO, gyro);3 w {, o9 a4 x2 O
- if (sensors & INV_XYZ_ACCEL)# v) Y8 Z: t0 f/ r$ H- B
- send_packet(PACKET_TYPE_ACCEL, accel); *// V b7 {1 L" ~5 Y7 o" w7 A
- /* Unlike gyro and accel, quaternions are written to the FIFO in the body frame, q30.
: n( N$ O* B3 ^5 ~; k3 d - * The orientation is set by the scalar passed to dmp_set_orientation during initialization. * {. A% w. C0 x) V6 p! U( B |
- **/
; N! g3 B% `4 a. ?% {+ v - if(sensors&INV_WXYZ_QUAT) 5 B' b7 q) g9 e) Y
- {
6 \' d( e) X$ o* \5 r3 e - q0 = quat[0] / q30; //q30格式转换为浮点数
8 f% D- o7 [4 \! }, g c- M# [" N' D - q1 = quat[1] / q30;2 |' B# r+ k, W2 Q4 \
- q2 = quat[2] / q30;
+ ]+ U1 ^9 ^/ k% M& O) @ - q3 = quat[3] / q30;
$ d. }: O, D5 W O - //计算得到俯仰角/横滚角/航向角
2 S" V4 d" Y- a, u9 H, | - *pitch = asin(-2 * q1 * q3 + 2 * q0* q2)* 57.3; // pitch
9 Q+ f) M# r2 n - *roll = atan2(2 * q2 * q3 + 2 * q0 * q1, -2 * q1 * q1 - 2 * q2* q2 + 1)* 57.3; // roll
, [! b1 g: C0 n& F - *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$ `! ~ - }else return 2;" v6 e5 A* s9 _# q" n
- return 0; k2 N. r9 |& G8 s! C! Z; O
- }
. L( a* k$ R M" g6 D/ E - / 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- #include "stm32f10x.h" , c+ M( g, ^6 D; K
- #include "usart.h"
% w# g# i& n1 [: ^, H( H - #include "delay.h"
R% `7 Y. ~' U' w# N( [* a8 r - #include "mpu6050.h"
8 v: T2 y2 j( p( g- W- i y" Q/ Z - #include "inv_mpu.h"/ W' p' t$ d9 n( u q
- #include "inv_mpu_dmp_motion_driver.h"
4 T/ H; W5 J- l6 O' o# t
6 o- z! @: I! P4 j: k# B- int main(void)
4 P2 e# T7 @% a1 D; z7 L% [ - {
# H! `- E' G, i- w9 A; _8 B- Q% f - uint8_t x=0;
* r+ c# Y8 a* ~) R$ M - float pitch,roll,yaw; //欧拉角
. o6 Z5 i+ q1 A) i7 C) g - short aacx,aacy,aacz; //加速度传感器原始数据
" l3 f5 u8 _, ?5 M. e) I - short gyrox,gyroy,gyroz; //陀螺仪原始数据9 ^! P! Y9 F: \# w' i0 J1 s0 O
- short temp; //温度# k! K& ?$ C1 T& s( b( s6 l
-
/ x; b/ f. M" ] - NVIC_PriorityGroupConfig( 2 );
7 Q; o. \, X% _$ b - delay_init();
& }- Q9 S( l- g' X( Y4 L! M - USART1_Init(115200); 8 Q6 N7 U/ a6 D$ ^8 O
- printf("程序开始\n");
: E6 ]% W* ]4 P' B& j - $ z0 f7 b9 j. k: S/ o4 O
- if( MPU_Init()!=0 )
+ J4 l3 w j: z; p: t# v, j - {
" e; w0 L' w5 Z* r# J, O- E$ U) | - printf("MPU6050初始化错误!\n");
+ @6 ^0 H( b0 a5 q/ _9 { - return 0;8 E' P" s1 R7 a9 }& j+ {+ J, m" ^
- }
) |5 ?: g9 e) K -
4 @- i. c. I$ n& u; ]+ e8 U! { - if( mpu_dmp_init() )
6 @& P1 b# Z8 t# a T8 r& C - {
, G- Y; {: |3 t9 J, C9 I - printf("DMP初始化错误!\n");2 i( M# Q, S1 P& C8 g' ]5 D0 {! A
- return 0;
( `/ L! C+ L' I3 K% O. G& @ - }/ l6 k6 g, Q+ m) c% ?
- while(1)
* g/ e6 L# m3 Q6 A, k8 B - {& | X' {4 x% D( K
- if(mpu_dmp_get_data(&pitch,&roll,&yaw)==0)
( h5 `, v# Y A - {
5 F/ n; x& D! F0 A2 ^- m* p - temp=MPU_Get_Temperature(); //得到温度值
" y2 I1 o& v* ^( y; t - MPU_Get_Accelerometer(&aacx,&aacy,&aacz); //得到加速度传感器数据: _* d/ u' d. G5 c
- MPU_Get_Gyroscope(&gyrox,&gyroy,&gyroz); //得到陀螺仪数据
0 P% c' Q7 E. X+ | - }6 Y+ k5 v5 B( G4 b7 K5 c$ o, T
- delay_ms(100);! N' X( W6 X7 N7 T8 E' b
- printf("pitch:%02f roll:%02f yaw:%02f\n",pitch,roll,yaw);
& D1 Z P0 }$ Q) T. s! i - }
q: U5 a$ E1 c) z
* M; l0 O- B. i* Y2 p6 o- }
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 |