使用GPIO引脚模拟SDA和SCL总线实现软件模拟IIC通信,IIC的具体通信协议层和物理层链接:
' N& P) Z0 ], D1 h- P! \3 W- #ifndef __BSP_IIC_H
8 ` g' J+ Y, g+ J, p2 N - #define __BSP_IIC_H) w7 v, r8 R g8 E
" q6 O+ p* f. N+ i, o/ W8 U- #include "stm32f10x.h"( q- ?( e- T5 X. G" S4 l
- O- |2 v; G1 T9 F& g- ; n0 i2 p3 `# w% y5 n# d: p
- + o. I4 }8 q2 C% ^ p
- #define SCL_PORT GPIOA
; C* q- v. y) X& i8 _/ x - #define SCL_PIN GPIO_Pin_2
; u; [. J7 U" g8 @9 |" b - #define SCL_MOOD GPIO_Mode_Out_OD
- \; l6 ~" ~! V7 e - #define SCL_SPEED GPIO_Speed_50MHz
0 Q' C; o8 A: H( a+ T7 H
. g ~# u, }6 a$ b# L C2 }4 S4 D- #define SDA_PORT GPIOA6 l e+ I' G/ Y1 @2 X: Q
- #define SDA_PIN GPIO_Pin_3' f0 c6 O: w7 O8 w
- #define SDA_MOOD GPIO_Mode_Out_OD, \8 |6 \! t/ `7 Z6 z% Q% g; J7 f
- #define SDA_SPEED GPIO_Speed_50MHz
$ C$ D M% M/ m' U+ F) }3 O
% `+ K; x' E! q: T5 \( \3 c: k- #define SDA_1() GPIO_SetBits(SDA_PORT, SDA_PIN)
) [+ T* ` u* w ?% s - #define SDA_0() GPIO_ResetBits(SDA_PORT, SDA_PIN)- o# k, r/ T: f& ~+ p
- & ~$ G ~0 d1 W& I7 X2 V% b2 E' ?
- #define SCL_1() GPIO_SetBits(SCL_PORT, SCL_PIN)
|( z" o+ t( @' `) e, @ - #define SCL_0() GPIO_ResetBits(SCL_PORT, SCL_PIN)
2 \& H9 g( |5 k/ M
! i8 G$ X& l3 u/ q* K- #define SDA_READ GPIO_ReadInputDataBit(SDA_PORT, SDA_PIN)
; N. T4 s# A: _$ C' r* ^' n - : w2 B3 t# k. n: B' _: J. K
- 6 m9 k' D" ?3 W8 m; i i* M
- /* ACK原型为acknowledge,意为:报告已收到 */
& m) c. u r" f( n J9 |) y0 \ - void Delay(void);0 S( U) L$ E$ P$ m4 }/ Y) L# i
- void IIC_START(void);
( A7 O$ a9 X9 K1 E$ F8 M; p2 v& [ - void IIC_STOP(void);
) L9 X- ~% l1 J5 f - void IIC_ACK(void);. \# W* m; i8 m( ]0 s" Q) n8 G' Q# A
- void IIC_NACK(void);/ c2 X7 C( q1 x% f2 `$ M+ `
- uint8_t IIC_ReadACK(void);7 s: y |3 j& C+ Q0 u4 @6 b; V
- void IIC_SendByte(uint8_t data) ;
. x. N Z; N4 N/ j9 U4 ^8 h" n9 x, N - uint8_t IIC_ReadByte(void);* G6 s/ q2 E" C) {
- void IIC_GPIO_Config(void);
4 G- f+ o4 n2 u: [ - ' q7 W! T+ E& s& X$ _8 p' d. M
. P- P: D- D$ E' f- + L! [; F0 r4 H! q2 D# u
- 5 y; P+ Q' y, w8 |0 f
- #endif /* __BSP_IIC_H */
x6 b% U" o" t9 K8 Z: {* e$ L. g9 X - |* p* ]- b3 E" X% _% O& F0 r2 L- I
复制代码- ) U5 o7 ~2 V7 J! }' B% W
- 0 ^7 d; K k o. t
- void Delay(void)
" E7 |$ H) J) B# A3 j7 d% D - {
s5 m% W) {0 k/ Z; e' v) V1 } - uint8_t i;. Q# Y( @/ p" S' i5 u% u. j
- 5 M: e- V% h* W w% x0 ]7 {7 j
- /*
% s, x# `) m0 ~4 N) b - 下面的时间是通过逻辑分析仪测试得到的。7 u/ n# X$ b4 R3 U
- 工作条件:CPU主频72MHz ,MDK编译环境,1级优化" r' V) \2 O0 o# K' Q) h8 P
- 7 k; h/ [. I1 G) t# b$ D
- 循环次数为10时,SCL频率 = 205KHz
9 e, X/ L7 ?& x; r1 Z' K+ c' l - 循环次数为7时,SCL频率 = 347KHz, SCL高电平时间1.5us,SCL低电平时间2.87us " W0 S0 E0 W M5 U7 v2 }
- 循环次数为5时,SCL频率 = 421KHz, SCL高电平时间1.25us,SCL低电平时间2.375us
" @5 y( ? R0 ]. c$ x" X% W - */3 p8 ~: l8 q5 X3 Q- P
- for (i = 0; i < 10; i++);- l `1 v+ c1 O2 ^! U4 F q6 u
- }6 f/ E% t5 @; z7 q& ^
- . v0 T- X1 F; r3 a3 M4 Z7 @
- ' i; J7 a& g) S3 ]6 E
- /* SCL高电平时期SDA产生下降沿表示起始信号 */
* k& \9 ^; Q+ r/ D: u - void IIC_START(void)+ O" C+ y$ |7 O* X }7 {
- {
, V& x% q# J7 g0 o) Z5 n% ~. w+ f4 T - SDA_1();
! G& c s0 M2 [0 x3 i1 p - SCL_1();" [5 M: _! `" C
- Delay();
1 C" d8 W3 A. W8 t. q0 r N, E - ( Q ]: E) p( |% b& }0 p0 E
- SDA_0();
( a+ c, |9 |- R$ ]* w - Delay();
( t, I; t* V7 i3 u7 ~ - SCL_0();% h7 }8 U. x# `( [+ {* O) {4 J
- Delay();
. p7 e# G5 S2 }2 ^0 ~ - }
4 y* I' P0 m9 i- K+ i& U, S c5 a2 @ - ; I1 z% m) ]) f% }, i; ]
- & g" P7 d/ V5 Q5 {# Y$ x
- $ D' w& ]' X( P% S9 w' @; T- F3 b
- /* SCL高电平时期SDA产生上升沿表示停止信号 */2 ~- t$ c5 u& B1 R5 }3 S7 K
- void IIC_STOP(void)
: `" I, Q( I0 V - {
) s! G6 c* B" x# \$ G" p" u: C - SDA_0();
8 f. A( y! Z6 r! r+ j' L - SCL_1();/ O+ m, d; y6 ]; c, |
- Delay();) M. A* O; m8 I* \% i* `) J
- 5 k# F; u$ p3 Q6 u5 g" ?/ s
- SDA_1();
1 N' j! @1 q+ k! r& q8 \/ D0 z - Delay();7 A1 d* f8 C- |" w
- /* 停止信号后SDA和SCL都为高电平 */
6 @- T2 B& d2 O/ n - }) N! \, C6 v2 b7 O* p
1 k: a6 o! G/ r1 C1 w
2 I2 @! A- I5 s* j- /* SCL高电平时期 SDA保持低电平代表 应答信号 */
" y* r9 n3 G2 c, L$ V - void IIC_ACK(void)
! j6 m/ j5 V5 O! D1 p& E - {
6 j( e3 p% V8 T% s1 D6 x - SDA_0();
- c, F( q y! L- W. Q9 z - Delay();* u. ?8 i6 O2 E5 C
- SCL_1();
& L. q) A0 x3 f( n+ ~7 C! E - Delay();
$ R4 \% Q$ s( m6 f4 g8 n - $ ^5 \; r( W, ^1 j' ~4 l
- SCL_0();* i5 ~9 `8 X' h% k8 h4 _
- Delay();7 L# ~' E' H( _3 T+ O* ~$ P
- SDA_1();3 u5 r8 z3 N% G
- /* 随后释放SDA总线 *// {) z6 M& V# t% D+ d
- }' ~9 h) c. d+ X2 s+ u0 T% G3 z
& F1 ?8 }6 r1 ^" S8 f' b3 k- T# J- 9 h" Z/ S! m" E. a+ R& ~; n
- /* SCL高电平时期 SDA保持高电平代表 非应答信号 */
c3 {. S" ^8 M+ f' K - void IIC_NACK(void)% x% k4 N# \' o
- {: Y9 L! t. N3 P8 h2 u! b. T
- SDA_1();2 n; D% H9 M7 u* C% h0 j8 g; E
- Delay();
. g9 f# N) a7 Y- J - SCL_1();- q, F5 s7 Y& I5 _% c: r; ?
- Delay();7 c8 ~& B2 f3 }5 |% l; m5 c2 i; G
-
0 s1 M3 S/ g' q. k - SCL_0();
4 P7 J' b' k, S3 E! } - /* SDA已经为高电平,无需释放 */
9 p1 I2 G' w9 }: s* [2 O1 _ - }
2 r* K8 G J* J3 n2 y- E - S: Y$ T( }9 X% {% b* F& ?1 m
- 9 Q/ j2 ~( R) b2 n2 ^
- /* CPU产生一个SCL时钟,读取应答 ACK:0 NACK:1*/' f- M& P& C4 J* ^$ m5 g6 @' s
- /* 因为SDA平时为高电平,所以没有收到应答时,SDA还为高电平,即读取到 1 为非应答 */
' u8 J, u& e) g6 }3 G7 T$ ] - uint8_t IIC_ReadACK(void)
. u; b8 z9 {& t - {
* F2 I- {! m0 C! { - uint8_t k;
7 N6 Q) o: ~4 e2 W# W - /* 释放SDA总线 */
+ u2 J. h* C5 a3 | - SDA_1();
5 x0 h5 D9 O, ]1 ?% g6 i% X - Delay();! a3 a t# ^- {* i
- /* SCL为高电平时,才会读取有效数据 */4 d2 X! d5 H9 R) g# z% c
- SCL_1();' t& e3 e$ c q0 r. J
- Delay();
6 O7 I; v) M) k; Z" {2 x1 E' \3 p - 4 I. n9 t/ i! N+ V
- /* 读取信号 */& [7 d2 v2 V: j* s
- if(SDA_READ==1). n9 s1 {5 G& e; j. P
- k=1;
, e, \' x1 A( O7 q% J3 j - else9 L; C# e6 m& l, N( q
- k=0;" b$ c, [& T- `4 U1 T$ X+ P% x- F$ x
- /* 收到信号后SCL要拉低 */' D: B) `4 f$ M( J, E
- SCL_0();
+ [! ?; w" n* s1 Q& j' ` - Delay();. y' ~8 T6 l# P( R
- return k;& @5 N! I# s/ ?0 I
- }
+ u% Z. _2 C$ L4 b3 g2 { - 8 S# F- a3 E* v. M
% l9 H7 g" \$ O* j: ?! d4 l& i( T- /* 发送一个字节,先发送高位 */
& Z! P8 y& g* |1 b3 ^5 a - void IIC_SendByte(uint8_t data)
9 r: r$ X4 h, y9 g' n! e) m - { O0 V; c( s4 o1 r/ C
- uint8_t n=0x01;2 ^$ P! K% g3 u* ?
- int i;
: a# J" v0 P; U& W: E9 x - SCL_0();: f7 J' g! @5 u- h% x
- Delay();
! m& Q$ K3 G) Z$ J; u. j - for(i=7;i>=0;i--)
4 Z0 Y' Z. Y" k7 x2 Y8 m& A1 f - {' v9 W4 k" C" t; k7 F% \
- if(n&(data>>i))
% E8 @8 }: B2 J1 T- H - {
2 e; C1 [) M( X' L+ T - SDA_1();' q9 X6 x7 I n [! W% d
- Delay();3 P; ^0 x5 C, i4 \$ h1 b3 n* ?
- SCL_1();
2 b7 ~0 i( q" V4 q" Y - Delay();
5 I- K* L) Q C! z" X% i - }$ m, |4 i: R. h' W' }5 U3 a2 S
- else
( i/ @! `- Y2 {7 A - {
" c. \8 x, x: ~& `& O( G - SDA_0();
* N9 h: x' Z3 ~ - Delay();
* C$ p o# f4 b2 H# Z+ } - SCL_1();. D x" G& s" |
- Delay();
( e- v/ }$ u! K# u2 v - }
: g- V$ d2 Q' @+ a - SCL_0();! b6 Z* ~ `1 P- u4 ]4 f
- Delay();; s% V2 p9 l: b
- }
) g3 i" r6 F5 O% U! P - /* 发送完一个字节后释放SDA总线 */& B1 _% ?8 E0 S# L5 m
- SDA_1();
# [4 R1 k+ k$ X7 s- F { - Delay();3 @* u& J6 ~6 ?
- ' o8 F! g; @. Y) G" o3 _
- }/ W$ d; y9 R. E
6 {1 y' }$ B& E4 h/ N8 t- /* 读取一个字节,在CPU产生的SCL高电平时期读取 */
. g2 ?4 Q% n$ T+ u4 n/ O( d - uint8_t IIC_ReadByte(void)
! ^; n3 v0 r$ Z' p - { G1 i5 b" i& P2 d# Z
- // uint8_t i,data=0;; S9 a# r# Z% L4 ^3 K
- // for(i=0;i<8;i++)1 [, ^# n. D9 R( D
- // {
' @1 S& b6 O6 |& `' t' j. r - // SCL_1();$ @9 p' |# X6 C5 c
- // Delay();" U8 [5 c. V4 e0 a
- // if(SDA_READ)% X" U( Z5 x: N5 z4 O. b
- // {4 d1 J9 p& R1 R
- // data++; /* 利用自增实现对最低位写 1 */
( `8 `! b+ p \ - // }6 I, F0 @2 K' h; h7 l$ n8 V
- // data<<=1;
' p% Y$ R9 }' {( F( v/ y - // SCL_0();: }# h8 ^# H* c
- // Delay();
8 {8 S/ u, A7 T' E/ t1 `/ d - // ( Y e1 o; x' m7 S, [* ^& Z0 q0 h% Y: ^
- // }
3 l- c; M1 v' Q - // return data;
! B6 u/ @& O3 ~8 s& z; y* ?- S; Z - // 2 Z+ _6 M/ j& `, }1 q" _
- " O* Y0 S) T* z4 F
- uint8_t i;1 `4 Q3 |" b/ c4 Q! z7 p3 K% N$ L
- ' `8 m& O7 g& w4 M2 \ ^; @
- uint8_t temp = 0;
* u. \9 `1 S8 ~8 y, R3 I- t - * z7 Z3 C8 x7 R: y
- for(i=0;i<8;i++)
/ D# v- c3 p+ z1 X3 {* P! f! M7 o - { " L) v7 U2 Y& d8 O% H
- temp<<=1;
! I& p$ ?5 ~& y; d0 _: L" J4 m - 7 |& f, E: ?) y0 B7 k, ?0 F
- SCL_1();2 X& d+ Z8 b# H/ ]2 @! T
- Delay();( i1 U. P+ _$ d7 J/ [
- & \! z! Z7 Z6 o
- if( SDA_READ==1 )
+ J6 J' m( `+ ]5 z- V& O1 J - {
' ~' W2 E5 z& W% u - temp += 1;- \" q9 ~% D, U5 {! H5 G( ^/ h
- }, U2 G3 O% g% ^+ @* a2 Y
-
m) e) Q" k& o* c ?- t - SCL_0();6 ]+ l: l! f# ?' ]4 j- H+ H/ O" c
- Delay();
! {' ~6 Z: ?: h9 I! C, N( U - }
" A( b6 A' \ g) Y - , e- h" S4 e* s7 \
- return temp;% m7 O. J( t8 m# I, E# \
- }
1 B9 {' O) E( `, {; c' _ - ( _$ U4 q+ w# t
- 2 I8 U W3 @3 f9 A/ W
+ V' u" d" c9 b' P" ~- /* 配置SCL和SDA对应的GPIO引脚,模式都为开漏输出 */, l* s" u& c% M, s; ?+ z
- void IIC_GPIO_Config(void)
2 G! N( V" X0 N) `2 l m - {" @6 ~% n, A8 E: B% ]
- GPIO_InitTypeDef GPIO_InitStruct;5 q, }# B7 o, M1 ], A
-
2 }: s; }& k. F' P. F, `6 n2 w; I - RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);' f$ i, N Q8 W
-
4 c' w1 b* X9 X8 j+ f0 u - GPIO_InitStruct.GPIO_Pin = SCL_PIN;
; o6 Y1 Q1 l9 _. P$ [1 ^, P3 t - GPIO_InitStruct.GPIO_Mode = SCL_MOOD;6 k) _: { K& l6 f0 ~$ y$ z& y
- GPIO_InitStruct.GPIO_Speed = SCL_SPEED;
; Y5 G( M! T4 |! l8 v - GPIO_Init(SCL_PORT, &GPIO_InitStruct);
, j0 F. y8 \! z5 j2 U( P4 m - * ?) r2 c8 _3 N% k! x3 P
- GPIO_InitStruct.GPIO_Pin = SDA_PIN;
7 h0 k$ e% a# A8 N1 }' O9 [ - GPIO_InitStruct.GPIO_Mode = SDA_MOOD;
6 R8 y7 M3 Z- l' k - GPIO_InitStruct.GPIO_Speed = SDA_SPEED;
4 [: q% y+ l7 O2 O2 G - GPIO_Init(SDA_PORT, &GPIO_InitStruct);4 }3 T% x; m/ W1 p" I
- # B% H3 Z# g' ~! Z0 Q4 D
- /* 给一个停止信号,使IIC总线上所有设备处于复位 */
" p4 u \: |+ d& o+ x" [ - IIC_STOP();
- ^+ l! `2 _& i; p* v! O, k$ V -
1 Y: `2 s: q4 g) G- Z1 Q% ^, u - }
) J/ J$ F @$ n+ O# n5 S* A- @ - % q2 \4 S6 W( _/ I! A3 v
) N. l" ` ]+ K# R5 h! f7 b5 E4 }
复制代码 转载自:Aspirant-GQ- x' J6 J* e3 M3 F
如有侵权请联系删除
- B# b( v" T. G, T- m% r7 x* \: e( n
) h m2 e5 r' ~4 K
0 g! g0 K: ]- C |