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

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

[复制链接]
aimejia 发布时间:2018-5-23 14:50
一、简单说明% `# l- N+ ], Z& O6 k1 L5 r: T
本例子参考了ST官方历程,官方历程的链接如下4 V" H1 n; A$ I" i' x+ y% o$ ^8 k$ n

; J! Y6 Y9 o; G5 e& o* Ihttp://www.st.com/content/st_com ... /stsw-stm32094.html' F  b! q+ d$ s9 W  C% V) ]
! s# I: p; `3 @: H( M) M/ M
关于i2c的协议这里就不做描述了  b0 E( q. f/ Y6 `$ z2 U& F

2 e9 X, B% g% g关于STM32 i2c的模式可以在中文数据手册中查看9 L6 w; n& Y/ T; H6 q6 {* F  p' T

/ J# S4 Q) l( X8 }3 z 1.png
3 h& P3 L% @! t$ {8 ]( Z  |) f9 K6 }) V8 v# }$ C/ d# g0 |# @
手册中已经描述,该模块默认工作在从模式,要想变为主模式,主要生产一个起始条件。(主模式的代码可以参考野火开发板的硬件i2c历程,本例子中也是使用野火开发板硬件i2c作为主机的), w1 E& c" j4 @6 I+ A: T) ]

  _6 ]; v6 o4 V; B二、i2c从机的配置# R4 k# H" F! `7 C) ^9 y5 @* ?
  1. [cpp] view plain copy
    " Q% T7 v4 X4 \
  2.     I2C_DeInit(I2C1);  1 f1 C8 U7 J7 l
  3.     /* I2C1 configuration ------------------------------------------------------*/  
    9 p9 H! B* d7 ?+ J5 J
  4.     I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;//模式  
    3 U3 E: [4 w5 ^4 a3 _7 l2 E
  5.     I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;  
    5 ]* ]( F6 u( o' Z
  6.     I2C_InitStructure.I2C_OwnAddress1 = I2C_SLAVE_ADDRESS7;//这个就是作为从机的地址,一定要配置正确  ; Z0 [4 o2 `9 l! o
  7.     I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;  
    3 _9 f7 I# W, A2 t5 @. _
  8.     I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;//7位的地址  ; p- w3 ~- Z% m0 s6 a) z! n9 x
  9.     I2C_InitStructure.I2C_ClockSpeed = ClockSpeed;  * Y! m& P0 k# {& w/ _
  10.     I2C_Init(I2C1, &I2C_InitStructure);  
复制代码
上面配置注意的就是从机地址,这就是主机要查询的从机地址
) L5 n5 c1 m3 I  K) f# [8 d1 y: k$ s2 V. R# |2 X
三、i2c从机中断的配置
  ^# B3 {3 p& s9 B& u" u
  1. [cpp] view plain copy
    * p9 h) ~; N% G1 L3 V
  2.     /* Configure and enable I2Cx event interrupt -------------------------------*/  : n0 j! a) k+ ?/ J$ W9 ~
  3.     NVIC_InitStructure.NVIC_IRQChannel = I2C1_EV_IRQn;  + t& G  i& I$ D% |0 ?/ i& c
  4.     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;  ; m( A$ |$ [6 E- C  L( K
  5.     NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;  8 b, _; p% h& C+ C2 ~
  6.     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;  & y: k  M' l- m5 l
  7.     NVIC_Init(&NVIC_InitStructure);  
    ! T: o8 [) {0 F6 n3 |6 o
  8.   
    - l' d# g) X: f# D- \
  9.     /* Configure and enable I2C1 error interrupt -------------------------------*/  
    3 K4 o- e) f+ |3 H
  10.     NVIC_InitStructure.NVIC_IRQChannel = I2C1_ER_IRQn;  
    1 [# E  W& ]' d+ {' c4 E( T; R; _
  11.     NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;  : {. h4 Z5 s. u: o7 E' v0 T4 \( t  p+ {
  12.     NVIC_Init(&NVIC_InitStructure);  
复制代码
标准库中的i2c一共有两个中断" P  p; Z) E. ]+ z' V4 ~9 `
一个是事件中断(EV_IRQ)和一个错误中断(ER_IRQ)
9 x+ }% q/ I; t3 g4 n) Y8 I- UEV_IRQ的中断只要响应EV1 EV2 EV4 之类的,后面会说明- U* J4 |. a4 z# h9 G5 B
ER_IRQ的中断只要响应没有应答和起始和停止条件出错等' Y) a6 K9 f- ?' [+ C5 T

& F# A5 e5 T4 {( C/ u四、使能中断  H% q! Z" p+ L( M, ?: Z7 m
  1. [cpp] view plain copy
    / u0 V( P3 M5 d* |/ Y
  2. /* Enable I2C1 event and buffer interrupts */  + ]( p* q+ T. ?2 ^
  3.   ; B9 Q8 N4 w* J% E) l- `
  4. I2C_ITConfig(I2C1, I2C_IT_EVT | I2C_IT_BUF, ENABLE);  ; O9 J, q% q% }* S2 s* ^
  5.   0 N4 S; G1 C8 a4 _3 a8 K
  6. /* Enable I2C1 Error interrupts */  
    9 d# b  d3 t/ l+ z2 x
  7.   
    2 y! `+ E/ f! X
  8. I2C_ITConfig(I2C1, I2C_IT_ERR, ENABLE);  
复制代码
使能了I2C1的这三个中断,每个中断的作用下面说明% M2 w6 H  g+ Q5 n  \1 [

# _0 Q9 I& C! Q" @) q" m五、中断处理函数
. H% F* Z' ^# z0 v" d# f
  1. [cpp] view plain copy5 ?* ~, K8 D4 F+ S. V: k
  2. void I2C1_EV_IRQHandler(void)       9 u" m( b: N# m. W/ i) C' n
  3.   
    & ~5 v' o/ O, s* a
  4. //事件中断处理函数   
    ) Q- U( d) S3 T( M$ R8 K
  5.   
    4 r0 Z6 u- j% I
  6. {   
    ( v0 Q$ o# Y& i( G+ ]# Z; a
  7.   ! ?- S* q' _  A2 x& z3 i/ D
  8. switch (I2C_GetLastEvent(I2C1))  ; d# i9 \( @6 W4 ^" K
  9.   
    . {& @' D+ [+ A' a! p
  10. //获取i2c1的中断事件   
    ' |0 f7 j3 w! w8 A! }& T3 E
  11.   
    * o- j2 J$ j7 I. T! _
  12. {   & E* O. y6 e1 c$ t
  13.     i" D$ g4 S) @0 u
  14.   /* Slave Transmitter ---------------------------------------------------*/   
      r/ F6 K' r* ?! R1 Q3 F' X
  15.   
    2 [9 z0 Z0 y2 y0 |( ?' h6 [
  16. case I2C_EVENT_SLAVE_BYTE_TRANSMITTED:   5 S0 I# x* d7 N* g1 Z# J5 I
  17.   & F, S, S: j" d/ Q% y# M, Q
  18.   /* 这个和下面那个都是从发送模式下发送数据的,具体两个的区别我也不是很明白,感觉就是移位寄存器空与非  空的区别,准备好数据发送吧 */   : K0 c" s4 T8 a( f
  19.   0 u3 S7 Z% Y! N& R, K- i  E2 ?
  20.   I2C_SendData(I2C1, I2C1_Buffer_Tx[Tx_Idx++]);  4 }- G% q: N7 U2 q
  21.   
    4 u% b+ y9 Z, n, E
  22.    break;   
    9 ?. {* h  ?: u) v6 |" @
  23.   5 v+ C0 I" T* l; f
  24. case I2C_EVENT_SLAVE_BYTE_TRANSMITTING:             /* EV3 */      
    * m2 j/ u9 d3 ~4 k1 I( X1 e) [
  25.   & W5 g# e6 p: g" n6 f
  26.   /* Transmit I2C1 data */  7 e5 r7 w9 R  K, S" R
  27.   ( P, s# h6 E' `* y
  28.   I2C_SendData(I2C1, I2C1_Buffer_Tx[Tx_Idx++]);   
    + c. C9 x9 m/ C
  29.   0 Z7 M- s7 L) L& s: f! |( p" w
  30.    break;   - d& o) f$ ?3 S$ G& r$ Z
  31.   
    % ]' M; u8 k1 W4 K
  32. /* Slave Receiver ------------------------------------------------------*/   
    1 b1 ^2 T7 @( W! |: w; R
  33.   ! r9 ]" {7 Z7 b1 h5 I
  34. case I2C_EVENT_SLAVE_RECEIVER_ADDRESS_MATCHED:     /* EV1 */   / g# K* u$ n& |' X& p
  35.   
    . \/ D3 P7 N. e/ l3 B
  36.   /* 地址匹配中断,不管从发送和接收都要匹配地址,如下图244、243发送地址之后都会响应EV1 */     R8 S$ ]% K  P3 T; B
  37.   ) t* V5 s. w& J& U
  38.   break;     G$ T2 o) ]% V5 w  S  y
  39.   
    7 {. }3 l- _; u7 e; V
  40. case I2C_EVENT_SLAVE_BYTE_RECEIVED:                /* EV2 */   # p- q3 a4 X; v9 m0 h
  41.   
    * @8 `. W- K0 R! u0 E
  42.   /* Store I2C1 received data */   $ k! e: x* v! R8 d
  43.   
    ! }( Q! J( A- f+ ~% n2 ~
  44.   /* 这个中断就是响应EV2中断,如下图244,每次主机发送完一个数据就会产生一个EV2的中断 */   
    ! |0 o3 \9 c1 i; z
  45.   # i2 f. ^2 _2 k
  46.   I2C1_Buffer_Rx[Rx_Idx++] = I2C_ReceiveData(I2C1);  + Y& J" k( L# b* P
  47.   : Z0 e2 y& o7 i3 t: ]! W7 H
  48.   /* 把接收到的中断填充到数组中 */   . t3 r  @" B  x
  49.   
    ( g9 o! N2 O6 D3 o9 a! u
  50.   /* 注意:地址不会填充进来的 */  
    % v) f$ x' S+ f- t$ g! k' O
  51.   + S! {; @- ]2 E) a; ]( v/ T
  52.    break;   
    7 x* l+ P2 k4 S3 ]; {% q9 Y
  53.   
    9 H0 `  x/ u. V: Z9 b3 F
  54. case I2C_EVENT_SLAVE_STOP_DETECTED:                /* EV4 */  
    , T- o9 p5 x$ k9 k
  55.   . G. P7 `: {; H/ ?8 b
  56.    /* Clear I2C1 STOPF flag */   
    8 u% c- w4 u# b% q
  57.   , V4 h( [! \+ s/ h0 n
  58.   /* 这个就是正常停止的时候产生的一个停止信号 */   ( b/ t. T- ]0 u+ ^
  59.   
    ) x+ C, u8 h1 X- T
  60.   I2C_Cmd(I2C1, ENABLE);   
    8 w+ h1 l/ }# T* y6 H' @$ Z
  61.   $ ]8 }* `6 D/ H$ D
  62.   /* 我也不清楚这个为什么要这样,如果接收完一串数据之后,不响应主机的情况可以 关闭i2c,然后在处理完数据后再  从新配置i2c,记得是从新配置 */   ! d  L: B6 b$ `3 B6 f  G
  63.   ) a& Y  t2 c! N' J
  64.   Rx_Idx=0;   7 U6 y! J4 o& J% L
  65.   % O) j# V, C- y* d; v
  66.   i2c_event = EVENT_OPCOD_NOTYET_READ;   2 o& E; q% M% \( t" }; [
  67.   ; E0 M3 j! W& }
  68.   break;   , L5 s5 z0 @2 p' n7 W
  69.   8 A- l+ ]& z, v& J& I; r7 L
  70. default:   
    4 o6 ~4 ^' ?# V/ I8 t
  71.   ' p! e- H6 W; w9 N8 M1 ]: G
  72.   break;      8 c, e0 F4 W8 ^3 f! k9 Q
  73.   8 H3 Y8 w* [7 Y) i
  74.   }   
    6 C% Q$ T5 c6 J4 h, {
  75.   2 N, ^: q9 q! H3 R' y" M
  76. }   
      N- r4 a; c1 m- j4 c. F$ o9 ^
  77.   
    % W7 k' g& R7 |! E! i1 ^
  78. void I2C1_ER_IRQHandler(void)   : ]& Z9 S1 M: L" l
  79.   ; h# K: f' @, u/ X2 O
  80. {   
      X& P' z. I+ d9 @5 K$ l
  81.   
    8 f# r3 y) Q* m) j: f- ?( b
  82. /* Check on I2C1 AF flag and clear it */   
    8 y3 o/ B* X4 V/ K4 R+ }
  83.   
    8 P( Q4 `/ a# c9 D  R, s
  84. if (I2C_GetITStatus(I2C1, I2C_IT_AF))   
    0 e: A8 V( k& H+ }0 J
  85.   
    1 k* S- ^; }7 a/ V  y- j
  86. {   . Z; T' g' m& |1 i
  87.   ' ^/ e4 R+ A( j/ C8 J( v+ f3 _
  88.   /* 这个就是图243中最后那个没有应答的中断,也就是发送了一串数据后的中断,可以做清零工作 */   
    * V& G. g' ?. w3 e5 \
  89.   
    ! y8 F) s2 Y$ A8 Y- ]) [
  90.   I2C_ClearITPendingBit(I2C1, I2C_IT_AF);   5 k9 O& W2 P) O& G4 d* L
  91.   # d4 ?; s$ z0 p+ J+ `7 y
  92.   Tx_Idx = 0;   % ?& s! n7 r- U/ r1 R# g
  93.   
    6 C% c' p$ V8 [: M8 Y
  94.   i2c_event = EVENT_OPCOD_NOTYET_READ;   
    9 {$ S# H! U8 G
  95.   
    9 X6 i: ]9 N) |/ {; M7 Q" S
  96. }   : a+ b2 E  z* Z" A2 X
  97.   ( ~* p3 M0 D1 ]0 H9 h8 u
  98. /* Check on I2C1 AF flag and clear it */   6 P# M- c1 ?# o5 G  G2 L6 |
  99.   
    - ^  ^; ]" `4 `, X% `; z0 {7 K
  100. if (I2C_GetITStatus(I2C1, I2C_IT_BERR))   //这个就是起始和停止条件出错了  ! O: {; l! h( T( S
  101.   
    & _* h: Y" K: Q; v' c- g7 ?7 ?) s5 `
  102. {   
      ~; k5 S* s- U& ~+ h
  103.   
      T$ n* S+ V( ~* V
  104.   I2C_ClearITPendingBit(I2C1, I2C_IT_BERR);  
    2 q# A1 W# ^. ?4 g
  105.   
    2 i+ Y% w; m: J0 r
  106.   }  
    ) s7 o8 t/ ?. Y  o4 H
  107.   % V" ?' U& l/ ~2 j" d4 j+ p+ p6 `) U0 P
  108. }  
复制代码
2.png
5 A  y) n: S$ c7 j# C# ^5 x3 i4 |3 N" v/ n0 O  F- i
3.png
. u! i; y3 w, ~* D" J: z7 f
4 d6 j0 v' \; f( ]$ l2 k注意:i2c中断中不要printf打印信息,否则会出错! E# X) F9 |) e6 T+ l% j
/ n1 u) O6 y8 H( _
主要是参考了官方的历程,然后自己再调整一下逻辑即可使用。6 `. U, Q2 C3 t' M. _

6 H) E/ Q3 `* P! n+ q 4.png
4 z- U# H4 r. I$ c) R# L+ l; l, |- c; _5 X
最后的效果感觉还是挺稳定的,这篇文章主要是给大家抛砖引玉的作用,也记录一下自己调试几天的成果。7 V1 x& G% k: d( k
ST官网的历程还是挺多的,没遇到的知识可以去官网找找。6 x" s% H0 G+ L9 W* z; f/ ^+ T# v2 @
+ p9 G8 C, u, ^: \0 J* A6 \
9 |0 \$ V4 H% \$ b/ o
转载自酱油师兄/ I) ]: g1 n& O0 A# j5 u2 S: a& M
; d6 X6 L% M% L- q: v
收藏 评论0 发布时间:2018-5-23 14:50

举报

0个回答

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版