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

STM32驱动MPU6050基于IIC协议

[复制链接]
STMCU小助手 发布时间:2022-9-7 18:17
一. 简介" {& 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
058e22e6615e4634b3cf0bf068e78eb0.png 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 e33b4e2ddaad4111a83bb7effb127c60.png
; 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
7782271f917c44fbb10144c37894ab26.png ( 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
  1. void MPU6050IICDelay(void)0 S. x" e% T$ L, r' T5 f% n) m
  2. {: H* w0 w  S6 t" |9 Y  p+ R
  3.     uint16_t i = 250;. B& v+ i( s" Q& p) _. D6 [9 \4 K
  4.     while(i--);
    # Y% `3 ^. w, v" ~) p& ?% x
  5. }
复制代码

; 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
  1. void MPU6050IICStart(void)9 \/ {$ D: q! V# h7 k
  2. {
    " A( }; I, d) p4 V
  3.     SetSDAOut();: K+ L! n, g8 |
  4.     SCLHigh();  D& d0 e7 o( ]/ Y3 x2 Z0 g) ~
  5.     SDAHigh();! h4 t, y- n3 V4 u5 f( o- J- Y7 C( `
  6.     MPU6050IICDelay();8 ]. @, }1 \# |4 v6 }
  7.     SDALow();' F* H- c0 Z" ?
  8.     MPU6050IICDelay();# J- u8 d7 Z" {, u! ^# d
  9. }
复制代码

" 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/ ]
  1. void MPU6050IICACK(void)
    / q5 k8 s) j0 Y7 d, ~7 ^
  2. {   5 `7 ^, {/ \# F% [' e
  3.     SCLLow();
    ! L3 S- Q: c7 m
  4.     MPU6050IICDelay();
    9 i# v% D6 o  X# h
  5.     SetSDAIn();, ]$ d4 a" D# N8 \% z+ m
  6.     MPU6050IICDelay();. l; q; o! [, j" L
  7.     SCLHigh();: K; R) A5 }" F: ^! Z" w
  8.     MPU6050IICDelay();; L2 M4 U5 l( Q0 L% o. @! C. e
  9.     SDARead();; S: v$ i+ u% M5 J. ~
  10.     MPU6050IICDelay();/ y6 b% f6 I5 [  b! @8 Z
  11.     SCLLow();
    / a" \. A$ h: {9 C, n
  12. }
复制代码

" 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 |
  1. void MPU6050IICStop(void)6 A9 l' w8 h* L: v; C  B) _
  2. {( y3 Y9 |3 a  V/ D- q! _# U$ R
  3.     SetSDAOut();
    1 _! p. Q' c7 x+ _2 F0 u7 W
  4.     MPU6050IICDelay();
    / ~% m) z3 N  d6 Y& R6 g* Q
  5.     SCLLow();
    0 j# K0 T  R1 t2 f$ T/ V
  6.     MPU6050IICDelay();
    6 \# K! g3 K) N! S/ I( a
  7.     SDALow();
    6 g5 o  @" N' m7 v
  8.     MPU6050IICDelay();6 t8 W+ r* A0 Q5 k& u; a+ G! I& o5 n
  9.     SCLHigh();) \3 P8 N, }; @& i
  10.     MPU6050IICDelay();
    4 w6 m; Y4 M; K9 u0 w
  11.     SDAHigh();
    5 K4 a! s9 v0 f1 m0 w
  12.     MPU6050IICDelay();. O1 B1 p  r9 p4 k* b
  13. }
复制代码
+ l7 o* e5 S7 w# H
(5) MPU6050IICWrite(void)
0 G% g: v% T) N/ Y  M$ V9 S
  1. void MPU6050IICWrite(uint8_t data)
    7 N/ N& J) Z* m) @& u6 \
  2. {
    , n  q* a/ U0 `3 g3 ?
  3.     uint8_t i;" g2 E. S/ \8 L! ]9 i: L* S
  4.     SetSDAOut();: G6 F3 ^: X* _
  5.     MPU6050IICDelay();
    " L3 L  s3 d" z: T% f, v
  6.     for(i = 0 ; i < 8; i++)
    ! O" G! b+ a3 t- w
  7.     {
    5 ?3 L+ Z* _9 v- m
  8.         SCLLow();
    , J+ Q; d& @/ C1 v& f4 d
  9.         MPU6050IICDelay();
    ( A, r, W2 n1 p, U* c( J& W. Z( t
  10.         if(data & 0x80)1 e3 |$ d$ B6 p( y/ |
  11.             SDAHigh();: ?# O& g1 A7 e5 h8 `1 i4 K9 h# R
  12.         else
    % a; l' Z; D- O- x3 _8 O
  13.             SDALow();8 S& b9 S  r/ w" u6 L
  14.         data = data << 1;. e* f8 e7 i+ N6 [; \' H) t
  15.         MPU6050IICDelay();' }, k: n4 {7 j; a
  16.         SCLHigh();6 m3 }! E* e2 P+ \  E% b% m
  17.         MPU6050IICDelay();
    * q( n6 _0 n/ }: X" N9 H) v* C9 \
  18.     }
    ) |% _1 s& U) f
  19. }
复制代码
0 v, d- ?' x/ y2 Y! F' q4 K
(6) MPU6050IICRead(void)
% |5 F$ j$ d4 T3 I
  1. uint8_t MPU6050IICRead(void)
    4 I+ U0 Q6 T# W$ s- p
  2. {
    9 \8 l  Y$ ?* }4 [
  3.     uint8_t i;
    2 M2 x- H: I0 v( O# |+ |
  4.     uint8_t data = 0;4 W/ r5 e  E1 d; M4 ^7 [. u
  5.     SetSDAIn();
    , f+ h" r9 T, s0 `
  6.     MPU6050IICDelay();+ b  F1 Q* c# _# @
  7.     for(i = 0;i < 8; i++)
    ) {4 o! |) q; {
  8.     {8 f: q0 `# e7 R% u9 l/ P0 H
  9.         SCLLow();
    8 ~& G2 H, T' C* x* d2 \( j$ S
  10.         MPU6050IICDelay();8 Q* T0 d2 B$ l; [( w" L
  11.         SCLHigh();( d1 y3 P% D# e9 Y$ W, |7 C
  12.         MPU6050IICDelay();
    1 k# X- V3 @3 h9 C$ b, {% V
  13.         if(SDARead())
    ; d! W: k9 d8 }! `$ y
  14.             data = data | 0x01;6 ]- C% l/ e! M- i& J$ V' n6 M! p
  15.         else
    # l, p7 w  F2 E) V
  16.             data = data | 0x00;* s. w! w0 ?( I- l" v0 l' j8 X
  17.         data = data << 1;
    ! N  ]) U# w( d! o1 T
  18.         MPU6050IICDelay();3 J8 z1 K3 l- z$ w  \
  19.     }5 N3 c( }8 D/ u- k) c) s
  20.     return data;& t2 J8 B' u, d) @4 p9 _
  21. }
复制代码
( 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 d1195f81776b4ed98491a04c6c6498e4.png
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
  1. #define MPU6050Addr     0xD0
    # p$ d8 c8 |  g$ ~) o# A
  2. #define ACCEL_XOUT_H    0x3B
    - w0 V! Z; l7 k# q4 K7 M! l/ f
  3. #define ACCEL_XOUT_L    0x3C
    0 r/ x. t% g/ ?; i
  4. #define ACCEL_YOUT_H    0x3D5 N) m5 ?$ ~9 x, V) b
  5. #define ACCEL_YOUT_L    0x3E
    6 I" u5 f9 O$ m$ r, I
  6. #define ACCEL_ZOUT_H    0x3F
    . H8 D: O/ B$ w1 f8 F; Q* o& m. R
  7. #define ACCEL_ZOUT_L    0x40
    1 ^& ?' Y3 }! i/ p- J+ I7 @  z

  8. # L5 m% O" a$ k: _( b9 x9 [7 ]1 U/ ]% V
  9. #define GYRO_XOUT_H     0x43  {9 Q* S( k# n* C4 F
  10. #define GYRO_XOUT_L     0x44" W. h! V* t, T0 C* J) {2 B% b  }
  11. #define GYRO_YOUT_H     0x45
    , i# U) t& X8 v: P+ ]/ C9 m' e
  12. #define GYRO_YOUT_L     0x46
    8 z% w' i/ r6 K( P0 z6 ]
  13. #define GYRO_ZOUT_H     0x47) d  |6 l, q0 `5 T' ?
  14. #define GYRO_ZOUT_L     0x48$ o4 ?2 p) M  ~; v5 d

  15. ( d4 C1 n) D+ Y, g
  16. #define PWR_MGMT_1      0x6B4 j  F( d" m! F& p$ O& _* T
  17. #define PWR_MGMT_2      0x6C
    , O+ v& {* c: q% x; t
  18. #define SMPLRT_DIV      0x19
    ! e; K; o8 z, l* H
  19. #define MPU_CONFIG      0x1A
    " n/ v/ s8 [8 J5 G+ _6 @# b3 v
  20. #define GYRO_CONFIG     0x1B
    : K+ A3 K" d. B$ g6 \$ \+ d
  21. #define ACCEL_CONFIG    0x1C" {$ x$ J( j  ~- d$ q

  22. & v9 n& k& e, y+ \8 T
  23. #define MPU6050ID       0x75
复制代码
- k* D9 c9 q" i( i
(1). 初始化
6 u) k  k) E" H8 O9 P6 s
  1. /*MPU6050初始化*/
    $ S4 o# P* _# l' J5 x$ V8 u
  2. void MPU6050Init(void)! V6 ?0 I0 k" \% {$ n
  3. {. j  E2 U% m8 r* x
  4.     MPU6050GPIOInit();- y+ d3 m. w% e' L+ B7 Q; \) \7 F. ?
  5.     MPU6050IICWriteRegister(MPU6050Addr,PWR_MGMT_1,0x80);
    1 w9 h5 m  s- t1 C; Y  T2 C& p
  6.     rt_thread_mdelay(100);
    0 s5 w8 Z' M2 V3 N* _
  7.     MPU6050IICWriteRegister(MPU6050Addr,PWR_MGMT_1,0x00);1 i- e- g7 B" o; |0 [
  8.     MPU6050IICWriteRegister(MPU6050Addr,SMPLRT_DIV,0x00);/ _2 k0 u4 Y8 g7 b
  9.     MPU6050IICWriteRegister(MPU6050Addr,MPU_CONFIG,0x03);
    2 N. b  g2 n, R0 j' ~/ p2 V3 p
  10.     MPU6050IICWriteRegister(MPU6050Addr,GYRO_CONFIG,0x18);// gyro scale  :+-2000°/s
    6 [3 X$ k# C) z+ k) _  _
  11.     MPU6050IICWriteRegister(MPU6050Addr,ACCEL_CONFIG,0x10);// Accel scale :+-8g (65536/16=4096 LSB/g)  0 ~4 W5 L3 a/ N# V3 Z
  12.     MPU6050IICWriteRegister(MPU6050Addr,0x6B,0x01);
    ) v1 _( U/ Z7 k. g7 [  q$ H
  13. }   
复制代码
(2)验证
# i2 x- y# q6 O1 ^. w5 S通过读取芯片的ID,可以确定IIC是否有问题。) K) O4 t6 y: l5 @- F( Z3 E+ a7 ~- ]

( m% Z! ~* }! Z
  1. /*读取MPU6050的ID*/
    0 m/ R' X6 |( v* A& x  V' c
  2. uint8_t MPU6050GetId(void)
    ' O- }4 f+ s7 I0 H  C
  3. {
    ; r% w' P. Y- p+ p
  4.     return MPU6050IICReadRegister(MPU6050Addr,MPU6050ID);
    / @5 B1 T; n, q" i* l. `
  5. }
复制代码
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; {
赞 收藏 评论0 发布时间:2022-9-7 18:17

举报

0个回答

所属标签

相似技术帖

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版