I2C总线简介
1. I2C总线是Philips公司提出的串行总线,但现在实际上已成为一个国际标准,在超过100种不同的IC上实现并得到超过50家公司的许可。它只用两根总线(时钟线SCL和数据线SDA)实现了多主的总线连接。它有3种模式:标准模式(100Kbits/s),快速模式(400Kbits/s)和高速模式(3.4Mbits/s),寻址方式有7位和10位方式。
2. SCL和SDA都是双向线路,都通过一个上拉电阻连接到正的电源电压,当总线空闲时这两条线路都是高电平。
3. 完整的I2C数据传输如下:
它包括起始条件、地址传送、数据传送、响应位、停止条件组成。起始条件是指在SCL线是高电平时,SDA从高电平向低电平切换。停止条件是指当SCL是高电平时,SDA从电平向高电平切换。接下来的一个字节包含7位地址和一位读/写控制位。接下来是主发到从或从发到主的数据,紧跟着的是响应位,由接收数据的设备发出。最后是停止位表示数据传输的完成。整个过程中传输的1或0是在SCL为高时SDA的电平决定的。而SDA线的高或低电平状态只有在SCL为低电平时才能改变。
4. 三种典型的数据传输模式。
A. 主机只发送数据给从机指定地址。
B. 主机寻址从机,只从从机读取数据。
C. 以上两种的复合模式,即主机既想向从机写数据又需要从机反馈数据。
/********************************************************************/
void StartIIC() /*发送IIC总线启动时序*/
{
SCL=1;
IICClockDelay();
SDA=1;
IICClockDelay();
SDA=0;
IICClockDelay();
SCL=0;//在scl=0时可以改变sda状态
IICClockDelay();
}
/********************************************************************/
void StopIIC() /*发送IIC总线停止时序*/
{
SDA=0;
IICClockDelay();
SCL=1;
IICClockDelay();
SDA=1;
IICClockDelay();
SCL=1;
IICClockDelay();
}
/********************************************************************/
/********************************************************************/
void IICClockDelay() /*IIC总线时钟电平延时*/
{
nop;nop;nop;nop;nop;nop;
}
/********************************************************************/
void IICAck(bit ackValue) /*应答/不应答函数,注意看谁对谁*/
{
if(ackValue==0)
SDA=0;
else
SDA=1;
IICClockDelay();
SCL=1;
IICClockDelay();
SCL=0;
IICClockDelay();
}
/********************************************************************/
bit IICSendByte(uchar byteData) /*向24C02发送一个字节数据或地址函数*/
{ /*返回值为发送成功与否标志*/
bit ackFlag;
for(i=0;i<8;i++) /*要传送的数据长度为8位*/
{
if((byteData<<i)&0x80) /*依次判断待发送位高低*/
SDA=1;
else
SDA=0;
IICClockDelay();
SCL=1; /*置时钟线为高,通知24C02开始接收数据位*/
IICClockDelay();
SCL=0;
IICClockDelay();
}
SDA=1; /*8位数据发送完后释放数据线,准备接收应答位*/
IICClockDelay();
SCL=1;
IICClockDelay();
if(SDA==1)
ackFlag=0; /*24c02无应答*/
else
ackFlag=1; /*数据成功发送*/
SCL=0;
IICClockDelay();
return(ackFlag); /*返回24C02应答标志*/
}
/********************************************************************/
uchar IICRcvByte() /*从24C02读一个字节数据函数, 返回值为读入的该字节*/
{
uchar retbyteData=0x00; /*置返回值初值为0x00*/
for(i=0;i<8;i++)
{
SDA=1;
IICClockDelay();
SCL=1; /*拉高时钟线后读取数据线电平*/
IICClockDelay();
retbyteData=retbyteData<<1; /*返回值依次左移一位*/
if(SDA==1) /*读取数据线电平至于返回值空出的一位*/
{
retbyteData+=1;
}
SCL=0; /*拉低释放时钟线*/
IICClockDelay();
}
return(retbyteData);
}
/********************************************************************/
/*向24C02的指定地址写入若干个数据函数*/
bit IICWrite(uchar slaveAddress,uchar subAddress,uchar *dataPointer,uchar num)
{
bit retBit;
StartIIC(); /*启动总线*/
retBit=IICSendByte(slaveAddress); /*发送器件地址*/
if(retBit==0)
return(0);
retBit=IICSendByte(subAddress); /*发送器件子地址*/
if(retBit==0)
return(0);
for(i=0;i<num;i++)
{
retBit=IICSendByte(*(dataPointer+i)); /*发送数据*/
if(retBit==0)
return(0);
}
StopIIC(); /*结束总线*/
return(0);
}
/********************************************************************/
/*从24C02的指定地址读入若干个数据函数*/
bit IICRead(uchar slaveAddress,uchar subAddress,uchar *dataPointer,uchar num)
{
bit retBit;
StartIIC(); /*启动总线*/
retBit=IICSendByte(slaveAddress); /*发送器件从地址*/
if(retBit==0)
return(0);
retBit=IICSendByte(subAddress); /*发送器件子地址*/
if(retBit==0)
return(0);
StopIIC(); /*结束总线*/
StartIIC(); /*重新启动总线*/
retBit=IICSendByte(slaveAddress+1);
if(retBit==0)
return(0);
for(i=0;i<num-1;i++)
{
*dataPointer=IICRcvByte(); /*接收数据*/
IICAck(0); /*发送应答位,mcu对24c02的应答*/
dataPointer++;
}
*dataPointer=IICRcvByte(); /*接收数据*/
IICAck(1);//非应答,结束读操作的要求
StopIIC(); /*结束总线*/
return(1);
}
/********************************************************************/