对于STM32F103单片机来说,它是自带了硬件 IIC,但是出于使用习惯和程序可移植性考虑,我们一般选择用 IO 口去模拟 I2C 协议。
8 Z, }$ s' e3 C* w使用 IO 口模拟 IIC 的好处有三点:
+ O% b2 p# [5 h1. 使用 IO 模拟 IIC 协议可以让大家把之前学过的 GPIO 知识再进行深度的理解和扩展;0 }: U. }8 g! K+ r# v& a
2. 加深对 IIC 时序流程的认识;2 e$ q4 p6 _) M0 M8 o( H4 p9 ~
3. 方便移植到 STM32 的任何一个引脚,如再做修改可以移植到其他 MCU 平台。
V- W% J1 o8 D, @& p# T1 \& l
, Z0 f2 K6 {( s, _& s$ @9 T4 Z当然这种方法也存在一些缺点,比如考虑这样一种极端情况,在程序运行时会有执行时 P! [& y$ H/ K% q `
间很长的中断服务函数打断 IIC 时序,造成 IIC 写失败或者读失败。如果存在这种情况,建
* S- V9 a; Y- _, ^; K" k4 w议大家在进行 IIC 操作之前关闭全局中断,使用后再打开。/ R' z/ j- \; G1 U4 `
' p, a5 C% h5 k7 M; c, T- ^
首先,对模拟I2C的I/O管脚进行宏定义,包括SDA线、SCL线管脚的定义等,代码如下:
; L3 C4 y D' ]
- w1 A& m& \6 @, _) @# G6 n- #define RCC_I2C_PORT RCC_APB2Periph_GPIOB
4 b* m. n9 k. @# T4 l! q - 2 F) z7 j6 ?( [7 e0 z
- #define PORT_I2C_SCL GPIOB
G. X! H. i+ S) _1 Z# R, n# M! N - #define PIN_I2C_SCL GPIO_Pin_6 / b6 K& s; D8 E+ U* _ }8 C4 \! ]" E& H
2 X- U8 y; F& U3 X/ L- #define PORT_I2C_SDA GPIOB
. Z6 x; x$ y! m+ B - #define PIN_I2C_SDA GPIO_Pin_7
; B& \+ E. L( `0 }& @% U `, D
& ]/ ? `4 P) |+ P- #define I2C_SCL_PIN GPIO_Pin_6 9 S, R- v2 q& B& ~* Q5 _$ v
- #define I2C_SDA_PIN GPIO_Pin_7 a( \+ ~+ u J( @3 q4 M8 r
- 5 z1 }' a9 C) `+ L$ X& O
0 i+ c& U0 @# x: r; N9 u- #define I2C_SCL_1() PORT_I2C_SCL->BSRR = I2C_SCL_PIN
$ D- Q L7 H: }3 l: Y - #define I2C_SCL_0() PORT_I2C_SCL->BRR = I2C_SCL_PIN & a) S) V8 _4 V" S F1 h
- 4 o+ E" e# s0 N3 P0 b- M% K( r3 ]
- #define I2C_SDA_1() PORT_I2C_SDA->BSRR = I2C_SDA_PIN / f! z5 e* \2 I# B7 s) @5 g5 u
- #define I2C_SDA_0() PORT_I2C_SDA->BRR = I2C_SDA_PIN
% _, W4 v5 q- o- \* K - 8 [, M8 F9 m8 }3 X0 C. X5 F
- #define I2C_SDA_READ() ((PORT_I2C_SDA->IDR & I2C_SDA_PIN) != 0) ; _% ^0 f. W) b: W
- #define I2C_SCL_READ() ((PORT_I2C_SCL->IDR & I2C_SCL_PIN) != 0)
m! w R8 ?- F! L
1 N3 T% c; v1 ~- void SetSDA_IN(void)+ }5 z$ S2 m) M! }- w l
- {
2 i" C4 q* g4 M$ k - GPIO_InitTypeDef GPIO_InitStructure;, o: x5 \0 w7 a
- RCC_APB2PeriphClockCmd(RCC_I2C_PORT, ENABLE);
& O2 Z1 q& v0 ` - GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
: Y; Q" q( z' ]' u# _+ @ - GPIO_InitStructure.GPIO_Pin = PIN_I2C_SDA;
" G) O5 P S- ?1 I N - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
5 N2 g. Y& s- H% U - GPIO_Init(PORT_I2C_SDA, &GPIO_InitStructure);
% d+ G/ l$ `% l0 ^; R9 W" O - }
" j/ M- }# h1 m* ]! F4 r5 `# B9 D - void SetSDA_OUT(void)
. A+ g, Z8 |/ L - {( X8 U; Z! Q- R) N
- GPIO_InitTypeDef GPIO_InitStructure;. S7 M8 L, a( D) a3 Y0 D
- RCC_APB2PeriphClockCmd(RCC_I2C_PORT, ENABLE); ; @0 s7 a8 ~' n. z6 c
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
7 z3 {1 }6 u s) F0 i" \7 ^4 s - GPIO_InitStructure.GPIO_Pin = PIN_I2C_SDA;
?3 q [: ^% ?! L9 X' J1 d+ p - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;
) u2 W1 ?; e1 K( O' |/ X1 H - GPIO_Init(PORT_I2C_SDA, &GPIO_InitStructure);
7 p1 N9 [9 o$ ~6 b) M - }
7 o g" _7 p0 t5 \$ r; Q( g; T& N
复制代码
& k7 `9 A: o) T' l K5 M6 E3 M接下来便是模拟I2C的初始化函数与时序操作的函数: P& G& M7 y* \* v8 J
初始化操作与GPIO初始化基本一致:- W0 @' O q# N5 O
1.配置时钟;
& a& b" ^. E! C3 d, V* T2.配置管脚的输入输出模式,其中输出模式最好设为上拉输出;
$ J: o; h) v) h' ?: F7 P3.设置管脚。
. H2 z* Q* l! ^. F! g1 ]9 J9 l! }! W3 ~; q; }/ {
- void bsp_InitI2C(void)5 u( E0 a% l1 h$ w
- {
# Q A3 ?' {6 `4 l$ ^# Q1 h. @ - GPIO_InitTypeDef GPIO_InitStructure;
, p( ~# [ p* q) A5 o4 @; t
0 N8 z( t8 A% A: g) H- RCC_APB2PeriphClockCmd(RCC_I2C_PORT, ENABLE); / B+ a9 q# Z9 f: ^4 M' y
- 0 J: Y. J5 |# m* d k8 B9 D
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;' ^) B+ h8 L8 N& Q
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD; # B4 y% M2 I7 c! V5 m
- & r5 ]+ @. K; J% ?% n7 F4 m# U0 h
- GPIO_InitStructure.GPIO_Pin = PIN_I2C_SCL;0 t# ]) T: F. v9 z
- GPIO_Init(PORT_I2C_SCL, &GPIO_InitStructure);
3 q7 P$ i2 l: b! E8 H - ; R% |+ M& t P$ i# k* S9 j
- GPIO_InitStructure.GPIO_Pin = PIN_I2C_SDA;
/ z0 }& y5 [& P+ Z# [+ F: v P S - GPIO_Init(PORT_I2C_SDA, &GPIO_InitStructure);
% Y! G9 \* h+ t; J2 k. R - i2c_Stop();
; i( C0 L7 L, T7 m0 A6 _ - }
1 ^! x# l0 J9 a% v& M1 E - static void i2c_Delay(void)- j' s. O, P% C# g& x
- {+ q% l# z1 O: S, D+ h
- uint8_t i;8 J+ S/ v4 G5 ~8 X" C
- for (i = 0; i < 30; i++);* z- m, B9 }" \$ ~
- }' P# u- o) S% Q1 V# C5 i
- void i2c_Start(void)/ z( k( Q: j9 x- c4 S* F0 |0 Q _
- {; l( O7 u3 }% s; w1 a8 L
- SetSDA_OUT();- W9 e5 y6 I8 U4 @( [$ W4 a
- I2C_SDA_1();* l7 ]8 X- e- z+ k# l3 O! p7 C- u
- I2C_SCL_1();6 g2 r1 U9 [9 L3 R+ _
- i2c_Delay();
/ e. V' Q4 y( f# B* K# t1 E* C - I2C_SDA_0();; f1 \, X3 ~$ Z0 f
- i2c_Delay();
0 [' n4 M/ \1 S$ z: n0 P/ `/ E; \ - " {+ D1 }/ o8 ]2 T
- I2C_SCL_0();
: y1 y! X+ d, l2 ]4 w( g+ _% x - i2c_Delay();
9 t7 N5 a5 d5 o. J - }2 r# d* o/ ^3 ]' P2 z; F
- void i2c_Stop(void)
; j* i/ [/ S. g6 G$ i - {
, @/ K1 c' c$ O2 C! Y - SetSDA_OUT();
; M' G, r, @ Y) x' F4 { - I2C_SDA_0();
1 N8 D( [& d5 x2 ^ - I2C_SCL_1();
1 _: u9 C/ J9 ?7 d# K - i2c_Delay();1 T( s& m6 Y6 b& J4 z5 l
- I2C_SDA_1();
4 O$ ~2 Z1 @; p! I% R* e% J, J) j - i2c_Delay();/ h! e V) f! B
- }" d* I4 e% C3 N4 Z2 S
- void i2c_SendByte(uint8_t _ucByte)
# L3 R" j/ ?& ?. a, { - {$ Z2 X( \; m1 g3 D* q
- uint8_t i;9 L8 o- {! P% [8 ~1 j, |
- SetSDA_OUT();0 d& O: G! F* C- g4 Z% |
- for (i = 0; i < 8; i++)6 u2 c1 M$ p6 f6 ?" N ?
- {) P" B! L7 F4 C' D( \8 _
- if (_ucByte & 0x80)/ {5 _. ~: T. h U% O
- {& D( H( } k o% e, |& o% f9 Z
- I2C_SDA_1();
2 j# E! m/ \. g2 {. a7 W - }# Q; {# b4 n" t1 m; C
- else! l/ e- P, a, \. m, s' p
- { B# [" }/ L c" s5 Q
- I2C_SDA_0();) a& o+ k& v) `( w
- }6 q/ \8 o" x0 U& U, n
- i2c_Delay();+ u1 E! F5 w2 A6 b
- I2C_SCL_1();4 R# ?7 R# @6 f3 @2 W8 ]
- i2c_Delay();
. a& J" N0 t& h8 Q - I2C_SCL_0();3 Y0 R3 k4 s* |4 y
- if (i == 7): Y; B2 G5 M; T
- {
% V7 A! a. ?% g" D - I2C_SDA_1();
) T" l7 D. s/ v; Y x - }. c' F5 r) T* q
- _ucByte <<= 1;
8 s: Z- r6 M" }" A, E - i2c_Delay();
0 K: A( H: `, J2 H - }
+ x$ S+ p+ Z4 l$ x8 d6 ~/ s; X4 I% q - }
3 C* p/ }! T) e5 E* M7 T- r/ N, u - uint8_t i2c_ReadByte(void)( n9 @ ^" o0 Y
- {/ N/ I! d0 N' s1 m6 a. c6 q6 s8 J- b
- uint8_t i;
# [7 C4 _" c$ e2 P) c, ?% P - uint8_t value;
7 J$ }' P0 b ?2 @/ O - SetSDA_IN();7 m, P, }; o" o* X: i5 a6 w
- value = 0;
6 Q2 Z/ ]* H5 A z) P" D1 `1 X - for (i = 0; i < 8; i++)
8 O7 d5 v2 r% O5 j* ]3 V5 M7 b - {
0 F( F1 Y( ~* b" @ - value <<= 1;% N! e* ^7 Q) }7 J$ m
- I2C_SCL_1();6 u5 ~. y& O, {2 Q; J& m/ e* {
- i2c_Delay();1 W4 G' `( W$ U3 f
- if (I2C_SDA_READ())% N9 `0 Z* q$ r; n+ U2 H9 X
- {) L | G7 \: l& } |6 q
- value++;
S( X! P$ j% k1 J - }. n$ x( D$ [3 w4 y- w( d
- I2C_SCL_0();
) d) l7 ?2 N+ g7 Q - i2c_Delay();
6 L% y% K0 F2 S% a - }
1 c2 }% H( \- r - return value;
H" d' \7 @8 l g
8 ?0 Z' z- c6 @3 Y. n: T- }5 }# X, n4 n3 q1 M4 Q- n, }
- uint8_t i2c_WaitAck(void)
# Q# }% H+ @5 ` - {
9 \4 \. q0 d9 Q! ~7 n - uint8_t re;% i: h$ R' ?+ d5 t& L. c6 t+ a7 V8 c
- SetSDA_IN();7 i( q/ v: F2 J T5 U. n: V
- I2C_SDA_1(); ; @; W7 C8 D* T4 ]* k3 j, n
- i2c_Delay();+ d4 d* Q) u; n$ i- A
- I2C_SCL_1();
6 |# }9 I/ s) b* \4 o, O1 t - i2c_Delay();
+ I* ~9 ^- B& v - if (I2C_SDA_READ())
/ j0 X) c- S# }0 O - {. T, f1 d1 s; V4 I0 [
- re = 1;
9 b) Y% ?, p n - }
& p9 x2 G* z: G7 S: M$ m - else
; s7 m5 K* a7 w5 [0 T7 e0 ?8 f - {
4 p7 a+ s3 Q# Z - re = 0;. I6 a1 j) ~- v5 k5 o4 @2 O
- }
0 S1 f+ L V$ L1 ` - I2C_SCL_0();
5 \' R; b, O& W3 x$ k } - i2c_Delay();7 |. F) \) _1 z; _( l
- return re;2 o p! u/ P. {6 ?- D
- }
6 Y/ P) y4 _% T% D* K: O - void i2c_Ack(void)
9 W1 j2 C5 Z6 u5 R, \# @3 ?+ ^: | - {
+ A5 ]) T$ S6 |2 u. s; X - I2C_SDA_0(); / r I0 H \ p& a6 F6 b
- i2c_Delay();
4 S4 @: K0 p) i- v ?" l - I2C_SCL_1();
V! e4 Q% T4 N - i2c_Delay();
$ S- @& o* ]" ]- l% Z) ~! V1 C: F' T - I2C_SCL_0();* b" n4 y3 j. r1 D
- i2c_Delay();( Y' }( h7 i) }1 L5 `5 K4 }$ b2 B- t5 E
- I2C_SDA_1();
( |; J. L% @" N0 v - }) g3 j! X- E+ d: {9 H s% z
- void i2c_NAck(void)
1 p8 ~8 f# ]& P - {
8 e# [) M1 f- b6 R+ l - I2C_SDA_1(); . Y; y' a( ]2 F. u: N. f
- i2c_Delay();4 Q2 f. p, k8 P
- I2C_SCL_1(); - `9 ~7 P X2 ^2 H, q2 }7 r2 M8 ?2 C
- i2c_Delay();0 f; i( L8 m2 k
- I2C_SCL_0();8 n z, Y% z* x0 ^2 t8 a# m
- i2c_Delay();1 T; z& A. q% Y. O1 T+ ]1 ?
- }3 c1 D6 K" Q4 @
- uint8_t i2c_CheckDevice(uint8_t _Address)
* G5 Z0 X4 s: `% f8 u% B& C3 K5 o - {
1 I/ W2 w, V; f5 Q2 m3 G* ]$ X1 G9 a - uint8_t ucAck;
% x6 A3 F& J$ K4 g - - Q) G$ l2 w- y* a$ O- S0 V) e* ^# H
- if (I2C_SDA_READ() && I2C_SCL_READ())& A0 t* n) m8 P" w- _
- {- T: [) r) i0 {% ~
- i2c_Start(); & E3 Y- N1 c {! Q1 f7 b2 |0 G
-
" W1 l2 H& I8 q$ ^ - i2c_SendByte(_Address | I2C_WR);
# u4 f: B9 ]4 L$ I- M/ y) Z, z - ucAck = i2c_WaitAck();
+ S: t3 l# |9 I - 7 Q- d+ N7 H) O. _
- i2c_Stop();
& e8 ]2 C. Q" t' U
. O0 \4 w9 I+ _) N. `/ O! W- return ucAck;
% w' r, `8 M# ?( U4 s. Y' J - }
7 g. N2 O: }( v! a7 d - return 1;
6 H8 X1 h/ Y; ]$ Z) [' Q: y - }
' w* A+ W) J2 J/ J/ L. |
复制代码
- D' F& m9 D0 T! d8 b4 d( T! R0 \以上便是STM32F103模拟I2C的全部操作。
4 B/ J* p" s3 ?. B& j- t————————————————
$ u6 v4 |; G+ a$ F- G0 Y版权声明:TangPeng_HanMO
2 W5 {$ q) d0 J q' i4 l3 C! [$ T8 G; L& k7 k1 ]- S, Q
|