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

STM32驱动MPU6050基于IIC协议

[复制链接]
STMCU小助手 发布时间:2022-8-19 16:32
一. 简介
8 x. b. E: H6 R5 E$ c7 kMPU6050是一款六轴陀螺仪,可以通过IIC协议输出三个方向上的加速度和角速度,在平衡车和飞控中较为常见。一般情况下,模块有用的引脚只有四个(其它的不常用),即VCC,GND,SDA和SCL。操作它的第一步,即编写IIC协议。3 K$ ~4 d8 |) j" g( F5 ]

' H& {: G1 A, y0 f+ `# w二. IIC协议  f0 y; K+ x5 I) X" N; l
作为三大常用协议之一,掌握它是非常有必要的。IIC为主从协议,分为主机和从机。IIC协议要比SPI要简单那么一点,没有像SPI那样还有模式的配置。下面就简单说说IIC协议。
1 E1 U) m1 K6 s6 S2 qSDA: IIC的数据线8 R. f7 s6 ?$ ~8 s! b: u( v+ n
SCL:IIC的时钟线
2 d# O( v! T" g3 ], R1 |) H& E0 s
2 J9 p0 r: C4 @" Z7 e1.空闲态: SDA和SCL都为高电平。7 x- m7 ?0 X3 z
2.起始态: 主机将SDA拉低) k" {: C2 ~3 I1 |' Q' @/ S: j
3.数据传输: 在SCL为低电平的时候,将数据输出,在SCL为高电平的时候,将数据输入。& t& {: H  g" a9 Q
4.应答态:在SCL为高电平的时候,检测到SDA为低电平。% J2 n$ a% }8 @; D3 Z
5.非应答态:在SCL为高电平的时候,检测到SDA为高电平。
; Y/ i. s/ y- d6 L6.停止态:在SCL为高电平的时候,将SDA由低拉高。
6 n" B2 q8 p4 k8 m+ V0 p9 [* x2 |& L, GIIC协议一共可以分为这六种状态,接下来将简要说明如何将这六种状态组成一个完整的IIC协议,来驱动MPU6050。
% V# w- U2 v6 }$ A) x5 v5 L, Y+ z2 K  K4 M1 I- ]# E3 I1 }: N" U' x
(1). IIC写+ k5 i$ X0 g: z* D0 l: E, h& Q
数据输出是以一个byte为单位的,从机地址一般为七位,与读写标志一起组成一个byte。0为写,1为读。% v0 ]( B* M4 v
开始 -》 从机地址 + 0 -》 应答 -》发送寄存器地址 -》 应答 -》 写入数据 -》 非应答(应答) -》 停止
+ U$ v' S# n  e  J4 O/ A2 D- x, j$ l
0 d3 h" O* G! \  \/ s 058e22e6615e4634b3cf0bf068e78eb0.png
" a3 r9 [* q! P& i: B2 i; W7 N: L6 z) `" R1 w9 P
(2). IIC读
* q+ j% P$ M' A) Y/ v0 PIIC读数据要比IIC写数据要复杂一点,主要是步骤上多了几步,但是状态什么的都完全一样。7 W0 X: u# x: f% }9 V0 S4 r

  ?6 O4 e& D6 ^0 u开始 -》 从机地址 + 0 -》 应答 -》发送读取寄存器地址 -》 应答 -》开始 -》 从机地址 + 1 -》 读取数据 -》应答 -》 停止
+ P2 O9 E- H! v4 h% O! |, m8 r% `; Z8 N- Y& ]' S
可以看到,只要将这几个状态实现了,按照这个流程就可以很容易实现IIC的读和写。大概的时序图如下。
+ B1 g2 }$ @# h  y8 v4 ~
4 F1 t& Q1 m- e& T e33b4e2ddaad4111a83bb7effb127c60.png " i8 g! [2 B4 ~
9 Q" w+ ?" Z2 j- v
三. 代码实现2 F3 W7 i! @9 F% S, K/ P5 D3 [
根据上面的六个状态,定义出对应的六个函数,对应的只有五个,空闲态忽略,因为经过Stop后,IIC的时钟线和数据线都已经为高了。delay时间需要根据从机所能接受的最大速率来决定,不然的话,会出错,下面就来详细说明这几个函数。
3 {' J* l; _5 K- _6 L7 |2 P1 x" ]. O0 U) i- f
7782271f917c44fbb10144c37894ab26.png
8 z4 }$ u: A, D# o' _; T4 }; ?8 n. E- @/ I* D
(1) MPU6050IICDelay(void)
; h0 X: _! }: Y- c6 v这就不用说明什么了
8 e. U$ F5 K( D$ K1 j! U# M
  ^" E8 u! T! i2 S
  1. void MPU6050IICDelay(void)7 o5 d% V1 w! K# G
  2. {
    4 Y3 s5 B3 v( X
  3.     uint16_t i = 250;
    % k6 T9 I5 s* H$ d9 `
  4.     while(i--);$ n5 S4 N. ~) b8 r. g9 ^- `
  5. }
复制代码

. f# a7 i% j% m  X& T9 B! s(2) MPU6050IICStart(void)4 n. |. E  @5 {6 K6 {# U
将SDA配置为输出模式。然后将SCL和SDA全部拉高,dealy后,将SDA拉低,就ok了。
+ m8 `( M0 ~6 O" q. G
) _7 ]$ R$ ^. N6 B  f
  1. void MPU6050IICStart(void)( y4 f- t+ b1 N8 g& F' S# ~  [
  2. {; J3 Z! M4 c3 h) S
  3.     SetSDAOut();
    3 x, G4 r  i+ p4 D$ u* U) C" R: [
  4.     SCLHigh();% m5 J4 f1 A. k% l
  5.     SDAHigh();0 u. U1 `9 c/ E, X
  6.     MPU6050IICDelay();
      @' F0 Y3 z% V+ u7 L1 V( o! `
  7.     SDALow();
    8 I1 m% s( W# J
  8.     MPU6050IICDelay();2 M5 Y2 m3 Y* H8 N8 P$ b
  9. }
复制代码

# z. \+ n5 T2 b! e- Y4 C  W* D(3) MPU6050IICACK(void)9 G- q/ ]. {1 @( ?2 l
这里只包含了从机应答。
  1. void MPU6050IICACK(void): Q0 ~" t: F* e
  2. {   % u) C9 G8 H" u9 d
  3.     SCLLow();6 z4 g! i* T1 Q' V
  4.     MPU6050IICDelay();
    $ u: x% w1 Z) T) E' T
  5.     SetSDAIn();, o8 u" U! K- }; ~
  6.     MPU6050IICDelay();! l- ~& b- x; t  R7 u) d
  7.     SCLHigh();5 @! L  t3 U, w0 p
  8.     MPU6050IICDelay();
    * ]; j7 k! y* T# ^# i
  9.     SDARead();0 a) p/ U) L% O
  10.     MPU6050IICDelay();
    + D" m2 r$ I4 M+ V5 _9 ~
  11.     SCLLow();
    2 D2 o9 c3 K# W$ a: l
  12. }
复制代码
* X3 _1 W, u4 m1 f, G; C8 y
(4) MPU6050IICStop(void)
: W5 [  }2 c) S3 t% q3 E) z; G* C, U停止位这里,需要先将SCL和SDA都拉低,然后先将SCL拉高,后将SDA拉高,9 S: Q3 A6 w  d' H* A9 A- N

6 m7 G  T- i, X! ^3 T! O
  1. void MPU6050IICStop(void)
    / G' A4 T' [& W9 X
  2. {
    : d" @' @4 o; {, ?: Y5 B- h
  3.     SetSDAOut();' }5 q! W9 H' t- e' a
  4.     MPU6050IICDelay();! D8 Z: D$ C- D  t$ O( `" q
  5.     SCLLow();- C: @! ~  B& T5 n; k: u" s
  6.     MPU6050IICDelay();# m0 w  N) P5 @& v' W2 r
  7.     SDALow();8 V! O; S- o/ n9 [5 k0 [
  8.     MPU6050IICDelay();% H6 C( S' K* u7 i
  9.     SCLHigh();
    + L- e  J/ p5 d* l
  10.     MPU6050IICDelay();
    ) d4 i5 I3 e8 b" h* Z
  11.     SDAHigh();/ d# t% {0 l; e) J  {: E
  12.     MPU6050IICDelay();$ ^2 W1 h+ S( A; D
  13. }
复制代码

/ L/ o$ p3 ~7 `3 F+ A) a$ x(5) MPU6050IICWrite(void)  ^7 U7 U. S* J" h! y
  1. void MPU6050IICWrite(uint8_t data)
      x0 @. k- B/ z5 ?) w) e/ j9 j
  2. {, H! A* [4 v: h+ m# ]* X
  3.     uint8_t i;
      j* _) ?7 q) W/ j0 X! u' H/ c
  4.     SetSDAOut();' }3 ^# P- L6 t" g2 Q! [! F' `# h
  5.     MPU6050IICDelay();  m9 t2 O8 i6 ]% t% g7 C
  6.     for(i = 0 ; i < 8; i++)
    ! ^: J$ [# v% `+ Q0 b7 Z0 @9 [" z
  7.     {. R" c3 g, g  B: d
  8.         SCLLow();( o% y, G: U5 |9 \. f
  9.         MPU6050IICDelay();6 _4 s8 f' q  r% ?8 m9 X
  10.         if(data & 0x80)" ~1 w4 `/ v2 r8 g) i
  11.             SDAHigh();& d6 y# E/ O  i! P1 ?2 H6 ?
  12.         else8 B* {4 q; g) b. x+ ~9 Q6 \
  13.             SDALow();+ w, u7 z. H8 J; M6 s2 b4 p# N$ E
  14.         data = data << 1;7 z; {8 J* F* J8 L+ r8 i2 K% w% D
  15.         MPU6050IICDelay();  G/ v9 u' p* m& A3 R
  16.         SCLHigh();
    & Q# {9 h# v3 U
  17.         MPU6050IICDelay();" z  T( A$ p6 m( t8 `4 d4 t' [9 U+ a; n
  18.     }& r/ S/ D$ I/ k4 U
  19. }
复制代码
9 O! k. P+ ]' Y% k8 b- `
(6) MPU6050IICRead(void)( X6 S  m7 l( T( T+ P6 Y
  1. uint8_t MPU6050IICRead(void)6 c' I' u; q' [7 ]
  2. {
    0 ~. a' I3 }$ ~, }! K
  3.     uint8_t i;+ G9 t& ]8 L9 a& S& ^4 n% v
  4.     uint8_t data = 0;
    % T/ P- X7 w5 f6 O* l: b
  5.     SetSDAIn();* [) J9 Z7 ?: S  ~$ r) L1 i  S) {
  6.     MPU6050IICDelay();
    1 E( n' X4 E9 x. r  i' ~9 H6 Z
  7.     for(i = 0;i < 8; i++)$ W7 ^, l/ |3 U4 a1 J
  8.     {1 U) K+ t4 O6 ~
  9.         SCLLow();
    : M* O3 @- C6 W& B
  10.         MPU6050IICDelay();
    6 I' @3 S- M" S& j% B, l2 R3 o
  11.         SCLHigh();
    % S; o1 T, ?$ g3 ^7 D, @! `2 f
  12.         MPU6050IICDelay();
      I. n/ R& m5 O
  13.         if(SDARead())
    % Q: @, V/ g/ l( w1 h7 Q
  14.             data = data | 0x01;
    ! F6 e7 k& j, E# a
  15.         else
    * U" O; k8 p) M1 G+ v
  16.             data = data | 0x00;
    / L: _3 [& j% Z8 q) y* z0 b" _
  17.         data = data << 1;% M, I( ^. H& M/ X- w
  18.         MPU6050IICDelay();
    ' v# \9 A7 s4 @7 V
  19.     }
    . O* t/ q3 i6 T7 S, d, d
  20.     return data;
    / {" m/ y; A! r' M6 _$ N
  21. }
复制代码
' J1 r2 P% ?3 ^% D$ M" Y5 t
读写数据,可以搭配时序图来,都是将SCL为低的时候,将数据送出去。在SCL为高的时候,接收数据。
7 Y  f) `3 D) Z2 h, }& u然后将上面的这几个函数依次组合成读写两个函数
4 f# z. r1 ^! r; X
% G! S1 D9 u: V, z9 I( B. Y d1195f81776b4ed98491a04c6c6498e4.png * L3 O7 }. F* d! C+ _
3 Z1 S7 w$ r4 `  S  y: w- K
这里IIC驱动编写完成。2 }3 }9 x0 Y% W1 }# ]1 E# c5 y

2 g) T7 f5 W. r; {3 |# l四. MPU6050 初始化
1 y3 d4 T: C% d初始化的实质就是对寄存器进行配置,这就要查看芯片手册,了解每一个寄存器的作用了,以及初始化的时候寄存器配置的顺序。5 k# T; h. O5 z8 D: Y
这里将重要的寄存器列举出来了0 V+ n+ x- p/ w, N
0 B( U5 V5 Z; W$ a1 Q
  1. #define MPU6050Addr     0xD0
    ) }. I" V2 {: Z$ d* A
  2. #define ACCEL_XOUT_H    0x3B
    * ~, [1 P" z! O
  3. #define ACCEL_XOUT_L    0x3C
    0 U, _! t) [$ e! F# E) M- p
  4. #define ACCEL_YOUT_H    0x3D" A7 H$ v- x& M8 q" G& Q
  5. #define ACCEL_YOUT_L    0x3E4 Q" y. k1 n# E4 D1 }" y6 i' z
  6. #define ACCEL_ZOUT_H    0x3F# D8 ]' ?1 G& U( I5 Z
  7. #define ACCEL_ZOUT_L    0x40& N: v+ ~: M0 X  m- f* D. w( d! Z

  8. 2 V% i1 P9 [3 ~1 B! A' H( X# ?
  9. #define GYRO_XOUT_H     0x43
    4 `$ I  N2 K9 Q+ N
  10. #define GYRO_XOUT_L     0x44
    2 ^$ a% _' g0 b5 v( h9 b  V
  11. #define GYRO_YOUT_H     0x459 U  A; q1 @& N; w
  12. #define GYRO_YOUT_L     0x46
    # y9 M7 e: A0 x3 c7 s, f
  13. #define GYRO_ZOUT_H     0x47! T1 z- d, y6 J$ |" a  q; s
  14. #define GYRO_ZOUT_L     0x48
    - k6 M2 C/ k" F4 {2 Q4 \

  15. , q6 W% x( i5 l+ A# }
  16. #define PWR_MGMT_1      0x6B
    ' z  H! L9 _( }5 \" h) s
  17. #define PWR_MGMT_2      0x6C6 [3 M+ u3 k/ l/ E, d/ q' |
  18. #define SMPLRT_DIV      0x19
    ; F3 x& S- B' h# R
  19. #define MPU_CONFIG      0x1A! _# Y3 h0 A, F+ ~
  20. #define GYRO_CONFIG     0x1B
    # S0 N. x) b3 t$ Z
  21. #define ACCEL_CONFIG    0x1C
    2 C  r/ B8 r" F3 d* |# h0 j
  22. ( l7 g; P) C9 J, W! E+ r7 K. s7 w: E
  23. #define MPU6050ID       0x757 i7 R7 R9 V& M9 T9 Z) |& v
复制代码
7 |2 ]5 E/ e0 u: J$ z0 E# [
(1). 初始化% C: _1 X. b$ H
  1. /*MPU6050初始化*/) u+ t$ U& t3 t( B
  2. void MPU6050Init(void)6 G# ?# s3 i6 [" @
  3. {% G# O/ P. @& `1 _. z# t
  4.     MPU6050GPIOInit();3 j# y5 p2 C$ u# G& J" }
  5.     MPU6050IICWriteRegister(MPU6050Addr,PWR_MGMT_1,0x80);/ |* P* ?/ V. @
  6.     rt_thread_mdelay(100);2 A" i8 H, c1 X( n) z5 H
  7.     MPU6050IICWriteRegister(MPU6050Addr,PWR_MGMT_1,0x00);0 T, Y. c; D+ k6 c) E  L
  8.     MPU6050IICWriteRegister(MPU6050Addr,SMPLRT_DIV,0x00);) d3 v8 {" }1 y  T  g
  9.     MPU6050IICWriteRegister(MPU6050Addr,MPU_CONFIG,0x03);
    9 s# M9 |& m# S7 t5 N0 t# \0 C
  10.     MPU6050IICWriteRegister(MPU6050Addr,GYRO_CONFIG,0x18);// gyro scale  :+-2000°/s, }" A; A/ P- k) \4 y9 n
  11.     MPU6050IICWriteRegister(MPU6050Addr,ACCEL_CONFIG,0x10);// Accel scale :+-8g (65536/16=4096 LSB/g)  9 V& R: t$ p& _; s
  12.     MPU6050IICWriteRegister(MPU6050Addr,0x6B,0x01);4 b& c  ]9 {4 z! S
  13. }   
复制代码
1 V; f3 n. v! H/ I7 Y
(2)验证
* w, D7 @* a' G通过读取芯片的ID,可以确定IIC是否有问题。
  1. /*读取MPU6050的ID*/8 r' {, N4 z3 i9 N7 A0 h
  2. uint8_t MPU6050GetId(void)9 `9 ~4 o8 z; c' V4 C
  3. {
    7 L1 O+ z- S6 L: y. b
  4.     return MPU6050IICReadRegister(MPU6050Addr,MPU6050ID);! N# B" G3 u- ^9 A/ o
  5. }
复制代码
) O0 x% A. ?( e, g
分享一个成果图
+ L- c7 ?* z+ c8 ]5 d5 i, W' T2 j/ q: \- z7 P4 z2 }( o. d4 I
7b2d581155e545f69d7e143901417356.png $ Y1 {2 z* N8 q  b: r& @
/ X: A% C* x/ k- ?! u( p  S0 G. Q4 v

$ u# H% U! N# }' ?6 v2 a& n( Y& h- _9 G. T) [$ ~) O, ?
赞 收藏 评论0 发布时间:2022-8-19 16:32

举报

0个回答

所属标签

相似技术帖

官网相关资源

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