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

STM32F103使用硬件i2c作为从机模式

[复制链接]
aimejia 发布时间:2018-5-23 14:50
一、简单说明. M; o" w% q) _+ a% m7 S) F. I
本例子参考了ST官方历程,官方历程的链接如下
4 W( T+ Q; r: D
$ B1 j* S3 y/ D/ G2 I  Whttp://www.st.com/content/st_com ... /stsw-stm32094.html
- l% j% B* C/ V% y4 F" N1 B( A% K- e4 n6 N& c1 J
关于i2c的协议这里就不做描述了
3 Y0 p' z+ i$ \9 h; U8 d, Y' {) W' n/ ^$ d
关于STM32 i2c的模式可以在中文数据手册中查看
/ Y& ?5 R/ c3 J0 H& C4 C3 E' q( M1 y& X& y/ g6 R
1.png # c# Q. N6 N* \- W' j
$ @0 F- |% n% q) T' q2 `4 w# @
手册中已经描述,该模块默认工作在从模式,要想变为主模式,主要生产一个起始条件。(主模式的代码可以参考野火开发板的硬件i2c历程,本例子中也是使用野火开发板硬件i2c作为主机的)6 B. O1 z* A% U: n0 t1 e3 @1 \
1 {1 H- Y1 x( f
二、i2c从机的配置
* R! I, F( K4 g' M9 X" B! v
  1. [cpp] view plain copy# p8 h7 O4 u6 f  i3 A0 U
  2.     I2C_DeInit(I2C1);  . y' q; I2 }+ E: i  R
  3.     /* I2C1 configuration ------------------------------------------------------*/  
    4 s* A8 P8 o* T3 w: b: G! a
  4.     I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;//模式  
    + N. m5 w( n2 Y. F6 t0 A
  5.     I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;  
    / ^) I- m/ s+ t8 {$ [
  6.     I2C_InitStructure.I2C_OwnAddress1 = I2C_SLAVE_ADDRESS7;//这个就是作为从机的地址,一定要配置正确  
    ) y9 S/ E! ~5 R$ x; R
  7.     I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;  . ^& ~+ D1 A2 H, Q$ O0 V. A, F
  8.     I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;//7位的地址  
    * \+ Q& J1 S( o/ ?" r, l
  9.     I2C_InitStructure.I2C_ClockSpeed = ClockSpeed;  1 }. G* {- @- J& Z% m+ X
  10.     I2C_Init(I2C1, &I2C_InitStructure);  
复制代码
上面配置注意的就是从机地址,这就是主机要查询的从机地址
; T/ {! r9 ]* A# S; ~
( \- a0 B1 T% x6 R4 Q三、i2c从机中断的配置
- t3 S4 x: r- B! v2 o
  1. [cpp] view plain copy
    ) l. E# {% S- Y* q3 i
  2.     /* Configure and enable I2Cx event interrupt -------------------------------*/  
    8 G& y2 C3 m8 I, Q+ {# h
  3.     NVIC_InitStructure.NVIC_IRQChannel = I2C1_EV_IRQn;  ' ~7 q8 b8 G; W0 _0 l. j. P
  4.     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;  
    / y. ^5 W1 t' t  [, y
  5.     NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;  
    ; N7 {4 o3 l0 o( e+ G; c) M
  6.     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;  ! p3 h! o* T# R5 U9 _
  7.     NVIC_Init(&NVIC_InitStructure);  6 e" [2 Y) i: ^' w) ^* C
  8.   8 H+ |2 v' X' @
  9.     /* Configure and enable I2C1 error interrupt -------------------------------*/  
    " b4 G# v' M6 i1 T
  10.     NVIC_InitStructure.NVIC_IRQChannel = I2C1_ER_IRQn;  
    ' B2 C4 ?" g; B3 y1 J! M
  11.     NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;  
    " X& Y% p, o- d2 P  M- D. Q
  12.     NVIC_Init(&NVIC_InitStructure);  
复制代码
标准库中的i2c一共有两个中断# d6 R/ E5 f+ l# z' s
一个是事件中断(EV_IRQ)和一个错误中断(ER_IRQ)
; i# r8 v+ o/ x4 M3 M& MEV_IRQ的中断只要响应EV1 EV2 EV4 之类的,后面会说明
; P( q7 Z% H- `% N3 }& V  XER_IRQ的中断只要响应没有应答和起始和停止条件出错等
+ H- f3 [& M* S& X( R
2 r' P( l7 Y4 q1 P& E& B; D4 @四、使能中断
$ e0 W" ?* `6 I6 b# A( t9 l( U/ e+ s
  1. [cpp] view plain copy
    * H; ~) ]+ F: m
  2. /* Enable I2C1 event and buffer interrupts */  
    + o2 n1 q3 |9 j# k# A# ]
  3.   - o* `! n: k4 E8 L
  4. I2C_ITConfig(I2C1, I2C_IT_EVT | I2C_IT_BUF, ENABLE);  % F$ Z2 M( o& m  ]  Q+ O9 c8 |8 B
  5.   
    # I6 j9 ?! c4 _
  6. /* Enable I2C1 Error interrupts */  
    ! ~7 A' F% _- U( a
  7.   
    3 T, A6 f) ~" F# v
  8. I2C_ITConfig(I2C1, I2C_IT_ERR, ENABLE);  
复制代码
使能了I2C1的这三个中断,每个中断的作用下面说明: ~) q9 @, v- l+ a" q" [

; {: U. F1 s' v五、中断处理函数
1 S! L" E5 C2 X, X8 A; {  l- m
  1. [cpp] view plain copy& P7 @1 l- ?6 O" U
  2. void I2C1_EV_IRQHandler(void)       + ?$ k' B% }1 x1 a5 B
  3.   , n$ ~. A! y% f" i2 s. j
  4. //事件中断处理函数   ; x/ ?) t& W1 g) E1 B1 ^; r
  5.   
    7 x# t" x' m+ g8 @% w6 w
  6. {   
    $ H% \& c( x. z$ K! }! k
  7.   0 ]- N& c% I0 B" Y% ^/ S
  8. switch (I2C_GetLastEvent(I2C1))  
    * e1 v1 _0 g1 f8 P+ r
  9.   ! Y  F( Z8 ^! n! V
  10. //获取i2c1的中断事件   
    + j- V( h2 A2 B6 u5 d9 j2 r1 ^
  11.   % m9 v" C! m( ^4 q! j4 W3 j5 g+ U  N
  12. {   - q; U% t' n; Z2 Q) J8 z
  13.   , @( @6 P8 g, Q- b: T* `. `! U7 ~
  14.   /* Slave Transmitter ---------------------------------------------------*/    ) o- f: ?2 f0 j2 ~" d8 e, Z
  15.   ; t7 s$ @9 @! \) t  X7 C
  16. case I2C_EVENT_SLAVE_BYTE_TRANSMITTED:   . _& ^9 O/ @& P! V0 q
  17.   
    7 U; r7 `$ W3 K
  18.   /* 这个和下面那个都是从发送模式下发送数据的,具体两个的区别我也不是很明白,感觉就是移位寄存器空与非  空的区别,准备好数据发送吧 */   * i" M7 d7 h9 a) \4 L! S6 u& k
  19.   
    8 L  c& D3 D/ x' W  {4 s; ^
  20.   I2C_SendData(I2C1, I2C1_Buffer_Tx[Tx_Idx++]);  ' s9 ~2 C/ v+ S* ^
  21.   
    " \" N8 c. }) w
  22.    break;   7 n  }& c: B! v& _$ O2 ~& h
  23.   
    ' ?3 p" k0 |; n; X  y* q9 r( u3 ]% U
  24. case I2C_EVENT_SLAVE_BYTE_TRANSMITTING:             /* EV3 */      
    $ {/ r0 ~& _1 U. x" D# V
  25.   7 B" M# F* H% I4 k  m
  26.   /* Transmit I2C1 data */  
    $ _8 e) q  W. I( @
  27.   
    % \. {1 R, O5 `& a. F1 b/ F
  28.   I2C_SendData(I2C1, I2C1_Buffer_Tx[Tx_Idx++]);   
    3 h  L9 p2 @; X) Z, x2 G1 {1 d
  29.   
    9 q* ^- S- s. e- b5 r6 @& o
  30.    break;   , z8 _" t; M% g2 r7 H
  31.   ) w* O, a: f1 M/ {1 k, |
  32. /* Slave Receiver ------------------------------------------------------*/   
    9 H& i  n0 {  t: v
  33.   
    , m# f" J; E) B
  34. case I2C_EVENT_SLAVE_RECEIVER_ADDRESS_MATCHED:     /* EV1 */   
    : u6 W8 |. L* L* t
  35.   5 A0 G0 }  q: `" i4 L1 n
  36.   /* 地址匹配中断,不管从发送和接收都要匹配地址,如下图244、243发送地址之后都会响应EV1 */   
      Q( j$ p( m& `4 `: h5 y
  37.   4 z% [- W) O: w% p4 r
  38.   break;   
    9 }/ E: v3 N# W. `. y/ F$ M* ?3 q
  39.   
    1 M) v7 J4 w4 K( L# ~+ m( K" W" z9 p- O* o
  40. case I2C_EVENT_SLAVE_BYTE_RECEIVED:                /* EV2 */   8 H, K2 {. {  s! `3 m& j, ?# V8 S% u
  41.   
    , a# i$ O9 h9 q$ `4 s6 s' }3 f
  42.   /* Store I2C1 received data */   3 ~* o9 O$ g) y  T
  43.   + T7 M7 t: ^& M/ ~4 F
  44.   /* 这个中断就是响应EV2中断,如下图244,每次主机发送完一个数据就会产生一个EV2的中断 */   5 v+ @- Q/ \8 t) L2 A0 o2 R
  45.   
    - k: P' `) J2 }- l. `7 C5 M; G
  46.   I2C1_Buffer_Rx[Rx_Idx++] = I2C_ReceiveData(I2C1);  , Z2 S7 R% V1 J. F# A) F
  47.   $ O* E1 e* O- {# T: {
  48.   /* 把接收到的中断填充到数组中 */   
    ( R$ \. p% m0 y- x
  49.   
    " ^8 I, V; [, _4 p. L' y
  50.   /* 注意:地址不会填充进来的 */  
    ) }# W* Z( e  m5 o
  51.   
    / m( F" y+ Z% o- p, i! m
  52.    break;   + {& e+ v. G! n. j
  53.   6 _# [  i5 j4 i/ `' j( k
  54. case I2C_EVENT_SLAVE_STOP_DETECTED:                /* EV4 */  
    , n$ ]6 l4 |0 A, e( R2 j, ]
  55.   
    6 l* m" p. d' |$ T: L8 T* m
  56.    /* Clear I2C1 STOPF flag */   . H0 X# Y5 @) C/ E9 B/ A# ?
  57.   ) Z% f9 c0 x3 }# ^8 |3 q
  58.   /* 这个就是正常停止的时候产生的一个停止信号 */   
    4 O( z: A4 a7 O6 L1 y! U
  59.   % a/ c# I! h1 k- ]5 N3 ~
  60.   I2C_Cmd(I2C1, ENABLE);   
    : N8 L* J. U, C
  61.   
    ) H# |1 L% m2 M) e( ?' f
  62.   /* 我也不清楚这个为什么要这样,如果接收完一串数据之后,不响应主机的情况可以 关闭i2c,然后在处理完数据后再  从新配置i2c,记得是从新配置 */   
    7 x2 P9 a4 f) j3 @
  63.   
    , k' y; s, M3 s0 ]7 i# F: m' W
  64.   Rx_Idx=0;   1 d, Y5 M$ r* G$ f. i" h
  65.   
    / x# x6 B1 f) x5 R* l. d
  66.   i2c_event = EVENT_OPCOD_NOTYET_READ;   ; e% p! R+ A) |& m* A) H7 u3 y
  67.   0 e) ]& V9 o' m5 B) Y* |4 K
  68.   break;   * f5 t. V0 G& Q: c5 t
  69.   
    ! U; @2 n8 e+ U
  70. default:   
    6 e; }; A0 W% n3 I1 @# q2 _9 b8 m
  71.   
    + [, g+ u& n" ~
  72.   break;      4 ?4 v3 l& S; s. f& s4 J3 K: |
  73.   % T+ h. G+ {$ J5 `
  74.   }   : @, K% p. h4 \2 U
  75.   
    , r9 w$ W, E- @5 z- g0 q
  76. }   
    4 i1 j- E& C1 R4 m9 T$ }% }) j8 m
  77.   
    ) k' W9 u( E3 V  h) s0 l
  78. void I2C1_ER_IRQHandler(void)   4 j" |1 g! T4 G% Y  o& Y6 ]) v  n
  79.   
    % w* L5 G& C  S
  80. {   3 p. u3 a% P* t. }' a3 G
  81.   
    % N2 q) i/ _, ~: N5 W0 E) @  C, M
  82. /* Check on I2C1 AF flag and clear it */   1 a5 c9 m$ i" l* y$ d5 s
  83.   ) }$ c: `8 W! f1 l0 I% o) |
  84. if (I2C_GetITStatus(I2C1, I2C_IT_AF))   : Y- J  p, W* s" n3 s$ K; S( Q
  85.   
    & G: n0 N; G' |8 Y- l4 [0 H# F! `: G
  86. {   
    ( u3 B# [" K) c8 h% m  v0 ^
  87.   
    4 a3 _  U" i/ h9 c2 y7 |# [
  88.   /* 这个就是图243中最后那个没有应答的中断,也就是发送了一串数据后的中断,可以做清零工作 */   
    : k3 G. w8 k3 J: F4 h* Z( t, A
  89.   / j. Q; D" n0 O$ ]) Q/ M& m
  90.   I2C_ClearITPendingBit(I2C1, I2C_IT_AF);   
    2 E8 i3 _5 f4 k8 }6 s. F2 f% |
  91.   , U: K5 o- {" n1 h) A( g) c
  92.   Tx_Idx = 0;   2 f7 I8 h& e; v; P! {& ~
  93.   
    $ d) Z7 {3 r% j
  94.   i2c_event = EVENT_OPCOD_NOTYET_READ;   
    $ B7 f# U2 M0 T* v" w
  95.   
    ; f7 x0 T/ L% A, d) p
  96. }   
    9 O8 U  j* Z; G* t8 U8 L4 r5 r
  97.   
    8 Y7 d0 h- L  h5 X: ^& s3 z
  98. /* Check on I2C1 AF flag and clear it */     c$ B/ [9 Q6 X* N# T# i
  99.   
    ) H0 Y: {4 v6 M- \
  100. if (I2C_GetITStatus(I2C1, I2C_IT_BERR))   //这个就是起始和停止条件出错了  8 W! E4 ~3 H7 y1 _$ U
  101.   3 X* x' e1 ?1 c) X0 T' ~
  102. {   % f5 j& Q6 `; c. e' v- H4 t# E2 ]. y
  103.   ! ~5 i0 N" R  H; W
  104.   I2C_ClearITPendingBit(I2C1, I2C_IT_BERR);  
    6 N4 b- m2 X3 c, M0 T# G
  105.   1 y% v3 c8 b% d1 y. B5 Y+ y
  106.   }  
    7 I# a1 Z$ F9 h, V2 c, R6 E
  107.   ; t( k, f, ^: j: L) J2 i
  108. }  
复制代码
2.png
* N2 u$ Y* G! B% t* M
/ J# p2 n. {7 m" j+ w 3.png ) X$ K  i! }* A2 [1 s5 I+ Y

8 v! a/ K0 R3 S. L5 C0 Y" t7 \1 z7 `; k注意:i2c中断中不要printf打印信息,否则会出错# \5 b- G1 D6 k/ g

& D) j+ E: i0 S$ J主要是参考了官方的历程,然后自己再调整一下逻辑即可使用。( ?* E3 @0 z2 [' L; z3 `

6 v* l8 p; B! w4 r 4.png
+ m( V1 n( n4 I1 H7 b' b
- L' U9 u6 S- ?/ `' Z5 M* P最后的效果感觉还是挺稳定的,这篇文章主要是给大家抛砖引玉的作用,也记录一下自己调试几天的成果。0 C! L* y- \  r. g; J$ t+ t
ST官网的历程还是挺多的,没遇到的知识可以去官网找找。
" l; A1 }, f" Z* s/ h5 `) n0 n
: ]( ]" [4 k! ?0 b* |) F3 Z: r; Z- a$ b9 ^$ b
转载自酱油师兄( u, Z6 r# k" e( {' m- r' ^

- b: T! z/ ]% c9 L, G
赞 收藏 评论0 发布时间:2018-5-23 14:50

举报

0个回答

所属标签

相似技术帖

官网相关资源

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