使用GPIO引脚模拟SDA和SCL总线实现软件模拟IIC通信,IIC的具体通信协议层和物理层链接:
; J4 ?$ M) {: f' u% Y- #ifndef __BSP_IIC_H
3 ?. T4 O; H2 I: x" w' R - #define __BSP_IIC_H
0 g* F$ D! G1 E* f i% @2 K
, |! L5 p. O5 r, J3 r- #include "stm32f10x.h"
& O B8 X6 ~; c( G1 J6 ] - # H1 R7 o9 f7 q
/ D K z# M8 o; p% G- 0 ?' `1 e& S7 N- _2 S
- #define SCL_PORT GPIOA9 p5 c8 S) q9 c
- #define SCL_PIN GPIO_Pin_27 T( j4 E- m1 a
- #define SCL_MOOD GPIO_Mode_Out_OD$ c+ z$ r! O: A
- #define SCL_SPEED GPIO_Speed_50MHz
/ K! c9 `# _! c4 n5 I2 I - + Y+ [9 d: S- }) t3 ?, S. Q* k
- #define SDA_PORT GPIOA
& T* g% o0 d+ W. V. J7 ?' O4 i7 | - #define SDA_PIN GPIO_Pin_3
( x$ I5 {5 X6 D% S1 n# x4 _( U - #define SDA_MOOD GPIO_Mode_Out_OD
4 p# s! a8 p) o' X( L7 E2 R - #define SDA_SPEED GPIO_Speed_50MHz
6 Q' q0 x4 J5 g/ L% |
& y- f" ~3 T; C% l& V- #define SDA_1() GPIO_SetBits(SDA_PORT, SDA_PIN)
/ Z- q, e3 \- x) C8 x% F - #define SDA_0() GPIO_ResetBits(SDA_PORT, SDA_PIN)7 P4 M. H% S: \1 g8 h
- 6 `- m8 l+ P% I7 ~, O% L `' F8 i
- #define SCL_1() GPIO_SetBits(SCL_PORT, SCL_PIN)+ R$ x( F/ q n. I
- #define SCL_0() GPIO_ResetBits(SCL_PORT, SCL_PIN)( |& Z. C4 u( o
- ! h# [$ r5 U g* ~0 C
- #define SDA_READ GPIO_ReadInputDataBit(SDA_PORT, SDA_PIN)* T% ^* o [! Z5 `
- ! Z- u# r3 N) Z# B
8 J3 j" d' q$ H" B1 K- /* ACK原型为acknowledge,意为:报告已收到 */
- x9 N; n) r0 E - void Delay(void);
8 |. F! _( E4 x. C2 ? - void IIC_START(void);
5 o+ H, |( {2 T1 z! w - void IIC_STOP(void);# \) \2 R: @0 [: F
- void IIC_ACK(void);
! E6 i1 J9 w# e - void IIC_NACK(void);% g& M1 |8 N) n1 U' W
- uint8_t IIC_ReadACK(void);- Y. j, O t* c: ?9 {: Y
- void IIC_SendByte(uint8_t data) ;
6 ^% ?. x/ Q- }" A5 X1 a% S3 B) Z - uint8_t IIC_ReadByte(void);
2 Q7 {% N0 ~7 R8 T! [" E' H8 D - void IIC_GPIO_Config(void);
% Z4 p5 h$ z' W! E4 W# _6 R( ^ - ) M7 H8 M. Q# m. G& x/ T
$ ]0 s$ ^5 _! }$ H' ]- : O3 ?3 n: {( ?$ D, M
^' @0 S, G R$ Y) b, }4 ]- #endif /* __BSP_IIC_H */
) S8 J7 `/ a& Z+ k* Q
. m: p3 g! z( q+ Z. X# s0 V! A" c
复制代码- ' [) B) P- a3 K1 \3 ~
9 K. w- I9 W x' t- ~$ I- void Delay(void)
. E1 t0 Y7 L+ y# ] - {$ Z7 H5 g" s# [( o( i7 }5 M
- uint8_t i;2 M! y4 h- U# G9 k/ j
- 1 @8 {$ C& W8 C" y. h
- /*
5 `$ n; P% U a - 下面的时间是通过逻辑分析仪测试得到的。. F7 m$ B; L% j
- 工作条件:CPU主频72MHz ,MDK编译环境,1级优化
9 u' P5 X/ ^) D" _$ Q -
5 l' J1 C! p8 F1 j1 h - 循环次数为10时,SCL频率 = 205KHz 8 [+ k1 o4 g( f* n6 ~4 m
- 循环次数为7时,SCL频率 = 347KHz, SCL高电平时间1.5us,SCL低电平时间2.87us
4 m, C' E: S. q! t - 循环次数为5时,SCL频率 = 421KHz, SCL高电平时间1.25us,SCL低电平时间2.375us 6 O$ Q* e$ V" A* h* f8 b! q
- */$ B$ |3 w# D( _/ e# Y7 I
- for (i = 0; i < 10; i++);
: E7 |' j- f! c$ U/ A - }
7 L. ^8 H: q! N5 c, A
* G d, O- o9 E6 F4 \+ X) [- ) h' i3 ]6 o; u" D
- /* SCL高电平时期SDA产生下降沿表示起始信号 */' X6 a" a% {) _9 L4 z/ K
- void IIC_START(void)6 c& \( W+ P( D* X U: @
- {
' j' k; F4 Q( Q3 T - SDA_1();6 q2 S5 ^# m- ?7 \
- SCL_1();
& j9 J7 O' ~( A$ i8 ` - Delay();
3 j8 v- e m, G, `6 h. a -
. J7 j+ Q4 F$ [# e* ~' O - SDA_0();3 a, F6 Q% ]$ i& Q& D& z# t8 S
- Delay();
/ r+ o9 a) Z$ n0 d9 M - SCL_0();. _* [" N( K# D' D2 k+ j
- Delay();
2 Z6 }3 @8 S3 ]; r - }
' {7 Z* _3 `7 J; a - * n$ k0 Y& {, M, W6 g, Z* J6 }
- & y1 e& b: c9 V, P1 Q/ K0 O- P. q
- & w$ V& B8 f. [1 |
- /* SCL高电平时期SDA产生上升沿表示停止信号 */
1 |$ M- \" C2 }( ]5 z8 N - void IIC_STOP(void)9 f. U C3 D; A
- {
1 l8 E' p& p2 d( [+ T: B$ r - SDA_0();
4 D0 q0 o0 e* @" ]' Y - SCL_1();+ R" }1 [9 }+ o2 V O& C: ^# F* g+ ^& d
- Delay();
; `- V0 V% E5 j# Q8 L+ q - 3 y4 x a0 e: g: p
- SDA_1();# c+ a I3 `( o4 P
- Delay();' ^3 L! O6 i1 i3 g* O3 p
- /* 停止信号后SDA和SCL都为高电平 */
. A/ q( A8 u# Q; w% o; ^8 j - }
3 o7 x, l/ j, @7 F
" P( F# X. P$ c ^- 2 ~- p8 O0 L+ c9 V) c
- /* SCL高电平时期 SDA保持低电平代表 应答信号 */
6 }9 C+ z! C+ X. D. M* t8 K - void IIC_ACK(void)
5 o9 [7 }: n0 g+ X5 `& ?7 g, |0 M - {
) a. c! t7 T% P3 m' ~. q - SDA_0();* {- W- `0 E/ {
- Delay();6 e' f: E- |8 `) U; [* a5 J6 b
- SCL_1();
/ g, Z* _- c( H) K/ w9 y2 e - Delay();
+ X5 Z! g6 d: X0 p/ b -
0 I" _) `8 M7 a: H) X - SCL_0();+ Y. `$ W- \8 R. M, b
- Delay();
3 D' [, R& @$ T, ^/ f' {0 T4 l - SDA_1();
, V" o0 S) z3 r6 I) I. P( X. }5 Q4 o - /* 随后释放SDA总线 */
/ [# W5 g {( ~) }0 `" y1 V* ? - }
$ g5 l% s* E }& @% c n2 s - , S9 z4 q/ \8 B; J
- , [! I$ G. q9 z
- /* SCL高电平时期 SDA保持高电平代表 非应答信号 */8 b6 r6 O4 C( u; M/ s
- void IIC_NACK(void)& \+ }( t$ L, Q6 k+ ^9 T& O. k" W
- { W7 ~4 a0 t% h6 k( U; v- \4 w
- SDA_1();; r6 m! u! o; j0 \3 D
- Delay();
3 }8 c7 n6 \4 M8 O - SCL_1();
+ _1 z0 I7 k1 r. [5 h2 z - Delay();
, c9 b$ s/ b4 v. H) G -
9 b4 z v ]5 ~0 ?6 Q5 e - SCL_0();' c Z' e5 d% u0 n8 Q
- /* SDA已经为高电平,无需释放 */! h3 I6 x" A" r( S) Y
- }
l9 a6 E; o" |0 `3 J" Z. D, H3 R - ! X7 t1 w4 G" G7 x. {5 w8 |
- ( e# b% }3 g( v1 a" @" c4 d) K" b
- /* CPU产生一个SCL时钟,读取应答 ACK:0 NACK:1*/
0 _; \* @$ ]) B( { - /* 因为SDA平时为高电平,所以没有收到应答时,SDA还为高电平,即读取到 1 为非应答 */3 _9 [' o7 o" g4 B2 K1 q. \
- uint8_t IIC_ReadACK(void)- h0 V1 c- A, w% v
- {- f2 A5 q1 X; ]: j9 e
- uint8_t k;
; V/ Z" {) _2 ]3 V# Y( l0 ?; o5 u$ x - /* 释放SDA总线 */
; d5 K+ |& C( |: y - SDA_1();$ w* `" s- P4 ^0 v. W
- Delay();
6 G( \' C& g" N5 _" t - /* SCL为高电平时,才会读取有效数据 */
. z' K; G$ J+ t: m | - SCL_1();
+ W6 E8 ~ h, E" }' V2 W( { - Delay();
4 l, f; i% @( G- B6 ]5 | -
; f) ~8 U1 S2 [4 ]: U - /* 读取信号 */1 H5 S8 s( y# \1 y
- if(SDA_READ==1)
3 E0 \, S1 J3 c, {+ E+ n - k=1;: \ P2 l/ a4 ^! O( L9 Z3 @
- else4 J9 x7 V k+ s. W
- k=0;, ]& M; b4 K6 b) b4 a; `' u
- /* 收到信号后SCL要拉低 */
+ T/ H% p: \/ R7 J4 _' r& s - SCL_0();
7 U% \+ @" @: _7 U+ y; v - Delay();- J$ V, M/ \8 k
- return k;
; C1 k* ]: ~/ L* N- C1 l# d - }( y+ x& a+ U: y0 g
- ! p2 S0 J9 h. o- N* x; D Z- h
- & o& `- Z/ G! \( Q/ S- W# A( a
- /* 发送一个字节,先发送高位 */
' E: h0 i* @) [ - void IIC_SendByte(uint8_t data)
& u3 p3 n, y6 H9 f( Q - {4 F6 |5 S4 W9 h7 C* j5 b
- uint8_t n=0x01;
+ x, |& J2 [4 R& G* U - int i;
4 l. R8 f5 _& g" Y2 L' l - SCL_0();+ {# N) V4 I( H* Y: A: f8 ]
- Delay();
5 e6 l P2 }4 H/ L0 i - for(i=7;i>=0;i--)+ F( H2 Q/ ], I% F( I& }2 M8 N; l/ @
- {6 {( J7 K0 S9 ]& c
- if(n&(data>>i))( h, E+ s. c$ K5 G9 O! n
- {
! j0 c. k& v1 e0 l, g - SDA_1();# `+ r1 ?& ?3 }) h O2 J0 _
- Delay();3 j! n, |1 P# z1 Q% ?
- SCL_1();
9 M6 d: J) l1 ?* W: M - Delay();# E( K' n6 u, T8 l
- }
! L! q% w2 _$ v$ R' Y1 q! T' U) u - else
( {4 b, u% L; G" {% W8 Q - {
5 g y2 R0 Z3 y9 u1 x# N- z - SDA_0();% H& N" q! y, c& g/ b' _3 J6 j
- Delay();
* G/ r% ]+ [# P- ]% v - SCL_1();0 H$ | ?) u7 [* L0 q( M
- Delay();& F9 q, t1 P9 a; k5 M! \
- }
4 U% @9 T8 A. B, J2 U8 Y8 N4 ~ - SCL_0();
! n$ ~& c6 J3 L4 ^ - Delay();
) V8 ^" S) T9 S: C( U5 w# ? - }
4 Z1 t3 r, B" b - /* 发送完一个字节后释放SDA总线 */5 Q D) {4 d2 N: F% G
- SDA_1();& @" k/ P+ l, v5 Y# c- r6 B1 E
- Delay();4 B3 I8 v7 K. X, N& y
-
' ^+ ^1 f$ [! g: e6 m - }
, t0 p3 `1 |- q9 G6 D% ^; W
, u2 M/ z6 S5 o+ M4 e0 a- m- /* 读取一个字节,在CPU产生的SCL高电平时期读取 */: p. ?+ d, `) n' `8 d3 _& D
- uint8_t IIC_ReadByte(void)6 {, K0 N, L* |% j, T) C0 m7 Y
- {0 M! a. L7 o/ s& d3 F' N# `' I
- // uint8_t i,data=0;1 U% X1 K! h4 m* t3 Z+ A" F
- // for(i=0;i<8;i++)
4 F* p- r, z; W8 W3 n# k+ o - // {0 {" |( b' N- ?. X3 @3 M
- // SCL_1();! a4 O" o: W2 ~# z/ R. i
- // Delay();
! {# o m; R* Q/ e4 U - // if(SDA_READ)
7 J z/ q: f" M# Y4 G) W - // {" m$ t7 E8 c7 W6 m! X
- // data++; /* 利用自增实现对最低位写 1 */: X) @ G( e" }. B
- // }
~1 c; V: B& F! q0 k$ L5 ^7 t$ e - // data<<=1;; c2 j5 _/ Z" @9 U% P
- // SCL_0();8 o1 ?% X. |; u& M, d3 l
- // Delay();* |) N" B! X* q t. Y# Z
- //
' B$ k8 M9 ^0 ~2 B - // }- N* D% B# ?- N" J" P; ]; T( G
- // return data;
7 Z* J) V, K; b - // + v; v- Y; y+ D* J8 s# z* _, F
- % ], j4 ?. }& {
- uint8_t i;+ D% @" H$ |# n3 f+ s4 t, x1 W; E
-
! w* v K! h, ]% i4 R2 u - uint8_t temp = 0;* k, E9 ?. F7 S" i
- ( L1 X# W$ p6 w8 |
- for(i=0;i<8;i++)! c. ]+ i7 l4 L0 _( k
- {
9 B/ K. k3 [/ o. {$ U - temp<<=1;4 ]' U B, l. |$ H) |6 r
- / K5 z9 S1 v' L
- SCL_1();7 B) K/ o9 N/ f/ C* Z
- Delay();
$ B t7 W2 O+ s; H -
1 s/ N _( D: ]7 {. Y6 X* s - if( SDA_READ==1 ); L1 y0 R+ i% Y
- {& M0 e: t# n: L& h* J2 K1 V% g
- temp += 1;
# f6 q* x8 [2 y) a/ K" I) ^+ a/ w. r- S - }
W" ^" q3 ~! e) k" f- q5 E - 6 {; l4 N. P" p. h
- SCL_0();" v! [6 Z6 R |9 L' W: [( x
- Delay();1 R1 u9 h. ]! j( A" [
- }
1 x, W6 M: k6 e4 A/ _: m/ B: y -
R# v5 `, v9 h% i - return temp;# R4 A1 J. m7 l' _# R# [3 B
- }: z3 T- _3 E) |/ n* t; d$ Z* |
: l1 B) W) O1 b( a: ?
5 a% X5 W$ a. t3 d3 T- % K4 A9 F5 v2 {! j& l. }* |
- /* 配置SCL和SDA对应的GPIO引脚,模式都为开漏输出 */
$ a3 r6 {& N% I. x& C8 r7 D/ U% | - void IIC_GPIO_Config(void)
6 Q' d$ X+ c) C - {1 {: j- f2 \& ~% |) x x% G1 D
- GPIO_InitTypeDef GPIO_InitStruct;* T$ c$ X+ O# ~! Z/ g! u
- $ h" T, P7 B; D1 \$ M- |* y% a
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);! L4 L6 Z% a2 E: t( g( f" f' c7 k; Y
-
0 G% U9 K0 d" U8 K8 g - GPIO_InitStruct.GPIO_Pin = SCL_PIN;
/ `) n; o3 a% ]5 F0 a! b, v" W - GPIO_InitStruct.GPIO_Mode = SCL_MOOD;
4 \) T, D0 X- G; d8 ` - GPIO_InitStruct.GPIO_Speed = SCL_SPEED;
; m% S& G$ R) v6 e l4 {$ o - GPIO_Init(SCL_PORT, &GPIO_InitStruct);
% Z; E0 @* R1 t0 F4 Y9 x -
) ] b5 r8 w% z - GPIO_InitStruct.GPIO_Pin = SDA_PIN;: Y5 H2 k5 e# M& _+ R
- GPIO_InitStruct.GPIO_Mode = SDA_MOOD;
8 V4 Z( E8 |0 ?' e H+ t3 m4 I - GPIO_InitStruct.GPIO_Speed = SDA_SPEED;
0 ^& B6 |4 {8 ]8 A1 E1 S0 Z - GPIO_Init(SDA_PORT, &GPIO_InitStruct);) r( m# b& w H- R4 J$ a# p
- " _7 R% C6 B1 s# Q1 K( h
- /* 给一个停止信号,使IIC总线上所有设备处于复位 */9 L4 m' X9 l/ f8 o% M3 [; y
- IIC_STOP();, a) @1 U5 k) v
-
) P# A" Y0 ?) A4 i+ F! D* v5 \ - }2 }. s2 h- E: ]& x5 z' s u8 o
& g/ F/ g0 j" o. Y" D$ r2 M- : z/ P# r! P* y7 B0 J. H
复制代码 转载自:Aspirant-GQ9 D% m9 W J2 @, V8 F0 J4 E
如有侵权请联系删除
& f i' P. T- d: {$ d& ~1 D! S. g; J& b! ?: f% o
. `) K9 _. [! Z# L
|