|
通过前面 I2C 的介绍,我们知道,要进行 I2C 通信,需要编写起始信号、停止信号、应答和非应答信号。因为 I2C 通信是以字节为单位进行传输的,所以还需要编写 I2C 读写字节的函数。数据的读写是在 SDA 线上完成,读数据的时候要配置此管脚为输入模式,写数据的时候要配置为输出模式,具体代码如下: - /****************************************************************3 N( u3 w6 @, b, K" d% t }6 j
- * 函 数 名 : SDA_OUT3 {3 b) W9 k( J& ?& ?: O* M
- * 函数功能 : SDA 输出配置
$ v4 O: I' V, Y8 [+ g - * 输 入 : 无8 s# h; g9 `5 v: d
- * 输 出 : 无: e3 o ]5 h/ O( k
- *****************************************************************/
% T) ]0 L; D$ A: P* @$ l. m: } - void SDA_OUT(void)
$ G5 L2 L. y8 P& c% j$ Z' E - {
, y3 w3 @9 n+ h* C& Z - GPIO_InitTypeDef GPIO_InitStructure;
4 C `3 \' }9 V7 f0 `% E9 V. z - GPIO_InitStructure.GPIO_Pin=IIC_SDA_PIN;1 {* [8 ?6 W7 X! J3 M
- GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;8 D) ~0 e9 S" a- a0 T/ v G X
- GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;
! s- ~- ^, [0 y7 h. Y: K - GPIO_Init(IIC_SDA_PORT,&GPIO_InitStructure);5 D) C6 l3 b4 ^" z' g: b
- }
复制代码- /****************************************************************% j6 J# V8 I- D
- * 函 数 名 : SDA_IN- l5 m f+ {% Y9 V5 W- J m6 ]
- * 函数功能 : SDA 输入配置
3 z. _0 \& w2 ^ - * 输 入 : 无$ f% [% C. a8 z
- * 输 出 : 无
# H( S& G2 w# e8 b+ Q: ^) I - *****************************************************************/+ C7 [6 X6 g* _) M
- void SDA_IN(void)8 M* t9 g2 B- w: G4 S" F
- {! `7 g$ p. M) j# t
- GPIO_InitTypeDef GPIO_InitStructure;+ ^# C* J) d$ c- C% D. W* b) _3 @5 M
- GPIO_InitStructure.GPIO_Pin=IIC_SDA_PIN;
0 P8 n q% a* z4 z+ z$ |2 g - GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU;* V* Z F0 E$ |& Z
- GPIO_Init(IIC_SDA_PORT,&GPIO_InitStructure);
* K8 a9 g4 S5 V5 q% v - }
复制代码- /****************************************************************; y! {. D5 n0 Q6 f$ D/ k
- * 函 数 名 : IIC_Start
' g+ ~% Q) b- W" F - * 函数功能 : 产生 IIC 起始信号$ j+ V0 h9 ~; a- y
- * 输 入 : 无8 a* ~, y4 v9 c$ \- k
- * 输 出 : 无4 y: Z- p6 c7 s9 r' q+ w& p* t
- *****************************************************************/
" _6 k; W6 ?& ~- W3 l - void IIC_Start(void)
8 q0 f( ~4 [( U1 q7 y: K - {
9 ~6 ]1 t/ a: c% Z; A, L - SDA_OUT(); //sda线输出
) i) F) ^* s. g$ l+ g - IIC_SDA=1;3 [# t* [8 i! E
- IIC_SCL=1;
3 M. x" ?5 L& h - delay_us(5);$ }9 L6 E* Q% ~4 Z5 v* R C
- IIC_SDA=0;//START:when CLK is high,DATA change form high to low; u A L9 A6 c
- delay_us(6);
, W8 `0 D# k4 W; v, k' V - IIC_SCL=0;//钳住I2C总线,准备发送或接收数据0 q" u' {5 d) D8 i
- }
复制代码- /****************************************************************/ Y" _( {5 ~6 k F. E, ] K$ ~
- * 函 数 名 : IIC_Stop
( v' E, i/ E1 C" i7 I3 x2 H - * 函数功能 : 产生 IIC 停止信号
, e# P+ Q3 q1 [- o4 y8 \" L5 c - * 输 入 : 无! b3 q! L! ^" [. O
- * 输 出 : 无
7 \8 X: ]6 u; t0 y- ?! V& M% u - *****************************************************************/
- L, r% }. O. `/ U& O7 e% d - void IIC_Stop(void)
8 P$ B% s" Z/ ]$ W8 w" ` - {
' Q, }) ^ P2 { - SDA_OUT();//sda线输出
7 Y2 c9 z' I4 Y+ e( J+ r - IIC_SCL=0;+ ?* n- Z; v7 r6 v+ s
- IIC_SDA=0;//STOP:when CLK is high DATA change form low to high
, H) w" ?& ?& x5 f$ D! b - IIC_SCL=1;
8 T' z6 s( k+ G: @# F' d. E" } - delay_us(6);
3 r' l5 H7 ~4 T/ }* j$ ^ - IIC_SDA=1;//发送I2C总线结束信号% E, q/ s: S- t+ f
- delay_us(6);5 R$ t6 `. d& x7 ?
- }
复制代码- /****************************************************************
3 |; m! N" \9 ?% b - * 函 数 名 : IIC_Wait_Ack8 q+ k( b. X9 G3 V, H- z
- * 函数功能 : 等待应答信号到来" k' [' }3 {; y- F
- * 输 入 : 无5 A1 |" v) c3 z, e* C
- * 输 出 : 1,接收应答失败
8 A [- e/ g. p, t' l - 0,接收应答成功; s$ { t7 i1 f# @0 W4 a
- ******************************************************************/' O8 l) ^3 p4 u
- u8 IIC_Wait_Ack(void)
; X* l) _+ ^ ?# K5 ? - {
5 k% F4 n* T" _1 q3 `) J+ O - u8 tempTime=0;
/ a( i3 x% J) d) z ? - SDA_IN(); //SDA设置为输入
+ F3 [ h F# f' `6 A - IIC_SDA=1;7 Y* ~# H" |5 h; V% `
- delay_us(1);
4 i [% x0 ]/ A/ {7 @* M" A: ` - IIC_SCL=1;" o: i$ H P/ z& y
- delay_us(1);/ u/ e* F$ l, }7 Y# G
- while(READ_SDA)
* }; L# n7 E5 Z2 X, F' H - {
3 t* H4 ]; I- A- x2 a - tempTime++;$ ]% v$ r- h8 y' b* ~& |0 s4 _
- if(tempTime>250)
' L# P2 c5 ^ Z! X! g - {' I! [; W! w5 d9 d+ f( x4 ]
- IIC_Stop();
3 |: J |! m0 g8 N/ C! e2 Z+ v! I - return 1;
$ g; h* b1 R5 {; ]6 u - }$ _3 ?# g' v$ y; }4 \4 }
- }; n! g" R: e- S" @, w2 P0 o
- IIC_SCL=0;//时钟输出00 t& M3 I& G) S: y& R
- return 0;
" \7 J2 v% H4 Z E5 j - }
复制代码- /****************************************************************" D0 i8 H7 ^* p' O9 z
- * 函 数 名 : IIC_Ack
: A4 c8 U" R3 K$ C; l - * 函数功能 : 产生 ACK 应答( D( N9 A G8 @4 C A
- * 输 入 : 无
- S4 h; T3 P4 Q' |2 w3 a% K0 z" j, t - * 输 出 : 无7 u8 y$ L$ |+ \9 [
- *****************************************************************/
4 s; k" G- d! Z' v a - void IIC_Ack(void)
5 l: z4 H# b4 d9 V5 C# c/ G! t - {/ C# |$ F8 F* q( Q
- IIC_SCL=0;$ R' l2 @- Y. t
- SDA_OUT();; L3 J$ Y8 A0 B3 e+ n( b6 B
- IIC_SDA=0;, V( g. o8 w9 O" v
- delay_us(2);
; |0 u. h8 B; Z! @) Q) d - IIC_SCL=1;
/ Y, [7 r* W: Y4 H - delay_us(5);
# d: p- J4 J! p$ |1 l0 I - IIC_SCL=0;& P. S3 h& p; K" x0 u
- }
复制代码- /****************************************************************6 J7 X: Q# B- v5 V4 q
- * 函 数 名 : IIC_NAck
6 W) C( n9 U- K) q8 ? - * 函数功能 : 产生 NACK 非应答
$ S! }1 N7 r& E; k% o/ V* k - * 输 入 : 无
; G5 j/ ^" f+ y. Q/ A5 p( e( V - * 输 出 : 无
: ]0 m6 T0 k7 Z3 ^2 q - *****************************************************************/
4 J5 ?) V1 k2 h - void IIC_NAck(void)
- H0 M6 y2 B$ j+ T: }" Y8 H - {3 T# J: J# T D+ t1 F& J9 n) M. D
- IIC_SCL=0;8 y8 @9 Q& q) P7 [; W- U
- SDA_OUT();
# o3 Q5 F B# \% W+ ~- v5 S7 Z - IIC_SDA=1;, a D; T" H" G4 k: e
- delay_us(2);
0 B2 x. Q. H7 E4 i - IIC_SCL=1;6 L6 T/ p7 W7 q0 V
- delay_us(5);
9 g5 P. O- U) q4 U7 Q - IIC_SCL=0;
3 ]5 y% ~$ ^6 i8 R. Y - }
复制代码- /****************************************************************
$ ] B+ H+ `8 C- h, U H1 i - * 函 数 名 : IIC_Send_Byte
% q: L3 s/ B7 Z0 d, C - * 函数功能 : IIC 发送一个字节% ]" C. K2 h+ i/ P+ M' z
- * 输 入 : txd:发送一个字节& u. \" f+ J6 V1 F
- * 输 出 : 无
5 u- m2 R8 j; W- |2 J( u: { - *****************************************************************/
" o$ {% F& _: a0 n, ~# o - void IIC_Send_Byte(u8 txd)- y5 i# h; T& H; [$ B8 B& ^+ P) n% X
- {& [- U/ q- i# w- k
- u8 t;
2 \+ y& O0 E9 \& r4 S: F - SDA_OUT();; ^! G) _# \9 v. \
- IIC_SCL=0;//拉低时钟开始数据传输
- l( {" D7 T* m3 L' i3 n - for(t=0;t<8;t++)
7 n5 Z k q+ Z* ]) o7 P - {" _: \# r4 V5 s5 l1 X! Y& `
- if((txd&0x80)>0) //0x80 1000 0000
; Y0 H8 D( j7 ]! r6 E9 L - IIC_SDA=1;. P) u) {: F% D% n0 T9 o1 G
- else
& h+ h5 o( j& { T8 T: y$ j - IIC_SDA=0;
) T- T x& Y; Y0 B - txd<<=1;3 t: n1 u ?" ?9 x5 @. A
- delay_us(2); //对 TEA5767 这三个延时都是必须的: h v, O. l Y9 L# R9 R
- IIC_SCL=1;# K/ P/ d" ~8 o' o
- delay_us(2);
% X- g, y* B) [& ^. n' P$ q% U v) N - IIC_SCL=0;/ M# W7 a6 M: v3 ~
- delay_us(2);
4 S4 D0 e8 b* T) P! c& A - }4 S% o# Z: j z! u
- }
复制代码- /****************************************************************
5 b( p1 \6 Z3 C+ @7 q - * 函 数 名 : IIC_Read_Byte- M; Y* R) L9 C" a' f
- * 函数功能 : IIC 读一个字节
0 X0 |: o8 K- m( O1 C1 }$ P - * 输 入 : ack=1 时,发送 ACK,ack=0,发送 nACK
2 U+ L) }! c7 o1 I) W+ a - * 输 出 : 应答或非应答
4 y: [; z' @, |- x) D5 f - *****************************************************************/* Z7 j- K) e. a- V4 B
- u8 IIC_Read_Byte(u8 ack)3 n9 [1 ~9 j; L
- {1 L3 b2 C) K' P$ v; J p
- u8 i,receive=0;0 x5 C; U% x3 W* a* j
- SDA_IN();//SDA设置为输入6 C$ }0 E8 j2 c' z( {- }7 ^$ p
- for(i=0;i<8;i++ )* H2 J+ `9 h; k7 h
- {+ m3 D: T P. {
- IIC_SCL=0;8 J- \) K% R! P' j. u; ?. u+ V% a
- delay_us(2);
( k3 D% O8 \8 A% L7 c+ S5 ? - IIC_SCL=1;
. [$ W* ?: } Z: g3 @ - receive<<=1;
8 O/ q2 t! w5 \' j - if(READ_SDA)receive++;" R, J' a4 Y4 Z0 S$ r- e! {
- delay_us(1);4 B) t3 X2 K8 R4 e
- }$ b _ Y! a( {: i% S- y1 C1 ^! Y2 ^
- if (!ack)
% ^8 s+ G n. Q3 i4 O- p8 v( ^ - IIC_NAck();//发送 nACK5 O* Z( l( i. W2 K. f5 }
- else0 G" f! ]) ?2 s$ K+ ]
- IIC_Ack(); //发送 ACK
) H: O! H; p7 T4 L - return receive;
. M9 s1 m4 ?! U j. _3 t4 t - }
复制代码
- y3 h0 V/ u k o6 ~0 {
SDA_OUT 函数功能是配置SDA 管脚为输出模式,SDA_IN 函数功能是配置SDA管脚为输入模式,这两个函数我们是通过初始化 GPIO 方式完成,当然也可以直接配置寄存器来修改管脚模式,这些内容在前面 GPIO 章节就已经介绍过,不清楚回过头看下或者查看下STM32中文参考手册 GPIO 的寄存器部分。
1 T+ e$ h2 |" L4 w3 L |