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

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

[复制链接]

该用户从未签到

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

EDA365欢迎您登录!

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

x
" U+ v5 D1 m& M" g
现在很多单片机都已经对常见的通信方式进行了集成,但是51单片机没有这些功能。如果想要使用其他通信方式,只能使用通用I/O引脚进行模拟。
: E3 M9 n4 H; Y7 l6 |' q- _今天我们就以I2C通信作为例子,演示一下如何模拟这些通信方式。
' F( |$ T7 Y' l, }1 }; h% m8 E, I. t
一、I2C通信介绍
4 _7 F5 `+ [" X6 j! }I2C总线是一种简单的双向串行总线结构。只需要SDA(数据线)、SCL(时钟线)两根线就能在器件之间传送信息。# I1 E6 N$ v  Q# w7 K4 C
I2C通信中,器件有主有从,一般以控制产生时钟信号的器件作为主器件,其余作为从器件。每个从器件又有一个7位设备地址,用于寻址。这就意味着,一条I2C总线上可以并联多个I2C设备,主器件通过设备地址可以分别对这些器件进行操作。( L* T( z2 e7 s3 H
一次I2C通信可分为三个部分:I2C通信起始信号(SCL高电平下,SDA从高到低跳变);I2C有效通信;I2C通信结束信号(SCL高电平下,SDA由低到高跳变)。( P8 v  H! g; @  O9 Q
同时,在I2C有效通信阶段,数据接收方每次成功接收一字节数据,都会主动将SDA线拉低,表示传输成功。
% }4 G' v5 _& t0 A" r* ~8 h 5 p/ K) a9 n2 }  `' ^& c
由此,我们可以编写得到I2C设备的基本读写函数与等待应答函数:
6 {  D- F- N- C  t2 r- R//开始信号5 X8 S, u' }) d/ N( r
void I2C_start()
5 u7 H  y2 K. N7 _& Z3 k{, k9 M% I: L. o
SDA = 1;//同时拉高数据线与时钟线' R3 W3 z7 K' C' n3 g$ P
SCL = 1;) n2 c1 C9 k% a$ f, E# i
delay_1us(1);
7 @4 B: B4 T2 X' n, e$ KSDA = 0;//SCL高电平,SDA下降,启动I2C通信8 p/ g9 `9 W, B% g0 M' [2 d9 Z) }
delay_1us(1);//等待1us2 y# Z/ K, Q# b0 ]% k+ M
SCL = 0;
- U7 {" g& n8 ~8 y9 F/ O}7 Q. I! D8 J! S3 J$ c0 M
" h0 T  T. H" h% v' H9 X+ B
//结束信号' U9 i7 ^/ ^6 k5 |4 |& ~
void I2C_Stop()" @" e8 ~2 m8 R) u, y' B
{$ j% ?7 V. [1 Y" G; U; B, w, s
SDA = 0;% N' n8 Q' n( f5 t5 {
SCL = 1;7 x7 f* {9 n# |0 W
delay_1us(1);
, B6 b8 L+ \) lSDA = 1;/ N; W' ~' Y  O4 T, U
delay_1us(1);
1 }3 F! k5 T: W: D}
4 l  V9 z) S8 [/ ]: S/ L
8 Q( v  l- j, l* j% c5 }//主设备应答函数/ c$ }( P& I' X; e
void I2C_SenDACK(bit ack), {4 [: g* T, s7 ^! K
{) D1 q# }7 v, m
SCL = 0;//SCL 拉低,数据改变
7 S* ?7 B( B' N6 v: VSDA = ack;//数据位改变' Z, p" H5 S4 k) m8 j
delay_1us(1);//延时等 稳定信号% H* \" R* u# U( O( S5 H; U
SCL = 1;//SCL拉高,传送数据) i, `" N- m0 e/ ^. N& c
delay_1us(1);//等待
, V5 G5 U- B* I* L+ b# y: ~SCL = 0;//SLC拉低
9 m, b# I; E, ?1 T1 U}0 e% T8 d% ?" G( \) F
; ]) k" K# `) @+ c
//从设备应答函数9 z! A  e; C& y+ R0 a8 l
bit I2C_RecvACK()
" z) s! ?- f5 _" E7 P8 i{
) h' X& p. {2 i+ J4 o1 o" vuchar wait=0xff;
) A. n- {6 O9 E% }2 A" {SCL = 1;//SCL时钟拉高 数据有效
+ C& w8 [+ d5 s7 V. n. Iwhile(SDA&&wait--);//SDA高电平,并且在512us没有走完% I+ Z% T7 M* j2 }, u. f
if(wait<=0)& \' Z+ t9 N7 N, K( q+ g3 T8 G3 z
{  t! L3 K% L2 |
I2C_Stop();
5 A8 a4 q% d# ~8 }return -1;" K# m  z' B0 u, _/ p& b- J3 e
}/ E! N% i% `: O# C
WSCL = 0;//否则SCL为低电平,结束该应答
; x; m' q6 y5 ~5 O+ l" h0 U& odelay_1us(1);# J8 m9 z3 ?* B1 b" P% v
return 0;2 |) p6 }1 A, o6 ]2 {3 a2 g$ f! ]7 _
}- u0 [# a, A" y7 |5 J$ ~
//数据发送函数* u  M6 M0 `% o0 s4 q$ q3 j# f3 {
void I2C_SendByte(uchar dat), O  n. f/ Q) [/ @) k  X
{7 Q4 [' M: g: ~% q- H6 ~2 W
uchar i;. I7 v2 a; u8 E
for(i=0;i<8;i++)1 J6 W4 u& ]- i
{2 a* C) C8 ]* }7 U
if(dat&0x80)//dat与0x80进行与运算
! B4 {- f" C: n8 W$ e7 ]" Q7 `SDA = 1;
; B6 c9 m) a  g; relse
- Y5 N! T: o1 t8 m% _# @SDA = 0;
. J" w6 f) I# X$ a' C: W) n5 N1 ~SCL = 1;1 X  j) t; W+ p3 t+ @
delay_1us(1);" U, }7 q7 _, K$ C! A% l
SCL = 0;
) B  ]) [0 a7 B( d( v) F% Gdelay_1us(1);
! x1 C! j6 _8 [& x- w, i. qdat<<=1;
) K3 ?6 @8 [) Z7 x. b% A}; h, H5 _  b0 T
}
  L8 ^7 m) L! T, e! A! ~//数据接收函数
5 B$ c+ S; O# i; m5 m+ }0 y: `! U2 Suchar I2C_RecvByte()//接受一个字节3 `" U% v7 X% b  z! l
{2 C( v" n! B# y1 p) M1 W) S
uchar i;
" C; B$ v! J, }$ juchar dat = 0;
) I: m# Q- b- i" M' iWSDA = 1;3 X# D" u  I4 Y$ ?- V8 G0 b0 L% H  n8 n
for(i=0;i<8;i++)//一字节 八位- S! g/ H8 i# j! G
{
# ^' e9 ?2 I6 w8 Mdat<<=1;//dat左移一位,从高到低接受数据
/ F) L% G0 O; _WSCL = 1;//SCL拉高,数据有效/ \2 _7 b# n6 h7 }9 \
delay_1us(1);//延时保持; N! ]+ P, B5 [
dat|=WSDA;" K3 e' B/ @# B- D3 _
WSCL = 0;//SCL拉低结束数据传输
- V2 {( c; v4 Gdelay_1us(1);//延时保持" S, K! |* X; R& `' h
}8 a  W/ Y  a6 j) V: u
return dat;//接受八次之后返回dat值! s; n. F# K6 {3 N  d
}$ z2 ~, v8 r1 y% d
3 X# T- ^- z: K$ x& s. c
二、I2C通信流程
, [3 \. _) O  o8 Z: x0 E" U- f& ^主设备向从设备完整的写操作
  R! {% o% l) ?1.主设备发出I2C开始信号:% Q1 @. y% V. `
2.主设备向I2C总线发送要操作的设备地址以及要进行的操作(读/写)7位设备地址+1位读写标识位(0读1写)
" F5 N2 ?8 Q' L4 R# M$ G3.主设备向从设备发送要操作的从设备寄存器地址
3 V* d. F7 |% b* V: L$ e4.主设备向从设备发送要写入的寄存器的数据4 C$ T0 M# V% N/ [* k$ R3 i3 |
5.发起I2C停止信号
# N4 i. [4 R( h0 D: c  t  E; `: @//对I2C设备的完整写操作5 t7 a# D* ?( _& V. F
void Single_WriteI2C(uchar REG_Address,uchar REG_data)
6 d6 T# s; W, S( l" S{
, `; F. N( d% i" ZI2C_Start();
, D1 k& R5 d& G0 P8 GI2C_SendByte(SlaveAddress<<1|0x00);
+ I! Y4 ^0 T7 S( ?" G7 n1 P6 pI2C_RecvACK();5 r1 Y0 B9 b4 E& m3 Q' ?
I2C_SendByte(REG_Address);8 w- R$ S' u- E8 |. C% Z
I2C_RecvACK();
1 D+ z. x9 Z( H! N9 [I2C_SendByte(REG_data);
  u, ?# U% }- g% l) Q- v; sI2C_RecvACK();
5 D$ P( K, S9 V% YI2C_Stop();
  W0 S" P( j5 v; \0 x9 D$ X1 C  n5 U}% b8 {* f, {2 d9 Z" D
处SlaveAddress为设备地址,使用宏定义。8 @" W' U! y3 B3 {; V4 i
主设备接收数据流程如下:- i5 S/ w, Q% y' v" a- g6 L
1.主设备发出I2C开始信号:
# `; M" a8 I5 B; c5 S6 F& ?! q% \2.主设备向I2C总线发送要操作的设备地址以及要进行的操作(读/写)此时,最后一位要为  写操作
9 q* f2 J' L, H% k( ^3.主设备向从设备写入要读取的从设备寄存器的地址8 [1 d( I6 m/ A/ ~9 g
4.主设备向总线发送7位I2C设备地址+1位读操作 标识
# v% {+ W0 f/ k9 g* C5.接收一个字节的数据$ ?8 O( ^6 `3 D5 `% K$ L  z4 B
6.发起I2C停止信号, {, B, m/ j% }, z  ~4 N* c% p% \$ Q

0 h" t. ~8 G: V* P" G  [% ^void Single_ReADI2C(uchar REG_Address,uchar *REG_data,uchar len)
  W+ Q  X; E# V7 J) c{/ V# \) f8 f2 C$ Z) Z
int i;& ]3 \7 ]' E3 n; s
I2C_Start();  L0 E, e; I! h0 P
I2C_SendByte((SlaveAddress<<1)|0x00);- z" S& u! k4 z( S  O/ j; [$ c
I2C_RecvACK();
1 [  H. A' V; J/ A1 }& Q) wI2C_SendByte(REG_Address);% D; I9 P  P2 ?
I2C_RecvACK();. L. J2 U% j  @8 ?& I
I2C_Start();  ~& s% |1 }0 Y' J0 E- E& J7 ?
Delay_Ms(50);/ R/ ^0 `$ }- J
I2C_SendByte((SlaveAddress<<1)|0x01);: U6 N/ q5 f4 \
I2C_RecvACK();
) [2 M( L! K! L1 ?
4 |: ?- p: j6 W% g$ s, Pfor(i=0;i<len;i++)
0 P3 X2 }7 ~7 i' k{
/ s" q( F9 O; X) Y/ EREG_data=I2C_RecvByte();7 @2 s$ ~6 }/ U, d9 N; e
if(i==len-1)# h4 ?. J1 D' p  V& V$ B: {
I2C_SendACK(1);0 ^+ U9 K; C0 ^8 ?
else
; n3 V: \5 s4 n3 qI2C_SendACK(0);: X4 t# k, p5 d  j5 S5 H
}
% {+ v9 @. U; ]4 D) BI2C_Stop();3 j$ Z% N1 y4 a& W2 [

1 W' i5 z" |# q}
& T2 @: i) W8 }& y% A以上就是常见的I2C设备通信的通用函数。) V- U# v- Y4 z0 L
使用单片机的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-8-4 22:04 , Processed in 0.125000 second(s), 26 queries , Gzip On.

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

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

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