一. 简介" {& q1 T3 K2 ^; E# e2 T
MPU6050是一款六轴陀螺仪,可以通过IIC协议输出三个方向上的加速度和角速度,在平衡车和飞控中较为常见。一般情况下,模块有用的引脚只有四个(其它的不常用),即VCC,GND,SDA和SCL。操作它的第一步,即编写IIC协议。# X: W7 ?6 [: K! y
, _+ n; f1 s6 _0 `% a5 S二. IIC协议
( g7 x4 a/ H) c) u% x. ?0 e作为三大常用协议之一,掌握它是非常有必要的。IIC为主从协议,分为主机和从机。IIC协议要比SPI要简单那么一点,没有像SPI那样还有模式的配置。下面就简单说说IIC协议。$ L' y: k5 Y5 ~* W1 C
SDA: IIC的数据线
7 U! D6 g- Y/ C: z/ L* a o, X3 _SCL:IIC的时钟线9 ?2 |, |$ f7 `$ r4 ~
空闲态: SDA和SCL都为高电平。
2 P9 ~$ W7 i5 N# k6 M) W. H4 q b起始态: 主机将SDA拉低
3 o8 J O. L/ c ?8 I$ Z9 f数据传输: 在SCL为低电平的时候,将数据输出,在SCL为高电平的时候,将数据输入。, W( Q! r# i8 q- w5 \! q. \0 f
应答态:在SCL为高电平的时候,检测到SDA为低电平。# h; J1 L* D2 q7 h& w
非应答态:在SCL为高电平的时候,检测到SDA为高电平。% ~$ n3 Y' p% g. V5 Z7 ]& ]1 F
停止态:在SCL为高电平的时候,将SDA由低拉高。 V- f \6 j- t4 g/ x, S9 Q7 h8 U! Q0 E
IIC协议一共可以分为这六种状态,接下来将简要说明如何将这六种状态组成一个完整的IIC协议,来驱动MPU6050。
, |/ i0 c" ~! G7 s# t) E
0 {4 s2 v5 e& Y9 E$ k+ T6 y: ^, X(1). IIC写: ]/ ~. I- T' X. E$ t G( S6 L
数据输出是以一个byte为单位的,从机地址一般为七位,与读写标志一起组成一个byte。0为写,1为读。
( k; G1 O) t; f J% H开始 -》 从机地址 + 0 -》 应答 -》发送寄存器地址 -》 应答 -》 写入数据 -》 非应答(应答) -》 停止
0 x4 k9 Z5 P! l: w3 N- R% R7 B+ Q# O0 C3 U1 Z+ Y
1 ~# H4 i8 @( o0 y# e T- F
9 S' }1 k% A* ?/ E$ ~8 e5 E7 ^& P(2). IIC读
* ]; a5 G# Y1 B9 W3 q9 M! A+ YIIC读数据要比IIC写数据要复杂一点,主要是步骤上多了几步,但是状态什么的都完全一样。! {! o: E# h/ |4 r
% R; S" o6 b0 ?, d7 l( r" h& | P
开始 -》 从机地址 + 0 -》 应答 -》发送读取寄存器地址 -》 应答 -》开始 -》 从机地址 + 1 -》 读取数据 -》应答 -》 停止& H2 k7 e. v, \! K$ `1 C# h
3 d; b- X& }7 Z0 U ?7 C7 a+ r4 p可以看到,只要将这几个状态实现了,按照这个流程就可以很容易实现IIC的读和写。大概的时序图如下。
+ {) a$ B+ w) g6 p4 R5 p3 H& Y1 U j
# f W- E& V' B
; V. q) |" W* S I7 w5 U: H5 T, c/ m/ Q1 h7 k2 _
三. 代码实现% |+ @2 t9 G9 g$ B( D) Q/ Y
根据上面的六个状态,定义出对应的六个函数,对应的只有五个,空闲态忽略,因为经过Stop后,IIC的时钟线和数据线都已经为高了。delay时间需要根据从机所能接受的最大速率来决定,不然的话,会出错,下面就来详细说明这几个函数。
$ u4 E" t& ~: U+ c W+ H& U3 I. q, T0 A' J9 S
( S+ F, U' [2 k8 P$ ^
% X3 L' i" |- t4 A% M(1) MPU6050IICDelay(void)7 A2 R0 e8 t( V% h7 p! j& a
这就不用说明什么了
0 K; a9 G2 u% |( D
" Q4 ?. I: L4 m' _/ _/ o- void MPU6050IICDelay(void)0 S. x" e% T$ L, r' T5 f% n) m
- {: H* w0 w S6 t" |9 Y p+ R
- uint16_t i = 250;. B& v+ i( s" Q& p) _. D6 [9 \4 K
- while(i--);
# Y% `3 ^. w, v" ~) p& ?% x - }
复制代码
; U7 [- A+ [: R3 g/ A- E8 R1 b(2) MPU6050IICStart(void)
. e% n' ?1 `$ L8 K% Z将SDA配置为输出模式。然后将SCL和SDA全部拉高,dealy后,将SDA拉低,就ok了。
4 l0 n, g, ^0 r) j0 f) z; a- ?" n, V& X
- void MPU6050IICStart(void)9 \/ {$ D: q! V# h7 k
- {
" A( }; I, d) p4 V - SetSDAOut();: K+ L! n, g8 |
- SCLHigh(); D& d0 e7 o( ]/ Y3 x2 Z0 g) ~
- SDAHigh();! h4 t, y- n3 V4 u5 f( o- J- Y7 C( `
- MPU6050IICDelay();8 ]. @, }1 \# |4 v6 }
- SDALow();' F* H- c0 Z" ?
- MPU6050IICDelay();# J- u8 d7 Z" {, u! ^# d
- }
复制代码
" w; x' d7 i7 k' C2 _( J(3) MPU6050IICACK(void)
$ w) z% A/ L' a( h) c4 ` u3 u这里只包含了从机应答。
y: S; B0 a5 Z$ p) H+ v
* X0 I5 j& b# a4 C7 Z+ I& i/ ]- void MPU6050IICACK(void)
/ q5 k8 s) j0 Y7 d, ~7 ^ - { 5 `7 ^, {/ \# F% [' e
- SCLLow();
! L3 S- Q: c7 m - MPU6050IICDelay();
9 i# v% D6 o X# h - SetSDAIn();, ]$ d4 a" D# N8 \% z+ m
- MPU6050IICDelay();. l; q; o! [, j" L
- SCLHigh();: K; R) A5 }" F: ^! Z" w
- MPU6050IICDelay();; L2 M4 U5 l( Q0 L% o. @! C. e
- SDARead();; S: v$ i+ u% M5 J. ~
- MPU6050IICDelay();/ y6 b% f6 I5 [ b! @8 Z
- SCLLow();
/ a" \. A$ h: {9 C, n - }
复制代码
" o: }& A7 _6 ?, P* Q(4) MPU6050IICStop(void)
5 `1 c q' w( W停止位这里,需要先将SCL和SDA都拉低,然后先将SCL拉高,后将SDA拉高,* r! f. e/ O( y4 \
( D" h L0 z A; w8 D. A3 |- void MPU6050IICStop(void)6 A9 l' w8 h* L: v; C B) _
- {( y3 Y9 |3 a V/ D- q! _# U$ R
- SetSDAOut();
1 _! p. Q' c7 x+ _2 F0 u7 W - MPU6050IICDelay();
/ ~% m) z3 N d6 Y& R6 g* Q - SCLLow();
0 j# K0 T R1 t2 f$ T/ V - MPU6050IICDelay();
6 \# K! g3 K) N! S/ I( a - SDALow();
6 g5 o @" N' m7 v - MPU6050IICDelay();6 t8 W+ r* A0 Q5 k& u; a+ G! I& o5 n
- SCLHigh();) \3 P8 N, }; @& i
- MPU6050IICDelay();
4 w6 m; Y4 M; K9 u0 w - SDAHigh();
5 K4 a! s9 v0 f1 m0 w - MPU6050IICDelay();. O1 B1 p r9 p4 k* b
- }
复制代码 + l7 o* e5 S7 w# H
(5) MPU6050IICWrite(void)
0 G% g: v% T) N/ Y M$ V9 S- void MPU6050IICWrite(uint8_t data)
7 N/ N& J) Z* m) @& u6 \ - {
, n q* a/ U0 `3 g3 ? - uint8_t i;" g2 E. S/ \8 L! ]9 i: L* S
- SetSDAOut();: G6 F3 ^: X* _
- MPU6050IICDelay();
" L3 L s3 d" z: T% f, v - for(i = 0 ; i < 8; i++)
! O" G! b+ a3 t- w - {
5 ?3 L+ Z* _9 v- m - SCLLow();
, J+ Q; d& @/ C1 v& f4 d - MPU6050IICDelay();
( A, r, W2 n1 p, U* c( J& W. Z( t - if(data & 0x80)1 e3 |$ d$ B6 p( y/ |
- SDAHigh();: ?# O& g1 A7 e5 h8 `1 i4 K9 h# R
- else
% a; l' Z; D- O- x3 _8 O - SDALow();8 S& b9 S r/ w" u6 L
- data = data << 1;. e* f8 e7 i+ N6 [; \' H) t
- MPU6050IICDelay();' }, k: n4 {7 j; a
- SCLHigh();6 m3 }! E* e2 P+ \ E% b% m
- MPU6050IICDelay();
* q( n6 _0 n/ }: X" N9 H) v* C9 \ - }
) |% _1 s& U) f - }
复制代码 0 v, d- ?' x/ y2 Y! F' q4 K
(6) MPU6050IICRead(void)
% |5 F$ j$ d4 T3 I- uint8_t MPU6050IICRead(void)
4 I+ U0 Q6 T# W$ s- p - {
9 \8 l Y$ ?* }4 [ - uint8_t i;
2 M2 x- H: I0 v( O# |+ | - uint8_t data = 0;4 W/ r5 e E1 d; M4 ^7 [. u
- SetSDAIn();
, f+ h" r9 T, s0 ` - MPU6050IICDelay();+ b F1 Q* c# _# @
- for(i = 0;i < 8; i++)
) {4 o! |) q; { - {8 f: q0 `# e7 R% u9 l/ P0 H
- SCLLow();
8 ~& G2 H, T' C* x* d2 \( j$ S - MPU6050IICDelay();8 Q* T0 d2 B$ l; [( w" L
- SCLHigh();( d1 y3 P% D# e9 Y$ W, |7 C
- MPU6050IICDelay();
1 k# X- V3 @3 h9 C$ b, {% V - if(SDARead())
; d! W: k9 d8 }! `$ y - data = data | 0x01;6 ]- C% l/ e! M- i& J$ V' n6 M! p
- else
# l, p7 w F2 E) V - data = data | 0x00;* s. w! w0 ?( I- l" v0 l' j8 X
- data = data << 1;
! N ]) U# w( d! o1 T - MPU6050IICDelay();3 J8 z1 K3 l- z$ w \
- }5 N3 c( }8 D/ u- k) c) s
- return data;& t2 J8 B' u, d) @4 p9 _
- }
复制代码 ( A4 n+ k- Y. ?1 @5 G& ^. p& J# m# c6 G
读写数据,可以搭配时序图来,都是将SCL为低的时候,将数据送出去。在SCL为高的时候,接收数据。
6 g1 F: L: p# b, c I$ t% r* T然后将上面的这几个函数依次组合成读写两个函数# f7 L, {; y& S
2 `# X/ ]* t$ \- v# o
3 V# f% S/ u8 J3 p& i6 _0 j' j! g# v+ ~
这里IIC驱动编写完成。- U s- ~6 t3 B3 E
" s" G o' r4 S# ?& m+ c四. MPU6050 初始化
0 R2 ^4 W4 s- u9 |+ l初始化的实质就是对寄存器进行配置,这就要查看芯片手册,了解每一个寄存器的作用了,以及初始化的时候寄存器配置的顺序。
/ P: ?0 |% e7 s3 e这里将重要的寄存器列举出来了
/ b7 o, l% y: X* q! N! ^- R( s9 C
- {7 ?2 Z+ f) N; I4 n+ _# b- #define MPU6050Addr 0xD0
# p$ d8 c8 | g$ ~) o# A - #define ACCEL_XOUT_H 0x3B
- w0 V! Z; l7 k# q4 K7 M! l/ f - #define ACCEL_XOUT_L 0x3C
0 r/ x. t% g/ ?; i - #define ACCEL_YOUT_H 0x3D5 N) m5 ?$ ~9 x, V) b
- #define ACCEL_YOUT_L 0x3E
6 I" u5 f9 O$ m$ r, I - #define ACCEL_ZOUT_H 0x3F
. H8 D: O/ B$ w1 f8 F; Q* o& m. R - #define ACCEL_ZOUT_L 0x40
1 ^& ?' Y3 }! i/ p- J+ I7 @ z
# L5 m% O" a$ k: _( b9 x9 [7 ]1 U/ ]% V- #define GYRO_XOUT_H 0x43 {9 Q* S( k# n* C4 F
- #define GYRO_XOUT_L 0x44" W. h! V* t, T0 C* J) {2 B% b }
- #define GYRO_YOUT_H 0x45
, i# U) t& X8 v: P+ ]/ C9 m' e - #define GYRO_YOUT_L 0x46
8 z% w' i/ r6 K( P0 z6 ] - #define GYRO_ZOUT_H 0x47) d |6 l, q0 `5 T' ?
- #define GYRO_ZOUT_L 0x48$ o4 ?2 p) M ~; v5 d
( d4 C1 n) D+ Y, g- #define PWR_MGMT_1 0x6B4 j F( d" m! F& p$ O& _* T
- #define PWR_MGMT_2 0x6C
, O+ v& {* c: q% x; t - #define SMPLRT_DIV 0x19
! e; K; o8 z, l* H - #define MPU_CONFIG 0x1A
" n/ v/ s8 [8 J5 G+ _6 @# b3 v - #define GYRO_CONFIG 0x1B
: K+ A3 K" d. B$ g6 \$ \+ d - #define ACCEL_CONFIG 0x1C" {$ x$ J( j ~- d$ q
& v9 n& k& e, y+ \8 T- #define MPU6050ID 0x75
复制代码 - k* D9 c9 q" i( i
(1). 初始化
6 u) k k) E" H8 O9 P6 s- /*MPU6050初始化*/
$ S4 o# P* _# l' J5 x$ V8 u - void MPU6050Init(void)! V6 ?0 I0 k" \% {$ n
- {. j E2 U% m8 r* x
- MPU6050GPIOInit();- y+ d3 m. w% e' L+ B7 Q; \) \7 F. ?
- MPU6050IICWriteRegister(MPU6050Addr,PWR_MGMT_1,0x80);
1 w9 h5 m s- t1 C; Y T2 C& p - rt_thread_mdelay(100);
0 s5 w8 Z' M2 V3 N* _ - MPU6050IICWriteRegister(MPU6050Addr,PWR_MGMT_1,0x00);1 i- e- g7 B" o; |0 [
- MPU6050IICWriteRegister(MPU6050Addr,SMPLRT_DIV,0x00);/ _2 k0 u4 Y8 g7 b
- MPU6050IICWriteRegister(MPU6050Addr,MPU_CONFIG,0x03);
2 N. b g2 n, R0 j' ~/ p2 V3 p - MPU6050IICWriteRegister(MPU6050Addr,GYRO_CONFIG,0x18);// gyro scale :+-2000°/s
6 [3 X$ k# C) z+ k) _ _ - MPU6050IICWriteRegister(MPU6050Addr,ACCEL_CONFIG,0x10);// Accel scale :+-8g (65536/16=4096 LSB/g) 0 ~4 W5 L3 a/ N# V3 Z
- MPU6050IICWriteRegister(MPU6050Addr,0x6B,0x01);
) v1 _( U/ Z7 k. g7 [ q$ H - }
复制代码 (2)验证
# i2 x- y# q6 O1 ^. w5 S通过读取芯片的ID,可以确定IIC是否有问题。) K) O4 t6 y: l5 @- F( Z3 E+ a7 ~- ]
( m% Z! ~* }! Z- /*读取MPU6050的ID*/
0 m/ R' X6 |( v* A& x V' c - uint8_t MPU6050GetId(void)
' O- }4 f+ s7 I0 H C - {
; r% w' P. Y- p+ p - return MPU6050IICReadRegister(MPU6050Addr,MPU6050ID);
/ @5 B1 T; n, q" i* l. ` - }
复制代码 5 T/ F+ W; ^$ ?
————————————————% W& B8 E9 ~0 h8 b
版权声明:ValentineHP$ z6 l1 m8 K" T
! [5 f4 x7 L; {0 [9 F
{: g- X( k" ]: V8 _$ x
: j3 J7 r2 [4 K" Q; { |