IIC通讯时序详解(下)
本文作者:阳光,e小白网址:www.e-xiaobai.com
四、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) //将dat的8位从最高位依次写入
{
SDA=1; //传送1
}
else
{
SDA=0; //传送0
}
delay_us(5); //这里延时可选2-10us,根据实际情况确定,不要省略
SCL=1; //SCL=1,保持SDA不变
delay_us(5);
SCL=0; //SCL=0,允许SDA跳变
delay_us(5); //表示一个SCL时钟周期传送1位数据
dat<<=1; //下一位数据
}
}
IIC主机发送一个字节程顺序如下(以AT24C02为例)
void IIC_ WR_Byte(u8 dat,u8 mode)
{
IIC_Start(); //启动信号
Send_Byte(0xA0); //RW=0表示主机写入,发送从机地址要根据实际器件确定
IIC_WaitAck(); //等待应答
Send_Byte(address); //发送要写入的字节地址(此处与0XA0不同)
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(); //SDA设为输入
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); //发送地址,D0=0表示写入
IIC_WaitAck(); //等待应答
Send_Byte(data); //发送数据(24C02数据低位地址)
IIC_WaitAck();
IIC_Start(); //再次发启始信号
Send_Byte(0xA1); //发送地址,D0=1表示读入数据,与上面相反
IIC_WaitAck();
temp= IIC_Read_Byte(0); //应答
IIC_Stop(); //结束
return temp;
}
------------------------------------------------------------------------------------------------------------
五、IIC寻址
前面有说到,启始信号后必跟从机地址,那么从机地址如何确定?在IIC总线上,每个器件都有自己固定的地址,这地址是IC在出厂时就已经设定好的,使用者只能按照手册进行配置。还是以AT24C02为例说明。AT24C02为地址低位D3-D1,可以设为000-111共8个不同地址 ,高4位D7-D4=1010这是厂商固定地址,不能改变;D0位是读写控制位,0表示写,1表示读。如果硬件电路A0-A2这3个脚接地(000),按照前面数据格式规定,那么向AR24C02写入时,发送的地址码为A0(10100000),如果要读回数据则发送的地址码为A1(10100001)。
还有些IC有发送命令和数据之分,因此在发送地址码后,还要发送控制字标识(D/C)位(通常0表示命令,1表示数据),总之从器件地址和控制字标识要按IC手册设定,否则会出现通讯错误。
六、其它
IIC协议理论上可以接127个从机(8位地址去掉一个广播位和0x00地址),实际上还受到总线电容的限制,IIC总线电容不能超过400pf,电容增大会导致数据和时钟信号的跳变产生延时畸变,导致通讯不能正常进行。在实际运用中,发送数据后的延时(2-10us)要保留,有时会出现程序都没变,换个场合就异常的情况,这时要重点注意延时是否合适。上拉电阻一定要加上,虽然有时候没有加也能正常运行,但是你不知道什么时候就不正常了。示例是用模拟IIC时序,STM32F103X支持硬件IIC,应用起来比较简单,速度也比模拟的要快,只是IO口就没有模拟的那么灵活,看情况而定。