这两天研究I2C总线,用51单片机,遇到了困难,被应答信号给卡住了,不过总算是解决了。
在这发个学习总结。有不对的,希望高手指点。
(原文件名:6.jpg)
上图为应答信号时序图
在单片机系统中,单片机和24c02是互为发送端和接收端的。
首先关于发送端和接收端的定义得明确一下:
发送端:往I2C总线上送数据的设备
接收端:从I2C总线上获取数据的设备
时序图上,能看出来,发送端在发送数据后,要在SCL第9个脉冲来临前把SDA拉高,以等待接收端发来ACK信号,接收端在接收到数据后,会向发送端发出ACK信号,也就是图上标的ACKNOWLEDGE
1、当单片机向2402写数据的时候,会向I2C总线发送数据,这时单片机作为发送端。
2、24c02作为接收端。反过来,读取24c02的数据时,单片机就成了接收端,2402成了发送端。
一、单片机作为发送端时,当它发送完一字节的数据后,
需要执行的语句是:
/**************************************
接收应答信号(写数据时)
检测24c02,是否产生应答信号,
若24c02,接收完一字节数据,则产生应答信号。告诉单片机已接收到数据。
若24c02,没接收到一字节数据,则产生非应答信号。告诉单片机没接收到完整的数据。此时可根据程序重复发送。
**************************************/
void recv_ack()
{
uchar i; //声明i变量,不应答时延时
sda=1
delay(); //释放SDA,等待24c02发送ACK应答信号
while((sda==1)&&(i<250))i++;// 一、若24c02发送ACK应答信号,即SDA=0,时序图的ACKNOWLEDGE信号
二、若24c02没发送ACK应答信号,即SDA=1,时序图的NOT ACKNOWLEDGE信号,则延时到I>250,默认已应答。
scl=1;
delay();
scl=0;
delay(); //确认接收到应答信号SCL=H>L
}
二、当单片机作为接收端时,如果接收多个数据,那么,在每接收完一字节的数据后,
都要执行以下语句:
/**************************************
发送应答信号(读数据时)
产生应答信号即已读完一字节
入口参数:ack (0:ACK 1:NAK)
**************************************/
void send_ack(bit ack) //发送DATE后,接收端SDA=L,后发送端SCL=H>L
{
sda=ack; //ack=0应答ack=1不应答,
即向24c02发送ACK应答信号,说明已接收到8位数据,使24C02地址自己加1
scl=1;
delay();
scl=0;
delay(); //产生应答信号SCL=H>L delay()>=4.7us
}
如果只接受一个字节的数据,那么就不发送ACK,这个时候,
要发送非应答信号即SDA=1,时序图的NOT ACKNOWLEDGE信号
就要把SDA置高,即执行语句:SDA=1
把ACK置1,后产生STOP信号,告诉24C02单片机停止接收数据,不用再发送了……
应答信号总结ourdev_715457OP12II.doc(文件大小:51K) (原文件名:I2C总线学习应答信号总结.doc)
|