使用GPIO引脚模拟SDA和SCL总线实现软件模拟IIC通信,IIC的具体通信协议层和物理层链接:
7 e d: ~$ t/ b; ~ V9 P: A( k- #ifndef __BSP_IIC_H
4 o7 u! ?* q& m# g' { - #define __BSP_IIC_H
1 j9 T; D8 `) `7 G9 d4 V - / G/ O7 F3 @5 f) x: X, Y* f
- #include "stm32f10x.h"
" O' P! V" m7 f6 f. v0 ]( S - & q6 _& r8 n9 ?8 `
- # M$ u3 `# G1 X
- # y% J! T$ G4 H# r( Y) J& ?# s
- #define SCL_PORT GPIOA, j1 e' R' s# K$ {4 h- ]- J" S- _
- #define SCL_PIN GPIO_Pin_2
- k0 J- q+ w5 H! ^+ |8 |' ? - #define SCL_MOOD GPIO_Mode_Out_OD7 g5 ]0 J. L2 w" g' J D
- #define SCL_SPEED GPIO_Speed_50MHz9 O+ ~9 n. j& d$ ]
- 9 v/ ]; r; v. u: w& x0 w
- #define SDA_PORT GPIOA
7 m1 h7 Y; x; O3 h4 i - #define SDA_PIN GPIO_Pin_33 ]/ E1 l9 m0 Z+ B
- #define SDA_MOOD GPIO_Mode_Out_OD
6 N3 x8 j: j c8 b - #define SDA_SPEED GPIO_Speed_50MHz# ^3 Y0 t% F4 |, r" }# `# L
- ! c* t# P3 D; h8 p0 z( h: j: m8 B
- #define SDA_1() GPIO_SetBits(SDA_PORT, SDA_PIN)
# h) ^! U/ H% ~ - #define SDA_0() GPIO_ResetBits(SDA_PORT, SDA_PIN)
5 W; T2 B0 [5 k% d1 M
2 ]3 ]8 V( n7 z. C" |) G& R- #define SCL_1() GPIO_SetBits(SCL_PORT, SCL_PIN)2 q7 @! t( d8 A: V
- #define SCL_0() GPIO_ResetBits(SCL_PORT, SCL_PIN)
0 a5 @& E o( E6 Q. |+ S( h6 b! Q - / r. E6 i. z9 H
- #define SDA_READ GPIO_ReadInputDataBit(SDA_PORT, SDA_PIN)' J# ]4 p Q) s7 u3 v
- 5 p. h/ R6 n: {3 Q
. E( i/ A# ]! y4 y- /* ACK原型为acknowledge,意为:报告已收到 */3 Z# L. E8 Y- s& `
- void Delay(void); E6 I# H* I% v4 H
- void IIC_START(void);: B* y: i: \6 ~4 z
- void IIC_STOP(void);
6 Z ^8 L7 p1 u( \' T) P$ Z - void IIC_ACK(void);: u1 j, U3 ` s( U, l
- void IIC_NACK(void);
, X6 k7 N" L% O; y& l8 b - uint8_t IIC_ReadACK(void);
! [) `' d; B) Z+ |# F0 H& d7 Y - void IIC_SendByte(uint8_t data) ;
) P7 Z9 _# V* t9 s* m% q, n - uint8_t IIC_ReadByte(void);
5 c4 @* e7 z) ?- c" W e - void IIC_GPIO_Config(void);
! p/ Z8 Y% O) V6 \4 u - 8 `4 J3 l, V1 X7 w, u" b
- $ B# Y- Y( t7 ]" ?9 @/ v- @$ g
) }/ e, ^: j0 j4 X
2 _9 y3 }; e& e4 {& H9 e- #endif /* __BSP_IIC_H */' i, y9 [4 S& l
6 p2 r+ e" _; J( O3 ~' w
复制代码
+ O! Y2 d7 P! r
s8 [1 ~) |9 w2 ~* i- void Delay(void)
) f( Y3 o0 p9 I' i - {
/ b- F' D- k; t+ s7 L% T# y: ^ - uint8_t i;
4 t" j% I2 F- T- x - 6 X r0 f0 i9 K" R% I' n
- /* 1 ^+ i, l& f- P8 ~/ n8 O
- 下面的时间是通过逻辑分析仪测试得到的。. L/ R, J" s7 T. F) M, s+ P
- 工作条件:CPU主频72MHz ,MDK编译环境,1级优化( j1 F5 R7 Z G1 T# b, t( S, N
-
/ V7 J3 h- T% c: f5 U - 循环次数为10时,SCL频率 = 205KHz ) i- v- A% Z- @
- 循环次数为7时,SCL频率 = 347KHz, SCL高电平时间1.5us,SCL低电平时间2.87us 6 M0 q! }0 Q, W; ~/ m
- 循环次数为5时,SCL频率 = 421KHz, SCL高电平时间1.25us,SCL低电平时间2.375us f3 H6 O b2 N; f
- */# S) ^. H, X0 Q! P0 J
- for (i = 0; i < 10; i++);
) u3 i/ w5 J; E! L2 D2 | - }
, V8 N ^4 v6 Y5 N - / o. A3 c; C$ l4 @, w
- r5 o0 M. J& @# @8 J# D4 F2 A- /* SCL高电平时期SDA产生下降沿表示起始信号 */
% s# V) C1 o5 r5 ] - void IIC_START(void)
# u9 y) l- Z) y' D# { - {7 Z, Z" c6 N) S* A' V
- SDA_1();
6 ~5 S% R, R3 t+ A. ~ - SCL_1();
0 J3 }1 Y+ X: m2 P9 C* p - Delay();7 B6 M; _1 U# w
- 7 t+ F& x% [& B( O& e# f ^
- SDA_0();
- r* D) b% ^3 t; _3 Y - Delay();
5 X e; G4 j# T2 z: l- h2 l6 u - SCL_0();. H3 E1 k8 t6 C" J. f0 S
- Delay();' k. E' `5 Z" o
- }
) @: B/ e0 F! L9 J2 G; w g
$ \0 K/ H2 ?2 z+ ?- 5 F2 F, K' w7 j$ e% m
- ! F% u1 D4 p9 ]' }: j$ i6 M
- /* SCL高电平时期SDA产生上升沿表示停止信号 */" P6 `* q7 m3 I% T
- void IIC_STOP(void)
) ~6 I ?" D9 U$ M v - {1 k4 f# w' a% ?( c7 O% L$ K
- SDA_0();
: y0 a; b* ^4 Z: r$ o) e$ h - SCL_1();
3 f3 B' c6 ^$ h% I - Delay();1 n. q& X. N* J
- & z# s; h7 i% G! j
- SDA_1();# o5 ~ b4 j9 r" ]! f5 t
- Delay();" S6 P0 Q, I4 ?( K* g
- /* 停止信号后SDA和SCL都为高电平 */
. h! R3 @8 X9 U; w - }* X1 |% B9 Q2 Q, E
: b' ]" v; |" X/ w) R5 S
`0 k5 \& _5 B! G, {2 ?- /* SCL高电平时期 SDA保持低电平代表 应答信号 */- U c ~6 F6 N1 ^- v: m' m
- void IIC_ACK(void); d! C1 P5 r" g
- {( q8 N8 f- G6 }( |
- SDA_0();
: {; G; M3 F6 n0 h# z. b - Delay();% |, H( s9 L& b4 P0 L* d: e/ V1 t
- SCL_1();% ]* r4 f5 R$ [
- Delay();7 \$ e- e( Y. s
- ; q0 E9 t5 R* u) g' S# O& |
- SCL_0();, V9 B6 K$ `# Z" ?% Z5 D
- Delay();
. [/ N4 U$ ?+ c* s, [$ n% g8 s - SDA_1();
4 k+ X- ?9 f8 g( O - /* 随后释放SDA总线 */
3 g/ U2 J- s+ z - }# i) L& @+ b& I
- & W! s: T+ k( o- K! Z+ P1 t
- , [( x K& ^( [5 j. b0 i/ i
- /* SCL高电平时期 SDA保持高电平代表 非应答信号 */
. l, l7 h) Q' y, c' ] - void IIC_NACK(void)7 z1 t* x; P& B% k8 B
- {
5 P% q7 a' b' D O6 @ - SDA_1();
- v3 n( Q7 X4 |6 \8 G - Delay();# l$ K V0 b( }/ q
- SCL_1();
2 t2 ]! n5 r6 ?! v0 N2 b6 k - Delay();
4 w* ]# x! P6 r8 T7 }2 L - ! P/ Y) H- p# V; D
- SCL_0();# i6 C1 h. [1 z
- /* SDA已经为高电平,无需释放 */# L" c' f+ [9 ^. ]: d+ l
- }% y5 `7 C: ^ I4 U q% o
7 i) `, `6 v' R& f6 j- 9 Q/ g9 f) V' L2 }. ^% `9 I
- /* CPU产生一个SCL时钟,读取应答 ACK:0 NACK:1*/
. x, M5 Q" s7 W* Z, l - /* 因为SDA平时为高电平,所以没有收到应答时,SDA还为高电平,即读取到 1 为非应答 */
$ P5 {6 k5 b' O: X - uint8_t IIC_ReadACK(void)% U' ^9 {3 S5 j% ?
- {
, ^' M' a! o6 [+ U+ o8 @ - uint8_t k;& `- Z2 y v t, U4 a( X+ R* I
- /* 释放SDA总线 */1 f; Y) _, V- G1 e
- SDA_1();, o( r b9 n' k; K! E+ i
- Delay();
7 U$ S. F+ m, R2 k# w+ J: r' y - /* SCL为高电平时,才会读取有效数据 */% ?' s. D) L( o* x P- V* w
- SCL_1();- N9 d; x/ a& C2 Y4 m
- Delay();/ B+ J5 Y: ~1 ]1 h, m
-
# K6 L6 x g; \; T' K) M - /* 读取信号 */. L6 U* b7 D& [" l) `8 A
- if(SDA_READ==1)9 ~5 i U1 Z% L# l) F; ]0 O& D
- k=1;# \4 G. d" t: y
- else
6 C5 r& i( K5 ^6 V1 a: Q - k=0;
, b' H9 n' s7 L, t" a/ A1 D. C - /* 收到信号后SCL要拉低 */( o# X& \/ g& Q m
- SCL_0();
7 ^ c; I6 V2 w& e" ` - Delay();/ w! y: h% T% P6 g4 _ d
- return k;
) [0 G/ }. D" ^: J$ ] - }
6 w% f1 V# t# ~& ?# P% C - 0 a( S9 N3 b9 P9 I
- . F/ v# I) U# y: K
- /* 发送一个字节,先发送高位 *// S0 m* s) K. M% C' y e
- void IIC_SendByte(uint8_t data); v, g" X) K/ W
- {, b8 f8 D. M7 y; g4 W
- uint8_t n=0x01;
; w0 r9 G7 @, Z; y+ ] - int i;
0 [! A% X6 G+ S0 X - SCL_0();
% F( ?( A3 r$ Q# b+ Q y n) D/ F - Delay();! _$ _, e7 m8 Q4 E9 K U( N7 C4 n
- for(i=7;i>=0;i--)
! _5 _2 ?+ h3 g - {
: O! \ f, L" t& j - if(n&(data>>i))
?* c3 g7 U6 t - {
4 z; ]- K! i$ M - SDA_1();5 q: ?4 \/ T+ t' ~' S }
- Delay();
3 R+ D( E7 @! [: q4 }9 O - SCL_1();7 w9 F4 i0 k: k% A
- Delay();5 T6 P2 k- c- |; B3 |+ E& ?
- }0 n" n2 L1 l4 |% P
- else
! Y/ M& j+ F& Y- t( I* a5 q - {/ N% ^$ b* ~3 j* U5 s5 u
- SDA_0();7 P2 V+ j2 W0 V* E
- Delay();1 y& l8 T+ s% P- n: s: ?
- SCL_1();) I. S4 d3 V! g$ h# s3 ^2 L4 ?
- Delay();
4 w+ V% E: }4 {) D - }
+ i- A: y6 F c1 c$ u) v - SCL_0();! L3 @6 V+ y& S% D" d
- Delay();
6 y: m$ h4 O8 f& U* |$ J8 _& D0 H - }0 O1 w, S7 R$ t' D" O9 n
- /* 发送完一个字节后释放SDA总线 */9 A: I( Y3 f: z# W, m8 T
- SDA_1();& C! i+ _+ s0 q' n
- Delay();) k0 S$ s2 e6 o+ T$ U! v& l/ U
- & m$ z2 E/ x: f% l- T) {
- }0 I" Q* o# s% C' |9 Q( s
- 5 W* `( M% k: n* |+ P: j' v X
- /* 读取一个字节,在CPU产生的SCL高电平时期读取 */
: P, d' n8 j- G - uint8_t IIC_ReadByte(void)4 E+ K; ^2 q) g) f" T& J6 K$ ?
- {
, C) V2 E3 N; n6 A% R& J - // uint8_t i,data=0;
! s9 K! n U# ~* W% j - // for(i=0;i<8;i++)# d+ I; z3 W" Z2 }& `- {
- // {- F4 z- l+ F u0 q# }. G
- // SCL_1();
. a1 P. Z. O% X* S1 l! B3 O - // Delay();
, _( V; C7 b+ H - // if(SDA_READ)+ Q6 n; ~+ w8 V$ X' n
- // {
8 d! ?7 J5 v" C& k: O - // data++; /* 利用自增实现对最低位写 1 */
9 `5 a9 v& B9 t, ? - // }$ @! v) J0 [1 ^! X# d
- // data<<=1;
7 J) b% M2 ?; E* P - // SCL_0();( d0 g; G& d* p( O
- // Delay();6 h: }' y& n Q$ }
- // 2 H2 j2 F& N$ h5 H
- // }
) h" K' C; L3 U) c7 d7 r. U! n8 D - // return data;
, L! ]* {: F8 M3 | - //
6 Z/ h1 q1 p' V* o2 B# l. D -
* {) g r" R* }. w/ n+ ~7 ?1 c1 X - uint8_t i;
# ?8 d) t" F. E; a4 C -
1 t6 n0 {' O# T6 s8 o - uint8_t temp = 0;* ^2 X- r# d- ~0 u8 m E( g! ^
- 7 a5 `- a/ w& _) e2 S+ S! m( b- j
- for(i=0;i<8;i++), {1 n* q4 P4 u* ^2 j( ?1 a* V
- {
6 O2 p* G- m. ^6 L/ ?1 d( Q2 K - temp<<=1;4 \, Q9 u% T7 C: e6 G! C
-
5 o6 z; E, d1 O( ] - SCL_1();) ]6 [# s& V" L, y
- Delay();9 Y `5 R! w' w. k* @
-
; e" @! E" }* R" j0 o. b - if( SDA_READ==1 )
; N- e V) c) R7 P - {4 q) w/ @8 z* y/ n
- temp += 1;
% I: [0 e! r% C4 U+ |9 V2 a - }; ^ j0 H5 o/ K+ g7 r% B
- 6 q+ ~6 p. M. t3 W
- SCL_0();
( ]; a) j9 f+ M9 [ - Delay();# p3 ]+ x* y3 b$ ^% G" l* X
- } ! y3 E# G0 |" ^9 m6 _% o
- % {. `! y/ S9 U# I, L# t
- return temp;( ~% S% A( f( U: @! H% h/ F
- }1 y" m/ g; b6 h/ V- o
- ( I7 b9 K$ U- l) x2 L5 p
- - U$ |! U3 t* j9 _# E( y, r5 m
. s% t/ `( f4 _) s u- v$ R! {- /* 配置SCL和SDA对应的GPIO引脚,模式都为开漏输出 */9 m8 s" m6 K/ P# M! J; ~) c
- void IIC_GPIO_Config(void)2 b, _5 m3 e0 v2 G2 o2 j) f6 g. c
- {
( G; t6 E3 i) D4 c2 Q* |0 S# Z; V - GPIO_InitTypeDef GPIO_InitStruct;
N& u9 I5 F2 s6 ]: |0 k, q8 @ - % Y) I, v0 B; W: U+ C
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);/ o- E: J) C! x- \9 \& @# [
- 0 ]& K5 @* ]+ ~0 j8 i, T$ `" y
- GPIO_InitStruct.GPIO_Pin = SCL_PIN;, g5 ]5 I% \3 o2 u: j3 Z% p
- GPIO_InitStruct.GPIO_Mode = SCL_MOOD;$ t# } R$ c- w9 p
- GPIO_InitStruct.GPIO_Speed = SCL_SPEED;
7 u0 B2 V5 _) ^5 }# y$ Z - GPIO_Init(SCL_PORT, &GPIO_InitStruct);% O t# l) Z/ L7 l4 Y/ }" P
- - P0 |+ c% n$ g
- GPIO_InitStruct.GPIO_Pin = SDA_PIN;! Q7 M% o/ c" S3 ~
- GPIO_InitStruct.GPIO_Mode = SDA_MOOD;2 j3 u1 @( h6 m% ?% T8 D+ v8 q
- GPIO_InitStruct.GPIO_Speed = SDA_SPEED;0 q0 H4 O3 u/ }2 \; {& o( c
- GPIO_Init(SDA_PORT, &GPIO_InitStruct);0 I4 B1 A9 g2 h, ?/ z7 E! d. J
-
, u/ E/ |/ ]4 ^9 W+ Z - /* 给一个停止信号,使IIC总线上所有设备处于复位 */7 L9 `; J+ p1 N2 s2 H2 @& @6 }$ t
- IIC_STOP();
) P6 ^4 T) i& r' o6 x - ! ]) k' B4 X$ y5 \$ M
- }
0 l: ?+ o2 J+ z0 e: d) ~
# U- l5 f# M6 \" K ^- x, z
0 ]0 L& s) ~4 x0 c
复制代码 转载自:Aspirant-GQ
& d* C7 Q4 S1 u2 ^$ z" d如有侵权请联系删除
0 w6 e: P6 y# N8 Q5 Q6 F7 O, J7 W
" q5 j9 y1 ?! b8 C& W |