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