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

STM32驱动MPU6050基于IIC协议

[复制链接]
STMCU小助手 发布时间:2022-8-19 16:32
一. 简介
: U, h# O- A6 k3 T. ?4 v7 zMPU6050是一款六轴陀螺仪,可以通过IIC协议输出三个方向上的加速度和角速度,在平衡车和飞控中较为常见。一般情况下,模块有用的引脚只有四个(其它的不常用),即VCC,GND,SDA和SCL。操作它的第一步,即编写IIC协议。
5 P* A/ v' t: Z, O1 e7 g; u
1 \" A5 x8 q( C二. IIC协议
6 {! {+ y' Q" z" P7 ]1 p% t作为三大常用协议之一,掌握它是非常有必要的。IIC为主从协议,分为主机和从机。IIC协议要比SPI要简单那么一点,没有像SPI那样还有模式的配置。下面就简单说说IIC协议。
; l( `; ?+ Z- D" I% x( a+ A  l! jSDA: IIC的数据线
- V" r# I& J( _; V3 f5 F& ESCL:IIC的时钟线
2 M9 G$ h. E" {
' m& ~% h: ^. w/ y0 y+ P0 b1.空闲态: SDA和SCL都为高电平。
+ W4 W, U+ u7 X' s; _, Q7 H7 S2.起始态: 主机将SDA拉低
3 Z, d* K1 H6 m! {0 k3.数据传输: 在SCL为低电平的时候,将数据输出,在SCL为高电平的时候,将数据输入。
% D1 e) m& Z, d7 {6 h7 w8 b4.应答态:在SCL为高电平的时候,检测到SDA为低电平。2 K$ Y9 W9 ^! w+ s
5.非应答态:在SCL为高电平的时候,检测到SDA为高电平。; F: P( Y: w0 J, ^3 D  e
6.停止态:在SCL为高电平的时候,将SDA由低拉高。& w# S4 a2 ]9 h* c0 A
IIC协议一共可以分为这六种状态,接下来将简要说明如何将这六种状态组成一个完整的IIC协议,来驱动MPU6050。
$ W0 [; @+ ]/ e0 N9 c- l2 O2 T  y4 J: m' E+ H' c) ~, o
(1). IIC写0 h1 K) T) ?5 }" R3 y. |; S4 L
数据输出是以一个byte为单位的,从机地址一般为七位,与读写标志一起组成一个byte。0为写,1为读。
, d: p% y/ B: \$ M开始 -》 从机地址 + 0 -》 应答 -》发送寄存器地址 -》 应答 -》 写入数据 -》 非应答(应答) -》 停止# X% N) K8 v# _' T! ?

3 Z2 F$ F& @! K% v* g 058e22e6615e4634b3cf0bf068e78eb0.png
3 Q& x* k9 h. f) N  c
6 I' A5 p' j# H: @(2). IIC读
- O5 {( i6 K! O9 B/ l  J! k( p0 OIIC读数据要比IIC写数据要复杂一点,主要是步骤上多了几步,但是状态什么的都完全一样。0 F5 b9 t- y( h- \
; G+ I! Y4 g# g5 L
开始 -》 从机地址 + 0 -》 应答 -》发送读取寄存器地址 -》 应答 -》开始 -》 从机地址 + 1 -》 读取数据 -》应答 -》 停止
; N* r  y! [5 e' X# F
- T9 |% l  A" D  X可以看到,只要将这几个状态实现了,按照这个流程就可以很容易实现IIC的读和写。大概的时序图如下。
/ [2 N+ x5 h0 k% u- O& G- ?* R/ i. C! p
e33b4e2ddaad4111a83bb7effb127c60.png . I/ K6 `$ [  r- t% |3 @
; E& u; S! X6 Y- ~3 N1 F9 s) R
三. 代码实现0 f. V2 q: r, T" D: b; m- H
根据上面的六个状态,定义出对应的六个函数,对应的只有五个,空闲态忽略,因为经过Stop后,IIC的时钟线和数据线都已经为高了。delay时间需要根据从机所能接受的最大速率来决定,不然的话,会出错,下面就来详细说明这几个函数。
# C3 d. ^0 t- W. f, Z5 x( P) q
* t/ s7 ?' l% k% z4 z5 P. V# N 7782271f917c44fbb10144c37894ab26.png
2 n' H1 o- X9 W) j
4 r, L; i" a% x5 Z7 }8 P(1) MPU6050IICDelay(void)
6 _! o# F# V5 l$ f" A/ c这就不用说明什么了
8 X1 H8 p' }; t' e6 ?
: k' E; |3 ^8 [) L! H' g
  1. void MPU6050IICDelay(void)6 b5 B; x  c) o: m" H
  2. {
    ) k( d# y, o8 U- D) K- O# [
  3.     uint16_t i = 250;
    4 x1 i: `  M( c/ [
  4.     while(i--);# R, W+ `2 j& O9 U2 \, ]' y
  5. }
复制代码
8 p$ L7 V& G0 N
(2) MPU6050IICStart(void)
: [$ X. p# S4 I* t! b: R将SDA配置为输出模式。然后将SCL和SDA全部拉高,dealy后,将SDA拉低,就ok了。
# P% ~& t# c' C5 o/ R& Z  m: l( F: o% o1 G; w3 b
  1. void MPU6050IICStart(void)- U% ~, c3 |2 Z! p3 G# w! P
  2. {
    ; G- O) h* I7 Y) O! U; p
  3.     SetSDAOut();
    & a* p, a0 j7 ?6 s; o) A
  4.     SCLHigh();- }" h, T7 ^! P: E
  5.     SDAHigh();6 \: ?/ j7 g5 h" O  W$ h; X
  6.     MPU6050IICDelay();. u( z0 o; j+ C; l* {
  7.     SDALow();' B1 r  e( L* G- u8 Y
  8.     MPU6050IICDelay();/ ?+ n3 a) S4 @. f4 x
  9. }
复制代码

2 t& h$ p2 ]- O$ _" r(3) MPU6050IICACK(void)
, s: x" ?0 L" r- n这里只包含了从机应答。
  1. void MPU6050IICACK(void)
    3 t6 g: @- g" L, z
  2. {   
    1 F' a7 \+ n$ e1 w4 n
  3.     SCLLow();' f# j! S" i: |  j( K  [
  4.     MPU6050IICDelay();
    2 ~5 k4 Z# S. q$ X. b2 t& h% Z
  5.     SetSDAIn();
    - H" }6 b9 K3 W" U6 i/ q
  6.     MPU6050IICDelay();4 w* B( d4 j. @% K! k
  7.     SCLHigh();7 A' p; f, I' V3 @# V+ Z; v
  8.     MPU6050IICDelay();
    4 K& z4 `8 ]$ ?& C3 B% H7 N
  9.     SDARead();' Y& u. b. W& H  b: P5 E
  10.     MPU6050IICDelay();
    & l; ^7 ?2 H+ Z- e, R1 T5 }6 d
  11.     SCLLow();
    7 t2 C, ~3 n, B( v
  12. }
复制代码
5 j8 F5 i8 [( Y6 s7 g
(4) MPU6050IICStop(void)9 G0 b6 k3 d' P  Z- S" |0 K
停止位这里,需要先将SCL和SDA都拉低,然后先将SCL拉高,后将SDA拉高,
2 c( `, L* a* b* l; Z
" Y7 X3 W2 P2 d' H
  1. void MPU6050IICStop(void)
    . J1 F/ p* {1 O: N# ?0 c8 m  s
  2. {5 K6 d# S: ~- n4 F, K" Q( L( U( @3 A
  3.     SetSDAOut();
    2 `6 _$ Q! W( t% J& H' [
  4.     MPU6050IICDelay();( y) w- [6 v9 R5 z8 Q' O4 e8 w: A
  5.     SCLLow();
    6 r  ?! C0 K. X8 z. j
  6.     MPU6050IICDelay();' r2 j' S: Q  Q$ W- D* V0 U
  7.     SDALow();% ~) B+ ~  p+ }. J
  8.     MPU6050IICDelay();
    $ d' @2 `# J0 b2 C: E7 T2 w
  9.     SCLHigh();
    , ]7 M' L5 W7 x8 I& m/ |% T4 W
  10.     MPU6050IICDelay();
    ; q4 W" v+ K9 ^9 q+ t; k1 p
  11.     SDAHigh();- R  ~+ ]7 j! l* X% s  \; {, Q: I0 Z
  12.     MPU6050IICDelay();+ p" Z' q& m+ z) n1 v3 @
  13. }
复制代码

5 {& G$ ]: N  [# o1 q(5) MPU6050IICWrite(void)
& {0 M$ G3 y; m2 b/ a( l2 E
  1. void MPU6050IICWrite(uint8_t data)( \( S2 X/ g5 s
  2. {
    4 S+ O, p2 ~0 ?/ i& s/ W
  3.     uint8_t i;
      C$ s( m+ D8 i, ~
  4.     SetSDAOut();+ n7 _0 D/ J; J" P3 q9 w# x4 z
  5.     MPU6050IICDelay();
    , H  l1 B8 h; B$ W& q
  6.     for(i = 0 ; i < 8; i++)
    8 p( R5 u* r+ _0 d
  7.     {
    * x. h0 @5 k/ n1 H) j
  8.         SCLLow();
    0 V- Y/ |! A% ?/ o0 K
  9.         MPU6050IICDelay();
    8 L7 f. ?( |5 J* s
  10.         if(data & 0x80)8 y2 {$ G; }3 P3 V+ V
  11.             SDAHigh();
    1 L9 i( \! R9 M5 G4 I
  12.         else
    ) F6 u+ v3 V: \, ~
  13.             SDALow();9 Y& A0 J5 p" ]! {" i
  14.         data = data << 1;, M& B5 T4 r' S6 W. E8 L
  15.         MPU6050IICDelay();& V9 K6 {" ~& e
  16.         SCLHigh();
    6 H7 t! W8 ^# `- m6 Z
  17.         MPU6050IICDelay();. n& t" E! {9 J$ T
  18.     }+ T7 a: h6 v# a9 E1 y* }0 I9 p1 p/ s
  19. }
复制代码
/ w( L/ M8 `6 p9 [: Z
(6) MPU6050IICRead(void)8 X( m9 A' ^0 H; T! {4 j& ]: u: \
  1. uint8_t MPU6050IICRead(void)) d$ p+ [7 @  K0 t+ f' [
  2. {, `1 C( k/ h5 m  L1 [
  3.     uint8_t i;* f) G, `) T1 M
  4.     uint8_t data = 0;6 Q: w7 D, b# s1 H( o$ {+ W1 q
  5.     SetSDAIn();9 S3 a, j5 p1 [# k) E9 {
  6.     MPU6050IICDelay();/ i1 \+ I/ F3 e  Z; J
  7.     for(i = 0;i < 8; i++)  b' x2 ?: w; `8 E7 k% X
  8.     {
    9 F/ d0 {* k/ ^/ ?' ]/ Y
  9.         SCLLow();! B% z; e0 Z+ Q3 B3 @% j* E
  10.         MPU6050IICDelay();
    * Q! {; H9 H. j3 c: p& ?
  11.         SCLHigh();
    ' i# d& V3 H* j  I% k/ u5 L  Z
  12.         MPU6050IICDelay();! H6 A6 ^# Y' _  a; v1 j
  13.         if(SDARead()). _. L: }4 ^  C2 N3 Z2 Y" v& h
  14.             data = data | 0x01;
    $ @4 w) F6 o' D' }  u9 o
  15.         else
    - T6 M: Y3 |/ N( M
  16.             data = data | 0x00;
    # G% Y1 C- B' b
  17.         data = data << 1;- O0 K0 k2 F5 x, v! O  a' i
  18.         MPU6050IICDelay();. R! b) A9 H0 \) P2 \9 B
  19.     }! w) b0 S) D0 m& O' R* m2 i
  20.     return data;
    . o) D. c  v, _* R  R$ ~, r
  21. }
复制代码
0 N9 R/ h* U  @
读写数据,可以搭配时序图来,都是将SCL为低的时候,将数据送出去。在SCL为高的时候,接收数据。5 I2 ?) [/ Z  ?/ X' X: b' G
然后将上面的这几个函数依次组合成读写两个函数: H' c6 [( Z* N* _; I. `

+ x* k& E9 W5 F# F4 [9 `4 F d1195f81776b4ed98491a04c6c6498e4.png
+ @6 T# c. m! q; B
/ z3 k8 D% o0 ~* _9 E$ i这里IIC驱动编写完成。/ n! {8 d3 N& n$ ~& ^

/ |0 \7 f/ p/ l# O* d8 y2 Z四. MPU6050 初始化
1 l4 a& H: A, N$ u9 H$ M初始化的实质就是对寄存器进行配置,这就要查看芯片手册,了解每一个寄存器的作用了,以及初始化的时候寄存器配置的顺序。
& E' ^) s4 i4 S% w0 y7 E2 G/ h这里将重要的寄存器列举出来了. ~" x+ w5 d1 t2 u; f6 b$ s
0 b- z# G9 K* }
  1. #define MPU6050Addr     0xD0' L9 [) V7 G, z  w5 ~7 k5 a
  2. #define ACCEL_XOUT_H    0x3B7 E% L' _/ a; x3 j0 w
  3. #define ACCEL_XOUT_L    0x3C
    $ N* [" f# g1 Y) K1 S
  4. #define ACCEL_YOUT_H    0x3D
    ( j9 {4 R% N; V2 x% W+ q, V  [
  5. #define ACCEL_YOUT_L    0x3E* c7 v' m. q0 q. H8 B- p
  6. #define ACCEL_ZOUT_H    0x3F* O, A# g: v% n6 M9 V: m
  7. #define ACCEL_ZOUT_L    0x40
    6 h+ ^, G. C$ J% D
  8. " |4 k& _( Q1 q1 J( U
  9. #define GYRO_XOUT_H     0x437 f! c0 b+ Z) c/ \
  10. #define GYRO_XOUT_L     0x44
    , J( V3 `* r/ [) \$ n6 X- o
  11. #define GYRO_YOUT_H     0x45
    8 |# D2 }, P' P7 X& X
  12. #define GYRO_YOUT_L     0x46$ M+ c9 O! H$ v2 ^8 m
  13. #define GYRO_ZOUT_H     0x47
    0 |1 p! M. O. W8 q! u( [9 Z
  14. #define GYRO_ZOUT_L     0x487 k! M8 H  T( {- k
  15. : r" p' z3 `3 q
  16. #define PWR_MGMT_1      0x6B# D8 }* o4 P) U% r% w
  17. #define PWR_MGMT_2      0x6C
    0 `% O& \. W8 R% N$ X
  18. #define SMPLRT_DIV      0x19
    1 x1 D. J: K& J) W0 R
  19. #define MPU_CONFIG      0x1A0 d' c! ^6 l" D4 P  |
  20. #define GYRO_CONFIG     0x1B
      p, r) B& _$ J2 _" h' i
  21. #define ACCEL_CONFIG    0x1C
    : V+ [3 o. r8 [# e

  22. / }/ u& E7 |1 K' @
  23. #define MPU6050ID       0x75( o4 ^& F/ g- }1 e" @
复制代码
# p; J- O& W# D5 u( d, s7 V  I
(1). 初始化. U0 A# Y7 H* V( s
  1. /*MPU6050初始化*/$ e) f& o1 ~8 I% h
  2. void MPU6050Init(void)5 z, R, O2 j- n  H) I5 `
  3. {
    5 V$ s% s0 f- k5 L# K/ W# e8 ^
  4.     MPU6050GPIOInit();
    7 B& m5 _' r3 W# T1 R
  5.     MPU6050IICWriteRegister(MPU6050Addr,PWR_MGMT_1,0x80);" ?) E2 u. k" A5 d
  6.     rt_thread_mdelay(100);
    ! W" t; w/ d! s2 b+ d; T& m" W
  7.     MPU6050IICWriteRegister(MPU6050Addr,PWR_MGMT_1,0x00);
    : `5 X1 z, d0 t$ E+ @6 d+ U8 G
  8.     MPU6050IICWriteRegister(MPU6050Addr,SMPLRT_DIV,0x00);
    6 v5 Q5 I. u2 _; Q# P
  9.     MPU6050IICWriteRegister(MPU6050Addr,MPU_CONFIG,0x03);/ z- S6 o3 E$ N  B# l% {* w
  10.     MPU6050IICWriteRegister(MPU6050Addr,GYRO_CONFIG,0x18);// gyro scale  :+-2000°/s$ d3 L) m! }1 |1 w
  11.     MPU6050IICWriteRegister(MPU6050Addr,ACCEL_CONFIG,0x10);// Accel scale :+-8g (65536/16=4096 LSB/g)  
    8 M5 A. j: T, u, Z' |, W
  12.     MPU6050IICWriteRegister(MPU6050Addr,0x6B,0x01);
    & v( f, C! T3 L  [8 x# ?7 @6 l
  13. }   
复制代码
% z4 g: z% [0 O5 N/ I) x/ A
(2)验证
9 I5 l6 V3 V2 e: \& o4 {8 g9 D通过读取芯片的ID,可以确定IIC是否有问题。
  1. /*读取MPU6050的ID*/; [* J1 P" K8 J- |
  2. uint8_t MPU6050GetId(void)  m9 j! o1 A; u" H
  3. {0 l! P* p0 O1 O
  4.     return MPU6050IICReadRegister(MPU6050Addr,MPU6050ID);
    / G7 \# N! N( i
  5. }
复制代码
6 D, W; E4 y; r
分享一个成果图
$ C0 C  u' ]  y: C# H9 E! Z5 h, r- I& b+ \  O8 G' W
7b2d581155e545f69d7e143901417356.png / v/ J. o0 D/ G* f
: C3 b( M3 E* _+ p

& h" \5 b$ L& V" w; F* N# ^8 k+ T& d8 ]9 ~0 H$ a
赞 收藏 评论0 发布时间:2022-8-19 16:32

举报

0个回答

所属标签

相似技术帖

官网相关资源

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