找回密码
 注册
关于网站域名变更的通知
查看: 154|回复: 2
打印 上一主题 下一主题

51单片机经典范例演练4 使用通用I/O引脚模拟通信方式

[复制链接]

该用户从未签到

跳转到指定楼层
1#
发表于 2022-5-26 10:20 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式

EDA365欢迎您登录!

您需要 登录 才可以下载或查看,没有帐号?注册

x

: r) N9 W: g2 `现在很多单片机都已经对常见的通信方式进行了集成,但是51单片机没有这些功能。如果想要使用其他通信方式,只能使用通用I/O引脚进行模拟。' i! O8 w) g2 C9 k; T
今天我们就以I2C通信作为例子,演示一下如何模拟这些通信方式。3 D: }6 t4 O$ e) N- a

2 A* W/ d! h7 l0 M! B' g# ^一、I2C通信介绍2 l5 K7 Y" O7 v7 G: O) e+ Y
I2C总线是一种简单的双向串行总线结构。只需要SDA(数据线)、SCL(时钟线)两根线就能在器件之间传送信息。
# ?7 B8 Z. V, xI2C通信中,器件有主有从,一般以控制产生时钟信号的器件作为主器件,其余作为从器件。每个从器件又有一个7位设备地址,用于寻址。这就意味着,一条I2C总线上可以并联多个I2C设备,主器件通过设备地址可以分别对这些器件进行操作。' L( c7 v. q/ s5 H* ^/ R
一次I2C通信可分为三个部分:I2C通信起始信号(SCL高电平下,SDA从高到低跳变);I2C有效通信;I2C通信结束信号(SCL高电平下,SDA由低到高跳变)。7 A3 }9 O) m5 U
同时,在I2C有效通信阶段,数据接收方每次成功接收一字节数据,都会主动将SDA线拉低,表示传输成功。/ z2 Z, ], ^, ?6 x' u

8 e* E7 a3 f/ h: H6 }* s由此,我们可以编写得到I2C设备的基本读写函数与等待应答函数:
' k2 Y4 o" h( }; p9 r# `  x8 r3 S//开始信号- {, c3 N7 G2 i, G
void I2C_start()- j9 K6 y& H/ C+ h3 i1 w5 z$ {6 W
{3 c& V1 p# `3 P, z# V
SDA = 1;//同时拉高数据线与时钟线
% L8 R. \! j, N  }6 T0 k% M7 ySCL = 1;
. [+ W7 I5 G/ _5 G9 Gdelay_1us(1);
( U1 r( C: f6 ~/ n7 _( zSDA = 0;//SCL高电平,SDA下降,启动I2C通信  E; u5 f, I2 [( V* `
delay_1us(1);//等待1us
7 j/ A: l0 a7 U& I5 ?" k: SSCL = 0;3 Y: \& M7 Z* a1 _; G: ]
}9 @9 G8 J: J5 R3 n* w

3 L; ^  F' v7 Q" r9 j/ N2 a9 n: Y//结束信号  Q, e; A, u3 p( d( E
void I2C_Stop()
* M: J, }6 Y' X& L3 S{
6 [8 a. B! n& g! t+ a6 I4 iSDA = 0;
8 A% f/ K9 E: J( i& O& |SCL = 1;0 ]( z1 \% \8 ]1 v% t3 o4 M( K  Z, }
delay_1us(1);4 N2 v% X9 x7 x  L
SDA = 1;
0 h( D. W' Z( o& bdelay_1us(1);# D& j, Q3 n& S$ Y! L
}2 u. [+ u9 e2 m2 {1 H( z

( |0 _* r# d7 p, I" j//主设备应答函数
2 e% D& \: x7 Ivoid I2C_SenDACK(bit ack)  |, v' x1 J4 X8 r$ x5 A
{' X# ?0 d# U1 _( Y% C
SCL = 0;//SCL 拉低,数据改变
( |7 c6 w2 ^) K1 s5 G3 r3 F' N* qSDA = ack;//数据位改变
2 L  X' _9 Y1 j! V' C8 M! }delay_1us(1);//延时等 稳定信号
9 f/ O8 I5 K1 }( B' {SCL = 1;//SCL拉高,传送数据* {: Y: u& S8 L) |' L
delay_1us(1);//等待) C" V& T2 H1 A0 k
SCL = 0;//SLC拉低  h! o& G" H# k$ y+ U
}, o4 |$ |+ d, n6 Z

% K+ `8 p1 K7 Z2 Y, |//从设备应答函数
, e8 ?2 T3 K0 f7 }; ?8 z/ l- tbit I2C_RecvACK()1 V: L5 Y* K7 o9 |! X
{5 _: F# Q; A9 V" i! I
uchar wait=0xff;
7 t3 `1 B: u8 p, h' ?4 g5 WSCL = 1;//SCL时钟拉高 数据有效5 R, i# Z+ a5 L5 Z! f: U& @0 _* Y
while(SDA&&wait--);//SDA高电平,并且在512us没有走完; J6 p6 f, i+ b. V; E; ~+ k* }& M
if(wait<=0)
2 v8 w9 V- w  O9 t: o% e; _. W{2 q( H8 T# s) \1 V7 i( A2 {2 B
I2C_Stop();0 }# |# o  [* I' ]6 {6 x2 y6 s+ s
return -1;
4 M' y. O7 m! H& p0 y, F' h}2 s8 z# h' S- j' R, e
WSCL = 0;//否则SCL为低电平,结束该应答
) I2 `2 k1 c# |- M# j8 Edelay_1us(1);- h8 s) |" c( `+ y4 o/ p8 S8 |# q
return 0;% W- [# ^# u3 A4 @: k
}) ?! A- u, u1 j7 |! l
//数据发送函数
$ e( m3 s8 T: k& n" ]void I2C_SendByte(uchar dat)
+ q' m. l% c8 @# X{- Y+ p4 E$ }# i! K8 n3 Y
uchar i;% [$ k, \5 e- m* Z" U( R9 a
for(i=0;i<8;i++), V; Q; C- ^  M9 v& R/ p
{
" a, ~6 ?% M6 ?if(dat&0x80)//dat与0x80进行与运算
) H* N6 u7 K0 J3 G' w( j- ]SDA = 1;, h1 s$ `  p' v3 r( J& R
else- V; }; ]" H! \
SDA = 0;" B/ v! H7 v! Z8 L# @& ]) M
SCL = 1;
% g5 a0 {3 J2 f/ H5 Udelay_1us(1);
; v' p2 @1 B9 O9 `& {  CSCL = 0;, J& L# U/ |+ u( v4 D7 t
delay_1us(1);
2 }3 |3 a, v3 T0 ~dat<<=1;
" t, [7 W) _7 _) F, L}
0 J, v5 W! l2 t- ^9 Q6 k}
, \" C9 H) g. [4 B//数据接收函数* ~! j" Y3 F7 w
uchar I2C_RecvByte()//接受一个字节2 _4 _4 f9 Y  b$ V/ U5 j
{
# L# o: a. ]* G& N5 K. xuchar i;
5 o0 m- s( u# b3 x1 Duchar dat = 0;: `' L( w3 x  W  b1 H
WSDA = 1;
' l+ K5 L$ r% j7 D  c, ufor(i=0;i<8;i++)//一字节 八位2 `% v* {3 w& s1 w% a5 `
{
% k4 K0 T: [# A- c9 {dat<<=1;//dat左移一位,从高到低接受数据% X  _) R4 f4 p  y
WSCL = 1;//SCL拉高,数据有效
$ P: t0 q! l& Q0 d, Ldelay_1us(1);//延时保持: Z# k2 R8 |/ y6 N6 g
dat|=WSDA;
  x( o- r7 E& ^! ^/ V* L( B% LWSCL = 0;//SCL拉低结束数据传输1 E6 D5 G- m  U% P) |5 R/ P4 |; w4 s
delay_1us(1);//延时保持
/ \6 K' m: ?& n}* D$ V" ?6 i/ z0 ?
return dat;//接受八次之后返回dat值
/ _1 A7 u( w" m+ T* X0 N}" {! w! u) R' `" r. z

* H& O; S( {7 V8 {* _4 W, I二、I2C通信流程$ P% B0 r2 N5 J+ D, F
主设备向从设备完整的写操作/ z, w" u4 ^% u% ]7 K
1.主设备发出I2C开始信号:7 l' {% X( ^' @# |$ ?
2.主设备向I2C总线发送要操作的设备地址以及要进行的操作(读/写)7位设备地址+1位读写标识位(0读1写)
9 R2 s3 r" R5 ^3.主设备向从设备发送要操作的从设备寄存器地址0 j/ ?3 I( K- s2 {. \
4.主设备向从设备发送要写入的寄存器的数据) I1 @: |6 i6 ^# f# L0 x
5.发起I2C停止信号5 w# f: s- h. Z: H# [* l0 ?
//对I2C设备的完整写操作( s. ]( E: U7 J2 {' q4 D- d- X
void Single_WriteI2C(uchar REG_Address,uchar REG_data)) l  ]& m" L& _- w
{" B: r3 e0 u7 ~$ q7 J* G
I2C_Start();0 W- S$ R" W' r6 }
I2C_SendByte(SlaveAddress<<1|0x00);9 K0 r; U" W* H$ U- T
I2C_RecvACK();
. I5 H1 ?+ x1 u3 F$ A  xI2C_SendByte(REG_Address);8 ]3 }$ l( _# |* z4 e$ c
I2C_RecvACK();
; x9 [; D" F/ ~( b3 f0 c/ J! M( ?! PI2C_SendByte(REG_data);
) H0 N* [# [6 F1 b* xI2C_RecvACK();
2 T2 Q3 j2 k9 r+ n2 k- s. b! @I2C_Stop();* Q9 i" X5 \' k& ?7 w1 `
}
; @2 P( C( j5 o/ U! N9 y: O# V处SlaveAddress为设备地址,使用宏定义。
: a3 a& B# b, s6 W7 f3 C主设备接收数据流程如下:
3 K5 a0 s$ z1 f" h$ M2 {* ~9 ]- [3 f4 \1.主设备发出I2C开始信号:) z. x7 ^; h5 P
2.主设备向I2C总线发送要操作的设备地址以及要进行的操作(读/写)此时,最后一位要为  写操作
* w! }) {- f2 M8 v3.主设备向从设备写入要读取的从设备寄存器的地址
8 |/ P9 t7 f  w7 f4.主设备向总线发送7位I2C设备地址+1位读操作 标识
8 V+ M( u+ \1 U5 e5.接收一个字节的数据1 A+ J) J2 ^  t; K
6.发起I2C停止信号+ F; c+ f' ~$ [' x6 K+ v

1 v4 ^( i" b: Pvoid Single_ReADI2C(uchar REG_Address,uchar *REG_data,uchar len), M) w* X2 e4 @0 h
{! K0 K* X1 p: S% c) @* D4 S) c
int i;
) Y5 a( w' i0 Q, lI2C_Start();% T5 s4 ^4 t2 [% i( _
I2C_SendByte((SlaveAddress<<1)|0x00);
" E, M0 c' }5 t5 P$ O( v9 ?I2C_RecvACK();( w" R8 c5 e2 o" I: Q& N3 C
I2C_SendByte(REG_Address);
9 H' ^& R: O6 d" L2 [I2C_RecvACK();" F# n) ^6 L& X3 M3 [6 a6 l
I2C_Start();" {! N6 E5 V5 X5 m
Delay_Ms(50);
! q% o+ U) S) x. A3 w# `* M" GI2C_SendByte((SlaveAddress<<1)|0x01);
; Y6 @8 N) c" a5 d# A8 [I2C_RecvACK();1 @/ r( K# [2 o1 }1 T& u

% o9 P; I' V$ f9 }& \% tfor(i=0;i<len;i++): Y5 w* O' _5 O/ `9 s; Z
{
1 U, L8 {% ~) U( y  M5 H, F7 a. VREG_data=I2C_RecvByte();+ _* s  T: U1 O
if(i==len-1)
5 P- ^8 A( y" H( _" p- L9 r* _/ DI2C_SendACK(1);
6 O2 L- O& T* `% e8 ]/ x% xelse8 J8 o, L" R0 E( d+ B
I2C_SendACK(0);
2 |( c; K6 E+ s8 F/ _; D, b}1 t/ B7 X% x' C; x/ k
I2C_Stop();- a% Q: E. I* g0 r
, w7 h4 F$ k4 A3 j! o( W7 B7 l% K
}( [8 V7 x1 P0 k
以上就是常见的I2C设备通信的通用函数。
, r/ p' A/ D( [使用单片机的I/O接口,再配合时钟,多数的通信方式都可以被模拟出来,就比如51单片机只有一组串口,如果有需要,自然也可以使用两组通用I/O引脚进行串口通信的模拟。

该用户从未签到

2#
发表于 2022-5-26 11:08 | 只看该作者
好强啊,谢谢你的文章

该用户从未签到

3#
发表于 2022-5-26 14:31 | 只看该作者
gogogo,学学学。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

关闭

推荐内容上一条 /1 下一条

EDA365公众号

关于我们|手机版|EDA365电子论坛网 ( 粤ICP备18020198号-1 )

GMT+8, 2025-7-18 03:06 , Processed in 0.125000 second(s), 26 queries , Gzip On.

深圳市墨知创新科技有限公司

地址:深圳市南山区科技生态园2栋A座805 电话:19926409050

快速回复 返回顶部 返回列表