I2C总线协议详解

一、I2C通信简介

●I2C总线(Inter IC BUS)是由Philips公司开发的一种简单、双向二线制同步串行总线

●主要用于近距离、低速的芯片之间的通信。

●两根通信线:SCL(串行时钟线)SDA(串行数据线)

●带数据应答,即主机每次向从机发送数据后,从机会都会返回给主机一个应答,接收数据同理。

●支持总线挂载多个设备(一主多从、多主多从),而且都可以作为一个发送器或接收器。

●I2C总线是一个真正的多主机总线,如果两个或多个主机同时初始化数据传输,可以通过冲突检测和仲裁防止数据被破坏,每个连接到总线上的器件都有唯一的地址(7bit),任何器件既可以做主机也可以做从机,但同一时刻只允许有一个主机。总线上器件的增加或删除不影响其他器件正常工作。

●连接到相同总线上的IC数量只受最大电容的限制,串行的8位双向数据传输速率在标准模式下可达100Kbit/s,快速模式下可达400Kbit/s,高速模式下可达3.4Kbit/s。

●常用的电子元器件有四针OLED屏、MPU6050模块、AT24C02存储器模块等

二、I2C总线的硬件规定

●所有I2C设备的SCL连在一起,SDA连在一起

●设备在使用I2C总线协议时,在程序中需要将SDA、SCL接口配置成开漏模式

●SCL和SDA各添加一个上拉电阻,阻值一般为4.7KΩ左右

注:在一主多从模式下,对于SCL时钟线,从机在任何时刻都只能被动的读取,从机不允许控制SCL线;对于SDA数据线,从机不允许主动发起对SDA的控制,只有在主机发送读取从机的命令后,或者从机应答时,从机才能短暂的获得SDA的控制权

三、I2C通信过程

        1、主机发送起始信号启用总线

        2、主机发送一个字节数据指明从机地址和后续字节的传送方向

        3、被寻址的从机发送应答信号回应主机

        4、发送器发送一个字节数据

        5、接收器发送应答信号回应发送器

        6、......(循环步骤4、5)

        7、通信完成后主机发送停止信号释放总线

【注:

●在4、5中用的是发送器和接收器,不是主机和从机,这是由于第一个字节的最后一位决定主给从发,还是主发从给。也就是说,第一个字节和最后的停止信号一定是主机发给从机,但中间就不一定了

●发送数据过程中不允许改变发送方向(除非重启一次通信)

四、I2C通信分析

        1、起始信号

                SCL高电平期间,SDA从高电平切换到低电平。

                时序图:

程序:

void I2C_Start(void)
{
    I2C_W_SDA(1);
    I2C_W_SCL(1);
    I2C_W_SDA(0);
    I2C_W_SCL(0);
}

       2、 终止信号

                SCL高电平期间,SDA从低电平切换到高电平。

                时序图:

              

程序:

void I2C_Stop(void)
{
	I2C_W_SDA(0);
	I2C_W_SCL(1);
	I2C_W_SDA(1);
}

注:在一主多从模型内,起始和终止信号都是由主机产生,从机不允许产生起始和终止信号,所以在总线空闲状态时,从机必须始终保持放开状态

        3、发送一个字节:

            SCL低电平期间,主机将数据位依次放到SDA线上(高位先行),然后释放SCL,从机将在SCL高电平期间读取数据位,所以SCL高电平期间SDA不允许有数据变化,依次循环上述过程8次,即可发送一个字节。

                时序图:        

程序:

void I2C_SendByte(uint8_t Byte)//I2C数据发送
{
	uint8_t i;
	for(i=0;i<8;i++)
		{
			I2C_W_SDA(Byte & (0x80 >> i));//每读取一个字节,就向右移一位读取读取次高位
			I2C_W_SCL(1);
			I2C_W_SCL(0);
		}
}

        4、接收一个字节:

                SCL低电平期间,从机将数据位依次放到SDA线上(高位先行),然后释放SCL,主机将在SCL高电平期间读取数据位,所以SCL高电平期间SDA不允许有数据变化,依次循环上述过程8次,即可接收一个字节(主机在接收之前,需要释放SDA【释放SDA相当于切换成输入模式】)

                时序图:

程序:

uint8_t I2C_ReceiveByte(void)
{
	uint8_t i, Byte = 0x00;
	I2C_W_SDA(1);//切换成输入模式
	for(i=0;i<8;i++)
		{
			I2C_W_SCL(1);//SCL电平拉高,主机开始读取数据
			if(I2C_R_SDA()==1){Byte |= (0x80 >>i);}//读取SDA电平状态,若不是高电平,则默认写进0
			I2C_W_SCL(0);
		}
		return Byte;
}

        5、发送应答:

                主机在接收完一个字节后,在下一个时钟发送一位数据,数据0表示应答,数据1表示非应答。

                时序图:

        

程序:

void I2C_SendAck(uint8_t AckBit)
{
	I2C_W_SDA(AckBit);//1:不应答  0:应答
	I2C_W_SCL(1);
	I2C_W_SCL(0);
}

        6、接收应答:

                主机在发送完一个字节后,在下一个时钟接收一位数据,判断从机是否应答,数据0表示应答,数据1表示非应答(主机在接收前,需要释放SDA)。

                 时序图:

程序:

uint8_t I2C_ReceiveAck(void)
{
	uint8_t AckBit;
	I2C_W_SDA(1);//主机释放SDA,防止从机干扰
	I2C_W_SCL(1);//SCL高电平,主机读取应答位
	AckBit = I2C_R_SDA();
	I2C_W_SCL(0);
	
	return AckBit;
}

五、I2C通信应用

        1、I2C指定地址写入数据:

程序:

void Slave_WriteReg(uint8_t RegAddress, uint8_t Data)
{
	I2C_Start();//开启时序
	I2C_SendByte(SLAVE_ADDRESS);//向指定设备发送地址,做主从机联系
	I2C_ReceiveAck();//接收应答
	I2C_SendByte(RegAddress);//指定寄存器地址,将该字节存在指定设备的当前地址指针中,用于指定具体读写哪个寄存器
	I2C_ReceiveAck();//接收应答
	/*【若想写入多个字节,可:
			uint8_t i;
			for(i=0;i<?;i++)
			{
					I2C_SendByte(Data);//写入指定寄存器地址下的数据
					I2C_ReceiveAck();//接收应答
			}
	】
	*/
	I2C_SendByte(Data);//写入指定寄存器地址下的数据
	I2C_ReceiveAck();//接收应答
	I2C_Stop();//终止时序
}

        2、I2C指定地址读取数据:

程序:

uint8_t Slave_ReadReg(uint8_t RegAddress)//对指定的地址进行数据读取
{
		uint8_t Data;
	
		I2C_Start();//开启时序
		I2C_SendByte(SLAVE_ADDRESS);//向指定设备发送地址,做主从机联系
		I2C_ReceiveAck();//接收应答
		I2C_SendByte(RegAddress);//指定寄存器地址,将该字节存在指定设备的当前地址指针中,用于指定具体读写哪个寄存器
		I2C_ReceiveAck();//接收应答
	
		I2C_Start();//再次开启时序
		I2C_SendByte(ALAVE_ADDRESS | 0x01);//开启从机读,将写地址0xD0变为读地址0xD1
		I2C_ReceiveAck();//接收应答
		/*【若想指定地址读入多个字节,可:
			uint8_t i;
			for(i=0;i<?;i++)
			{
					Data = I2C_ReceiveByte();//将接收到的数据存储在变量Data中
					I2C_SendAck(1);//不给从机应答,主机收回主线控制权
			}
			】
			*/
		Data =  I2C_ReceiveByte();//将接收到的数据存储在变量Data中
		I2C_SendAck(1);//不给从机应答,主机收回主线控制权
		I2C_Stop();//终止时序
	
		return Data;
}

  • 16
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值