IIC通讯时序详解(上)
本文作者: 阳光,e小白网址:www.e-xiaobai.com
在刚开始接触单片机的时候,会被板级内的各种通讯接口方式弄的晕头转向。嵌入式系统中常用板级通讯方式有:并口(8位、16位)、SPI(4线、3线)、IIC、USB、TYPE-C等。具体采用什么通讯方式,要根据实际项目情况选择。并口传输速度快,处理数据量大,像处理图形图像优先考虑,硬件成本高;串口传输速度相对比较慢,接线简单,硬件成本低。这里详细介绍下IIC通讯方式的使用。
一、IIC 简介
IIC(Inter-Integrated Circuit)总线是由NXP(原PHILIPS)公司开发的两线式串行总线,用于连接单片机及其外围设备。多用于主控制器和从器件间的主从通信,适用数据量少,传输距离短场合。在 MCU 与被控 IC 之间、IC 与 IC 之间进行二线制、双向、同步半双工传输。IIC传输速度分为标准100Kbps、快速400Kbps、高速3.4Mbps,目前大多数器件都支持快速传输。IIC总线的传输距离受到布线、速度、总线电容的影响,虽然没有明确规定距离,但是建议不要超过300mm,否则最好加上IIC中继芯片。
二、IIC物理层接线

从上图可以看出,在IIC物理层有主机(MCU)、从机(IIC器件);2条总线,SCL(时钟线)和SDA(数据线)及上拉电阻(必接4.7K-10K)。
所有接到I2C总线设备上的串行数据SDA都必须接到总线的SDA上,各设备的时钟线SCL接到总线的SCL上。I2C总线上的每个设备都自己一个唯一的地址,来确保不同设备之间访问的准确性。器件的物理地址是器件厂商出厂设定好的,须按照IC手册设定。
在IIC总线中可以接多个主机,其中任何一个能够进行发送和接收的设备都可以成为主总线。一个主机能够控制信号的传输和时钟频率。当然,在任何时间点上只能有一个主机控制。
---------------------------------------------------------------------------------------------------------------
三、IIC协议层
IIC 总线在传送数据过程中共有三种类型信号, 它们分别是:启始信号(Start)、终止信号(Stop)和应答信号(Ack)。
启始信号:SCL 为高电平时(1),SDA 由高电平向低电平跳变,表示起始信号,接下来可以进行数据传输,必须有;
终止信号:SCL 为高电平时(1),SDA 由低电平向高电平跳变,表示终止信号,表示结束数据传输,必须有;
应答信号:接收端器件(不论主从)在接收到 8bit 数据后,向发送端器件(不论主从)发出特定的低电平脉冲,表示已收到数据。发送端向接收端发出一个信号后,等待接收端发出一个应答信号,发送端接收到应答信号后,根据实际情况作出是否继续传递数据的判断。若在约定的等待周期内未收到应答信号,判断为接收端接收数据不成功。
非应答信号:若接收端希望结束数据传输,则可以向发送端发一个“非应答信号NAck”,接收端收到此信号后会产生一个终止信号,结束传输。
IIC 总线时序图

启始信号:SCL高电平(1)状态下,SDA由高(1)变低(0),保持至少4.7us后,产生启始信号;程序表示如下
void IIC_Start()
{
SDA=1; //确保SDA线为高电平
SCL=1; //确保SCL高电平
delay_us(5); //保持5us
SDA=0; //在SCL为高时拉低SDA,产生启始信号
delay_us(5);
}
终止信号:SCL高电平(1)状态下,SDA由高(0)变低(1),保持至少4.7us后,产生终止信号;程序表示如下
void IIC_Stop()
{
SDA=0; //确保SDA线为低电平
SCL=1; //确保SCL高电平
delay_us(5);
SDA=1; //在SCL为高时拉高SDA线,产生终止信号
delay_us(5);
}
应答信号:主机SCL拉高,读取从机SDA的电平,为低电平(SDA=0)表示产生应答,为有效应答位(ACK,简称应答位),表示接收器已经成功地接收了该字节,可以继续发送;若为高电平(SDA=1)时,为非应答位(NACK),一般表示接收器接收该字节没有成功,结束发送。如下图

每发送一个字节(8个bit)后,在一个字节传输的8个时钟后的第九个时钟期间,接收器接收数据后必须回一个ACK应答信号给发送器,这样才能进行数据传输。程序表示如下:
//主机产生应答信号Ack
void IIC_Ack(void)
{
SCL=0; //先拉低SCL,使得SDA数据可以发生改变
SDA=0; //SAD=0,产生应答信号
delay_us(2);
SCL=1;
delay_us(5);
SCL=0; //一个SCL时钟等待周期
delay_us(5);
SDA=1; //释放SDA总线控制权
}
有时候从机因某种原因不需要对主机应答时,须将SDA置为高电平(1),由主机产生终止信号结束数据传输。程序表示如下:
//主机产生非应答信号NAck
void IIC_NAck(void)
{
SCL=0; //先拉低SCL,使得SDA数据可以发生改变
SDA=1; //SAD=1,产生非应答信号
delay_us(2);
SCL=1;
delay_us(5);
SCL=0;
delay_us(5);
}
在实际写程序时,我们可以用一个等待应答子程序来判断应答信号,程序如下:
等待接收端的应答信号:应答0,非应答1
u8 IIC_WaitAck (void)
{
u8 temptime; //临时计时器
SDA=1; // 释放SDA线的控制权
SCL=1;
delay_us(5);
if(SDA_READ==1) // 如果读回的SDA=1,则为非应答
{
temptime++;
if(temp>250) //超时,这里250大概数参考
{
IIC_Stop(); //停止传输
return 1;
}
}
SCL=0; // SCL拉低
delay_us(5);
return 0; //如果读回的SDA=0,则为应答
}