IIC(Inter-Integrated Circuit)是IIC Bus简称, 它是一种串列通讯总线,使用多主从架构,由飞利浦公司在1980年代为了让主板、嵌入式系统或手机用以连接低速周边设备而发展。

IIC简介:

IIC总线只有2根信号线,一根是数据线SDA,一根是时钟线SCL。SDA和SCL均为双向信号线,通过上拉电阻接正电源。当总线空闲时,两根线都是高电平。连接到总线上的任一器件,输出低电平,都将使总线的信号变低。
连接总线的器件输出级必须是集电极或漏极开路,以形成线“与”功能。
每个具有IIC接口的设备都有一个唯一的地址,也叫做设备地址,通讯时需要进行寻址。

在这里插入图片描述
数据在进行传输时,时钟线SCL为高电平时,数据线SDA上的数据必须稳定,时钟线SCL为低电平时,才允许数据发生改变。
在这里插入图片描述

IIC的启动和停止

在这里插入图片描述
时钟线SCL高电平时,拉低数据线SDA-------------启动
时钟线SCL高电平时,拉高数据线SDA-------------停止

//总线启动条件
void IIC_Start(void)
{
    SDA = 1;
    SCL = 1;
    IIC_Delay(DELAY_TIME);
    SDA = 0;
    IIC_Delay(DELAY_TIME);
    SCL = 0;	
}

//总线停止条件
void IIC_Stop(void)
{
    SDA = 0;
    SCL = 1;
    IIC_Delay(DELAY_TIME);
    SDA = 1;
    IIC_Delay(DELAY_TIME);
}

数据通信

在这里插入图片描述
启动总线后,必须发送设备地址,其中高4位是器件的类型识别符(EEPROM的识别符为1010),接着3位是片选信号,最后1位是读写控制位,读操作为1,写操作为0。

第9位是应答信号位,以确定数据传送是否被对方收到。应答信号由接收方在数据开始后的第9个时钟周期发送,在SCL为高电平期间,接收方将SDA拉为低电平产生应答,用来结束一个字节的传输。也就是说,一帧完整的数据共有9位。
等待应答信号的代码:

//等待应答
bit IIC_WaitAck(void)
{
    bit ackbit;
	
	SDA  = 1;				//新加,释放数据总线
	IIC_Delay(DELAY_TIME);
    SCL  = 1;
    IIC_Delay(DELAY_TIME);
    ackbit = SDA;
	if(ackbit)				//新加,若无应答,则停止总线
		IIC_Stop();
    SCL = 0;
    IIC_Delay(DELAY_TIME);
	
    return ackbit;
}

注意:当主机接收数据(也就是在读数据状态)时,它收到最后一个字节后,必须向从机发出一个结束传送的信号。这个信号是通过对从机的“非应答信号”来实现的,在SCL为高电平期间,SDA为高电平,即从机释放SDA线,允许主机产生一个停止信号。
主动发送应答的代码实现:

//主机发送应答
void IIC_SendAck(bit ackbit)
{
    SCL = 0;
    SDA = ackbit;  					// 0:应答,1:非应答
    IIC_Delay(DELAY_TIME);
    SCL = 1;
    IIC_Delay(DELAY_TIME);
    SCL = 0; 
    SDA = 1;
    IIC_Delay(DELAY_TIME);
}

发送数据

在这里插入图片描述
操作时序:总线开始-----发送地址+写(0)-----从机应答------发送数据------从机应答……
发送一个字节数据的代码实现:

//通过I2C总线发送数据
void IIC_SendByte(unsigned char byt)
{
    unsigned char i;

    for(i=0; i<8; i++)
    {
        SCL  = 0;
        IIC_Delay(DELAY_TIME);
        if(byt & 0x80) 
        	SDA  = 1;
        else 
        	SDA  = 0;
        IIC_Delay(DELAY_TIME);
        SCL = 1;
        byt <<= 1;				//从最高位开始传输数据
        IIC_Delay(DELAY_TIME);
    }
    SCL  = 0;  
}

接受数据

在这里插入图片描述
操作时序:总线开始-----发送地址+读(1)-----从机应答------接受数据------主机发送应答……
接受一个字节数据的代码实现:

//从I2C总线上接收数据
unsigned char IIC_RecByte(void)
{
    unsigned char i, da;
    for(i=0; i<8; i++)
    {   
    	SCL = 1;
		IIC_Delay(DELAY_TIME);
		da <<= 1;					//从高位开始接受数据
		if(SDA) 
			da |= 1;
		SCL = 0;
		IIC_Delay(DELAY_TIME);
    }
    return da;    
}

Reference
https://blog.csdn.net/ohy3686/article/details/86716456