IIC协议层
IIC 总线在传送数据过程中共有三种类型信号, 它们分别是:启始信号(Start)、终止信号(Stop)和应答信号(Ack)。 启始信号:SCL 为高电平时(1),SDA 由高电平向低电平跳变,表示起始信号,接下来可以进行数据传输,必须有; 终止信号:SCL 为高电平时(1),SDA 由低电平向高电平跳变,表示终止信号,表示结束数据传输,必须有; 应答信号:接收端器件(不论主从)在接收到 8bit 数据后,向发送端器件(不论主从)发出特定的低电平脉冲,表示已收到数据。发送端向接收端发出一个信号后,等待接收端发出一个应答信号,发送端接收到应答信号后,根据实际情况作出是否继续传递数据的判断。若在约定的等待周期内未收到应答信号,判断为接收端接收数据不成功。 非应答信号:若接收端希望结束数据传输,则可以向发送端发一个“非应答信号NAck”,接收端收到此信号后会产生一个终止信号,结束传输。
启始信号:SCL高电平(1)状态下,SDA由高(1)变低(0),保持至少4.7us后,产生启始信号;程序表示如下
void IIC_Start()
{
SDA=1;
SCL=1;
delay_us(5);
SDA=0;
delay_us(5);
}
终止信号:SCL高电平(1)状态下,SDA由高(0)变低(1),保持至少4.7us后,产生终止信号;程序表示如下
void IIC_Stop()
{
SDA=0;
SCL=1;
delay_us(5);
SDA=1;
delay_us(5);
}
应答信号:主机SCL拉高,读取从机SDA的电平,为低电平(SDA=0)表示产生应答,为有效应答位(ACK,简称应答位),表示接收器已经成功地接收了该字节,可以继续发送;若为高电平(SDA=1)时,为非应答位(NACK),一般表示接收器接收该字节没有成功,结束发送。如下图 每发送一个字节(8个bit)后,在一个字节传输的8个时钟后的第九个时钟期间,接收器接收数据后必须回一个ACK应答信号给发送器,这样才能进行数据传输。程序表示如下: //主机产生应答信号Ack
void IIC_Ack(void)
{
SCL=0;
SDA=0;
delay_us(2);
SCL=1;
delay_us(5);
SCL=0;
delay_us(5);
SDA=1;
}
有时候从机因某种原因不需要对主机应答时,须将SDA置为高电平(1),由主机产生终止信号结束数据传输。程序表示如下:
//主机产生非应答信号NAck
void IIC_NAck(void)
{
SCL=0;
SDA=1;
delay_us(2);
SCL=1;
delay_us(5);
SCL=0;
delay_us(5);
}
在实际写程序时,我们可以用一个等待应答子程序来判断应答信号,程序如下:
等待接收端的应答信号:应答0,非应答1
u8 IIC_WaitAck (void)
{
u8 temptime;
SDA=1;
SCL=1;
delay_us(5);
if(SDA_READ==1)
{
temptime++;
if(temp>250)
{
IIC_Stop();
return 1;
}
}
SCL=0;
delay_us(5);
return 0;
}
四、IIC数据有效性规定和传输格式
IIC信号在数据传输过程中,当SCL=1高电平时,数据线SDA必须保持稳定状态,不允许有电平跳变,只有在时钟线上的信号为低电平期间(SCL=0),数据线上的高电平或低电平状态才允许变化。简而言之,SCL=1时, 数据线SDA的任何电平变换会看做是总线的起始信号或者停止信号,只有SCL=0时,才允许SDA数据进行电平转换。如下图所示
在IIC数据传输过程中,输出到SDA线上的每个字节必须是8位,数据传送时,高位(MSB)在前,低位(LSB)在后,每次发送的字节数量不受限制,但是每一个被传送的字节后面都必须跟随一位应答位(即一帧共有9位)。当一个字节按数据位从高位到低位的顺序传输完后,紧接着从设备将拉低SDA=0,回传给主设备一个应答位ACK, 此时才认为一个字节真正的被传输完成 ;如果一段时间内没有收到从机的应答信号(SDA=1),则认为该数据接收不成功。如下图
主机写数据过程如下: 1.主机首先产生START信号; 2.然后紧跟着发送一个从机地址,这个地址共有7位,紧接着的第8位是数据方向位(R/W), 0表示主机发送数据(写),1表示主机接收数据(读); 3.主机发送地址时,总线上的每个从机都将这7位地址码与自己的地址进行比较,若相同,则认为自己正在被主机寻址,将自己确定为发送器和接收器; 4.这时候主机等待从机的应答信号(A) 4.1当主机收到应答信号时,发送要访问从机的那个地址, 继续等待从机的应答信号; 4.2当主机收到应答信号时,发送N个字节的数据,继续等待从机的N次应答信号; 4.3主机产生停止信号,结束传送过程。
主机发送数据程序表示如下: //写入一个字节
void Send_Byte(u8 dat)
{
u8 i;
SCL=0;
for(i=0;i<8;i++)
{
if(dat&0x80)
{
SDA=1;
}
else
{
SDA=0;
}
delay_us(5);
SCL=1;
delay_us(5);
SCL=0;
delay_us(5);
dat<<=1;
}
}
IIC主机发送一个字节程顺序如下(以AT24C02为例)
void IIC_ WR_Byte(u8 dat,u8 mode)
{
IIC_Start();
Send_Byte(0xA0);
IIC_WaitAck();
Send_Byte(address);
Send_Byte(dat);
delay_us(2);
IIC_WaitAck();
IIC_Stop();
}
主机读(接收)数据过程如下: 1.主机首先产生START信号; 2.然后紧跟着发送一个从机地址,注意此时该地址的第8位为RW=0,表明是向从机写命令; 3.这时候主机等待从机的应答信号(ACK); 4.当主机收到应答信号后,发送要访问的从机地址,继续等待从机的应答信号; 5.当主机收到应答信号后,主机要改变通信模式(主机由发送变为接收,从机由接收变为发送); 5.1主机重新发送一个开始start信号; 5.2然后紧跟着发送一个从机地址,注意此时该地址的第8位为RW=1,表明将主机设置成接收模式开始读取数据; 5.3主机等待从机的应答信号,当主机收到应答信号时,就可以接收1个字节的数据,当接收完成后,主机发送非应答信号,表示不在接收数据; 6.主机进而产生停止信号,结束传送过程。程序表示如下:
//IIC主机接收一个字节
void IIC_Read_Byte(u8 ack)
{
u8 i=0,receive=0;
IIC_SDA_IN();
for(i=0;i<8;i++)
{
SCL=0; delay_us(2);
SCL=1; delay_us(2);
receive<<=1;
if(Read_Sda==1) receive++;
delay_us(2);
}
if(!ack) IIC_NAck();
else IIC_Ack();
return receive;
}
}
以读取EEPROM AT24C02为例,读取程序如下(仅参考):
u8 IIC_READ_AT24C02(u16 addr)
{
u8 temp=0;
IIC_Start();
Send_Byte(0xA0);
IIC_WaitAck();
Send_Byte(data);
IIC_WaitAck();
IIC_Start();
Send_Byte(0xA1);
IIC_WaitAck();
temp= IIC_Read_Byte(0);
IIC_Stop();
return temp;
}
作者:e小白官方 https://www.bilibili.com/read/cv16110897?spm_id_from=333.999.0.0 出处:bilibili
|