使用GPIO引脚模拟SDA和SCL总线实现软件模拟IIC通信,IIC的具体通信协议层和物理层链接:/ B2 D$ A! F5 S* K) m
- #ifndef __BSP_IIC_H& t a( ?' J+ V* J+ u" P* j C* a' {/ u! I. q
- #define __BSP_IIC_H
t Z! F: U9 ]7 o g7 l5 g/ A
7 \% ~$ j9 ^8 b1 Z) J- #include "stm32f10x.h"
I0 M& p* ^* m5 t& K: }6 P& [ - 9 f' q8 f: j6 p# b' z0 t
- q& E, R# g6 r u6 q9 ]/ X m6 x5 G |
* M' [3 o& M- A, {$ }9 M+ d' ]. R- #define SCL_PORT GPIOA
1 d' \7 P6 i0 Y$ ]6 d4 n - #define SCL_PIN GPIO_Pin_2
' T8 {8 O% `5 l2 I - #define SCL_MOOD GPIO_Mode_Out_OD
) p. k& S" A1 O, ~& i9 ] X - #define SCL_SPEED GPIO_Speed_50MHz
: w1 q1 M( ?+ \3 r - $ c% K9 X/ d$ z5 A. I
- #define SDA_PORT GPIOA
; f$ }& h0 s8 ^5 b$ N4 ?3 a - #define SDA_PIN GPIO_Pin_3
9 x, a& | J) E0 d - #define SDA_MOOD GPIO_Mode_Out_OD
/ r7 Q F/ G9 c$ z) J2 ^ - #define SDA_SPEED GPIO_Speed_50MHz
2 A) ^/ w6 T& j6 G
$ r3 `4 x# R4 k. Q! p6 k- #define SDA_1() GPIO_SetBits(SDA_PORT, SDA_PIN)
4 G" s) V8 w9 m Z+ V, _3 e, |6 E - #define SDA_0() GPIO_ResetBits(SDA_PORT, SDA_PIN)
& x& q/ ?9 Z, k - ! g* H( @4 t t# k: V
- #define SCL_1() GPIO_SetBits(SCL_PORT, SCL_PIN)
$ W4 Q3 B- L, _6 v - #define SCL_0() GPIO_ResetBits(SCL_PORT, SCL_PIN)) {4 u. d1 s5 f/ t; W+ R+ c" Y
- ; h, E0 O$ b2 K, v- b
- #define SDA_READ GPIO_ReadInputDataBit(SDA_PORT, SDA_PIN)" R: o, G" `9 q( S! o
- + L5 Q- k0 w4 O. S5 G6 Z/ P
. C) W b+ Y3 o& O' c( |3 y* o, f9 u c- /* ACK原型为acknowledge,意为:报告已收到 */
. ^) J9 Y% d( H& h5 E+ D - void Delay(void);
& I5 D7 \+ n x o - void IIC_START(void);
! a; q5 d7 }, Q/ y - void IIC_STOP(void);+ K! o) F- V" o0 m' e
- void IIC_ACK(void); n1 }$ n/ h. N7 Q
- void IIC_NACK(void);# c1 K% @2 G3 V1 d
- uint8_t IIC_ReadACK(void);
) M* K; p' e, m {; G - void IIC_SendByte(uint8_t data) ;$ r* G7 b% ?( O D
- uint8_t IIC_ReadByte(void);; e' y$ w* r4 h
- void IIC_GPIO_Config(void);' ]5 o3 {1 ]! \. L& y
4 M1 y# W: v8 {- & w2 ^- W5 }5 A2 W; N
2 K& j+ ~. u4 h: m# g- I
, Z- P$ {% s2 G' B0 r- #endif /* __BSP_IIC_H */
* t$ I$ y; j& J8 W; `1 f' q" m
/ E# r% r S1 @' O
复制代码
" f, C( z. y, o- ) b# n1 z8 O+ O6 ]
- void Delay(void)
' ?; m/ }& B# y' j8 F0 [8 Z - {
' K& z5 l( S' K- d6 q - uint8_t i;
# V& d8 G$ m1 B Y - ( P9 w& |- e" S* I+ U+ }, N- b
- /*
. I5 r& [5 K7 E4 [- {9 _ - 下面的时间是通过逻辑分析仪测试得到的。
+ V& W; J' z$ X9 D3 J7 ]; s4 [; Y k5 Q - 工作条件:CPU主频72MHz ,MDK编译环境,1级优化( \! Q$ O5 K+ \9 C& b [$ A
- & A" ^9 S6 q C6 }
- 循环次数为10时,SCL频率 = 205KHz
9 X# p4 ~& O6 Z- x2 z7 V - 循环次数为7时,SCL频率 = 347KHz, SCL高电平时间1.5us,SCL低电平时间2.87us % y0 h) \9 J; G, o# M, ?( V% s/ e
- 循环次数为5时,SCL频率 = 421KHz, SCL高电平时间1.25us,SCL低电平时间2.375us
% t, ^) @# p4 E* N; B - */
+ m. W. D4 o2 ~7 z Z - for (i = 0; i < 10; i++);9 m( D7 f+ l! S. v8 e
- }
* @1 p& B+ e& A4 \# A) E1 w
7 m4 d4 t% E6 q0 z- & c5 y' q. M$ G- z8 }
- /* SCL高电平时期SDA产生下降沿表示起始信号 */% ^/ f" s8 j0 i% E' C
- void IIC_START(void)' O, h/ E' @( U+ E7 ]7 c; E! q
- {
4 c/ `# @: h4 l8 O1 \ - SDA_1();
8 W" Y/ D! |& Z - SCL_1();
) t9 a3 u" l: G# ^% L/ r - Delay();1 T; L( _* M1 |5 V- q5 ]. G) ]9 p8 j
- 7 ]0 ]5 J9 A# P9 X; y1 M8 R7 u
- SDA_0();
. y/ W; {+ Y/ S3 z: g8 t/ S! p - Delay();! P' q, S0 y0 Y* M" Y* B/ C8 n% N
- SCL_0();! w7 C. H1 t- P/ _! V
- Delay();
! l/ |1 z5 D: ^4 K+ C - }
3 {3 i4 p, D' x7 a# v" Q4 [ - - A* `6 D2 B7 ]0 m# s3 Q1 j" P0 w
- , I5 F4 ?3 J% T0 L5 k7 r# t0 B
0 q1 f- m6 [ g/ h, W/ T- /* SCL高电平时期SDA产生上升沿表示停止信号 */
8 B% u7 e0 a% B l3 \ - void IIC_STOP(void)9 {: E6 h& _" M) l0 c4 F
- {- y: o6 }4 H9 |0 L
- SDA_0();
- _8 j: p( U" W" p( u - SCL_1();/ n5 h9 W5 \: X3 [# V& |
- Delay();
" n2 R3 q( R; O' C -
; F% M5 H0 T6 X) p Q - SDA_1();
" j0 C- A+ |+ d2 M) E% o6 b - Delay();" N3 B& @4 @0 k- w. W, v$ p* s
- /* 停止信号后SDA和SCL都为高电平 */2 g3 K! g! _$ m; L
- }
! x$ S7 \6 s1 h# o; C
) b; F t1 m- \! [! o: v4 u+ G% I- 8 M9 `+ s% `7 _! V a7 q; C1 Z
- /* SCL高电平时期 SDA保持低电平代表 应答信号 */4 \3 S% l9 s, y2 U3 }
- void IIC_ACK(void)9 m1 [) K3 [- b) S! F
- {3 V$ R4 b0 B2 C5 X% }
- SDA_0();
, \! d4 x6 D( X9 ]- `% p - Delay();& n3 @& D/ G3 U x
- SCL_1();
: }, J+ W* I0 R8 I2 Q' l8 s- B+ V - Delay();
, x/ G' H" u5 e6 \' y+ r -
5 ]4 a# L. s# C% D1 y - SCL_0();* }8 D$ q' \, o# L
- Delay();
( y7 h }4 _& F - SDA_1();
' s2 j( d2 w- b# c- \+ j2 l! p - /* 随后释放SDA总线 */" z7 B- X1 `* ^! ~
- }) V: b E/ g" w; C+ y, h
) m8 g: G% C+ I; r W/ C$ a0 ]' I1 T
0 ~' n: W( d* Z- /* SCL高电平时期 SDA保持高电平代表 非应答信号 */
2 g" F3 C7 M, h+ J - void IIC_NACK(void)/ Z' P# w7 r0 i, \1 Q" b7 o; }; Z) I; k* ]
- {
) \, \; T, |( A& Q. l0 U# ] - SDA_1();
`3 t$ h& I5 x4 @4 m+ J$ @! P - Delay();- V2 S& G# \$ d$ v, N c
- SCL_1();) \8 X' M5 {$ @9 C6 d1 a* N1 [% w
- Delay();$ |# Q* M8 Z1 |
- ; Q0 E! T# Y5 r- k
- SCL_0();
+ T5 p% c; o6 o3 J/ T - /* SDA已经为高电平,无需释放 */
) D7 O$ M. K2 K+ P3 N8 T* T - }
* C6 l- }; K/ ?! t
9 i) }9 Z4 ?" d; M5 c$ U- r
8 t; _: H7 q' K- /* CPU产生一个SCL时钟,读取应答 ACK:0 NACK:1*/
. ` ]2 _1 H$ K( Y* u* i - /* 因为SDA平时为高电平,所以没有收到应答时,SDA还为高电平,即读取到 1 为非应答 */8 N/ ~0 I6 z) a+ n$ V# K1 ~
- uint8_t IIC_ReadACK(void)
& y+ N% m5 N. K" T - {
* L5 ^0 y$ P8 f3 A - uint8_t k;
$ }$ K9 E* V8 f9 p, e - /* 释放SDA总线 */$ |' c% n5 C3 O. M( \( _
- SDA_1();3 Y# ^; G$ t( a" A1 n# k% J0 o- U
- Delay();
/ r5 a) v' w d* y' f5 b - /* SCL为高电平时,才会读取有效数据 */
" |+ t" o) f( h4 y; U# P( U0 A* V - SCL_1();
+ ?" k1 r# W3 Y+ W! ^ - Delay();
: i4 N H. E$ r; A, e5 p1 K1 \ -
- R" e. m: P3 ^ - /* 读取信号 */
$ o8 B7 ^6 g6 Y& g - if(SDA_READ==1)
& n( T8 X- G& ^' e$ U x" L - k=1;3 I% f- u% S: b* e) l) |. G' N
- else
% s W; c) J6 B9 Q5 ]7 K- R4 d - k=0;
; C, p4 b3 l3 W3 ?* O - /* 收到信号后SCL要拉低 */
# z1 Y4 D5 i8 w7 t" J - SCL_0();% f; v1 B8 a5 E, B7 K" f
- Delay();. y4 g$ |3 C$ M3 U) ?2 n+ [
- return k;0 x6 u1 ?: ~; X
- }+ `; j$ W$ s: M }: X
3 W1 E( `. B5 {+ }/ z# c+ z
$ Y) Q% u5 K& W7 v$ U; y, F1 I- /* 发送一个字节,先发送高位 */
1 |0 F' S$ U% a" `6 x" o# Y - void IIC_SendByte(uint8_t data), r. H! v3 I k$ A$ n' M
- {
# w$ y7 p' Q( M) I- c% a0 k - uint8_t n=0x01;9 \) C2 S+ S8 X+ y% l
- int i;* Q: W9 k- v: l" g3 w8 ^3 c* z
- SCL_0();+ L7 l; [) b1 j, Q) o1 X7 } i1 [/ `
- Delay();
8 q) N" O+ N1 ?2 k; O - for(i=7;i>=0;i--)
" N3 |1 c: W$ o7 L - {* @, v1 J8 ]6 f; L% s6 d% F8 Q
- if(n&(data>>i))
3 H$ V/ Q( f5 Z& r& C9 O8 n6 x - {
1 L# n! o: c8 X. K% i; ?2 P9 k - SDA_1();. H8 L; u0 O& H+ L" [3 s& L
- Delay();
1 b' F( q& a4 I& [ - SCL_1();: i% {/ Y. i; \. `. J% f- I7 n* R' L
- Delay();
5 k( s$ j; O; j. k - }; h; \+ f- t% O* I
- else
# A% n# a7 b/ |/ h: N' x, ? - {& `% J/ X; _- Z4 d0 m- H. b
- SDA_0();8 E$ ?% S! b ] l
- Delay();
1 j' Q4 Z9 ^/ b- n - SCL_1();
# m+ I$ V2 [# M @+ {% C d+ Z - Delay();
2 H4 k; C, {/ u+ n - }% l8 J, K# E5 q8 E0 J
- SCL_0();
1 [3 f2 k7 u% h8 K. A8 d - Delay();
5 q- [( W( G* i3 ^; [3 K1 o9 { - }9 N5 Z7 f* t" C* x9 q
- /* 发送完一个字节后释放SDA总线 */
: m! T5 L, E- C. ?: ~+ c0 I - SDA_1();( d7 _* ~) e' d8 m% l. Z/ i5 }' X$ M
- Delay();+ r1 q1 [7 g. F9 X5 S
- " e% x1 J& L2 r. a0 n
- }
- N" W, ?* v1 e: B( q2 [* K# V - + ]+ A& D0 h4 `
- /* 读取一个字节,在CPU产生的SCL高电平时期读取 */5 N7 O# V6 C; _$ P7 q- T' p
- uint8_t IIC_ReadByte(void)
* p/ s( _# `7 c4 g7 T - {
6 T4 Y6 n- q8 U# ~ - // uint8_t i,data=0;
- s: x; O6 X2 | - // for(i=0;i<8;i++)
6 z" p+ L: |( r( a& E* e - // {
; C2 Z1 n i9 E$ r* l - // SCL_1();4 |* v& }" Z/ x/ G' w# h) f
- // Delay();
- [ U7 y/ @8 r - // if(SDA_READ)
8 k% S0 i6 k9 x8 n - // {$ p+ B5 z: `1 Q" V
- // data++; /* 利用自增实现对最低位写 1 */
+ P( j' d- V( F- y - // }
; F9 h: u# {2 c& E2 Q! T0 |8 k7 n - // data<<=1;
$ h0 J. N9 j* n' }, _ - // SCL_0(); \& X6 @3 u- h/ H
- // Delay();% d$ M- F4 b8 h7 h
- // 3 {8 y# r3 f- T5 n9 i$ }
- // }
4 X- t/ D* D2 a9 l3 T6 S o; J - // return data;" Y8 U+ J% w/ O. P: H
- //
7 i8 e" Z1 q' C& P2 x! j$ v) W% X# O - 1 N* d# ?) K, j8 i7 @7 \
- uint8_t i;6 P" U& x) x* w+ ^
- ( ]$ E% G8 U7 S* V% u* t+ U/ G( ^
- uint8_t temp = 0;. o2 c2 ~% y: v! P
-
7 x% Y0 \8 J- u# x1 e5 N - for(i=0;i<8;i++)* W, D$ t4 ?5 L5 l$ t
- { # Q4 ?3 {, ~, e3 \) `- [' e, @1 Y
- temp<<=1;8 m2 Q1 n# Q) {6 |/ p( _
-
+ j& m# m3 H) d: k - SCL_1();
6 [' s$ ~% c4 I z3 Y! D - Delay();+ Y& j) j$ D6 f' j$ S
-
2 P+ m, i. D2 K - if( SDA_READ==1 )5 Q* _3 e& C H+ {) L
- {
, [8 W |! _$ p" [/ C' c: k) p7 @ - temp += 1;+ ~8 Z! X2 h$ X2 `9 k
- }
1 V! j* q5 s5 p z7 l4 t -
6 y* c5 ~: }/ ~! @* \4 f - SCL_0();
% q3 P' @0 R" s, ~/ U2 x - Delay();
- r0 P3 q+ a/ [6 G - }
0 \( v* w( b0 k' e; g/ a - - b1 j: i2 O: o) A0 u& W* h3 _
- return temp;3 I% p) |& z X& P
- }
~# D8 p3 c) a8 H/ j* q1 J* w N9 N
( e) y7 T. U) {5 Y5 M% a: {1 O( ~- " S5 R w6 q; M; y( l$ E! n
2 s5 k& x, ]9 H! \5 p+ o" F; k7 e- /* 配置SCL和SDA对应的GPIO引脚,模式都为开漏输出 */' U* Y3 |8 n2 n, ^* m/ w0 ~) K
- void IIC_GPIO_Config(void)- t9 ]+ S3 a+ q
- {
; ~% y- L! o- M0 L( r - GPIO_InitTypeDef GPIO_InitStruct;
$ b: Q l+ I& }: d - 6 n# u7 B4 O! Z8 ]5 a
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
: q9 t: i) b* A3 ?* ^: _/ F -
# h, O0 a1 M! i, `8 w - GPIO_InitStruct.GPIO_Pin = SCL_PIN;: \& f, x- x6 W" X4 l: r5 ?
- GPIO_InitStruct.GPIO_Mode = SCL_MOOD;
/ b6 C& h9 ?$ {% U - GPIO_InitStruct.GPIO_Speed = SCL_SPEED;. J7 M9 F4 H1 \* |, {
- GPIO_Init(SCL_PORT, &GPIO_InitStruct);& Q8 O4 a" K+ m; g8 {: e# S1 \
-
7 p, |( `0 S' h/ F6 T: c5 D; {6 ` - GPIO_InitStruct.GPIO_Pin = SDA_PIN;
, `/ y2 U. h' w# t% | - GPIO_InitStruct.GPIO_Mode = SDA_MOOD;) j/ A. u c @: \0 n+ w
- GPIO_InitStruct.GPIO_Speed = SDA_SPEED;
, W1 M1 L, c g; m. P' f6 u+ t - GPIO_Init(SDA_PORT, &GPIO_InitStruct);! D! I( Z% t6 Z6 ^
-
( ?4 M$ g7 R+ P; K% a - /* 给一个停止信号,使IIC总线上所有设备处于复位 */$ |# p+ S- D7 E1 ] S: E
- IIC_STOP();
3 O" I0 h8 L4 R -
4 ~0 e1 v; E; h0 F; q: J" h) S - }1 G5 F6 x$ i: `$ L6 Q
2 x( T- m6 b& r/ |- W1 T. O" a+ _5 t. I. p% G" ]3 g
复制代码 转载自:Aspirant-GQ( T2 w1 Q$ @( Z4 ~3 `
如有侵权请联系删除
- z6 ~9 d2 _8 X. O: F% Z6 \$ A+ X! W- U
+ e" D5 g9 ^' k" V7 e* m- z
|