通信协议之软件模拟IIC通信

        IIC(Inter-Integrated Circuit)通信协议,也被称为I2C,是一种由飞利浦(Philips)公司在20世纪80年代开发的串行通信协议。它主要用于近距离、低速的芯片(如传感器、存储器、显示屏等)之间的通信,通过简化PCB板上的连接和通信需求,提高了系统设计的灵活性和便捷性。

一、IIC通信协议的特点

1.1. 简单性


IIC通信协议仅使用两根信号线:数据线(SDA)和时钟线(SCL),这使得它在硬件电路实现上非常简单,数据线(SDA)和时钟线(SCL)外部接一个4.7K的上拉电阻即可。

1.2. 双向传输


数据线(SDA)用于主设备和从设备之间的双向数据传输。这意味着主设备可以向从设备发送控制指令,并接收从设备返回的数据。

1.3. 多从设备支持


IIC支持多个从设备连接到同一条总线上,每个从设备都有独立的地址。主设备通过发送地址字节来确定要与哪个从设备通信,从而实现了多设备之间的数据交换和控制操作。

1.4. 时钟同步


        通过时钟线(SCL)的协调,主设备和从设备之间的数据传输是同步的。这种同步机制提高了通信的可靠性,并确保了数据的正确传输。

1.5. 强应答机制


        每传输完一个字节的数据,接收端都会发送一个应答信号(ACK或NACK)。ACK表示接收器已经成功地接收了该字节,而NACK则表示接收器接收该字节没有成功。这种应答机制确保了通信过程中能够及时发现并处理错误。

1.6. 通信过程


        IIC通信过程通常包括起始信号、设备地址发送、数据传输和停止信号等步骤。在起始信号产生后,主设备发送从设备的地址和读写标志位(最低位为0表示写操作,为1表示读操作)。从设备在收到地址后发送应答信号以确认通信的建立。然后,主设备和从设备之间开始进行数据传输,每传输完一个字节后都会有一个应答信号。最后,当所有数据传输完成后,主设备发送停止信号以结束通信。

1.7. 数据有效性


        IIC总线进行数据传送时,时钟信号为高电平期间,数据线上的数据必须保持稳定;只有在时钟线上的信号为低电平期间,数据线上的高电平或低电平状态才允许变化。这种机制确保了数据的正确性和稳定性。

1.8. 寻址方式


        IIC设备通常具有一个唯一的7位或10位地址,用于在通信过程中确定目标设备。主设备通过发送包含设备地址和读写标志的字节来寻址从设备。

二、IIC通信协议

如图为IIC通信协议的时序图。可知,数据线SDA具有两种状态,DATA IN 与 DATA OUT两种,分别对应接收数据与发送数据。该时序图可以拆解为以下6个部分。

2.1起始状态与终止状态

起始状态:意为通信的开始。时钟线SCL高电平时读取SDA的状态电平。当SCL为高电平时,SDA从高电平切换为低电平,此时表明,通信已经开始了。

/**
  * 函    数:I2C起始信号
  * 参    数:无
  * 返 回 值:无
  */
void MyI2C_Start(void)
{
	MyI2C_W_SDA(1);
	MyI2C_W_SCL(1);
	MyI2C_W_SDA(0);
	MyI2C_W_SCL(0);
}

终止状态:意为通信的结束,在时钟线SCL为高电平期间,检测到SDA从低电平翻转为高电平。此时表示通信终止。

/**
  * 函    数:I2C终止信号
  * 参    数:无
  * 返 回 值:无
  */
void MyI2C_Stop(void)
{
	MyI2C_W_SDA(0);
	MyI2C_W_SCL(1);
	MyI2C_W_SDA(1);
}

2.2发送数据

        IIC通信协议中,主机可以对从机发送数据,此时DATA处于发送状态。当时钟线为低电平的时候,SDA数据线按照高位先行的顺序,依次将需要发送的数据放到数据线上,当SCL为高电平时,将SDA的数据发给从机。且SCL为高电平的时候,数据线SDA不允许改变数据。按照此步骤操作八次即为发送一个字节。

/**
	* 函    数:I2C发送一个字节
  * 参    数:字节
  * 返 回 值:无
  */
void MyI2C_SendByte(uint8_t Byte)
{
	uint8_t i;
	for (i = 0; i < 8; i++)
	{
		MyI2C_W_SDA(Byte & (0x80 >> i));
		MyI2C_W_SCL(1);
		MyI2C_W_SCL(0);
	}
}

2.3接收数据

        对于IIC通信的接收模式下,为主机读取从机发送的数据。接收一个字节:当时钟线SCL为低电平时,从机通过IIC通信协议将数据传输至数据线SDA上,高位先行。将一个数据上传到SDA数据线上后,释放SCL时钟线(即时钟线SCL置高电平),与发送状态一样,SDA在SCL高电平器件,SDA数据不允许变化.只有当SCL为低电平时,SDA才允许改变数据。先后操作八次,即可接收到一个字节的数据。

/**
  * 函    数:I2C接收字节
  * 参    数:无
  * 返 回 值:无
  */
uint8_t MyI2C_ReceiveByte(void)
{
	
	uint8_t i,Byte = 0x00;
	MyI2C_W_SDA(1);//释放SDA
	for( i = 0; i < 8 ; i++)
	{
			MyI2C_W_SCL(1);//释放SCL
			if (MyI2C_R_SDA()  == 1)
			{
				Byte |= (0x80 >> i);
			}
			MyI2C_W_SCL(0);						//拉低SCL,从机在SCL低电平期间写入SDA
	}
	return Byte;
}

2.4发送应答与接收应答

        由于IIC通信强制应答的的特性,在主机与从机通信的过程中,主机对接收从机发送数据后,主机会对从机进行应答操作。如果SDA数据线在此时为低电平,表明主机对从机应答。如果此时SDA数据线为高电平,则说明未应答。

/**
  * 函    数:I2C发送应答
  * 参    数:返回状态
  * 返 回 值:无
  */
void MyI2C_SendAck(uint8_t AckBit)
{

	MyI2C_W_SDA(AckBit);
	MyI2C_W_SCL(1);
  MyI2C_W_SCL(0);

}

        与发送应答类似,IIC通信的接收应答也是这样。当主机通过SDA线发送了一个字节的数据之后,在下一个时钟接收一位数据,判断从机是否应答。接收到数据0表示应答,接收到数据1表示未应答。

/**
  * 函    数:I2C接收应答
  * 参    数:无
  * 返 回 值:应答值
  */
uint8_t MyI2C_ReceiveAck(void)
{
	
	uint8_t AckBit;
	MyI2C_W_SDA(1);
	MyI2C_W_SCL(1);
	AckBit = MyI2C_R_SDA();
	MyI2C_W_SCL(0);
	return AckBit;
}

三、AT24C02

3.1器件概述

AT24C02的外围电路比较简单,IIC通信部分用两个上拉电阻与VCC相连即可。A0~A2为地址选择位。电路直接将A0~A2接地,即器件地址为1010 0000 (0xA0);

3.2器件读操作

/**
  * @brief  AT24C02读取一个字节
  * @param  WordAddress 要读出字节的地址
  * @retval 读出的数据
  */
unsigned char AT24C02_ReadByte(unsigned char WordAddress)
{
	unsigned char Data;
	MyI2C_Start();
	MyI2C_SendByte(AT24C02_ADDRESS);
	MyI2C_ReceiveAck();
	MyI2C_SendByte(WordAddress);
	MyI2C_ReceiveAck();
	MyI2C_Start();
	MyI2C_SendByte(AT24C02_ADDRESS|0x01);
	MyI2C_ReceiveAck();
	Data=MyI2C_ReceiveByte();
	MyI2C_SendAck(1);
	MyI2C_Stop();
	return Data;
}

/**
  * @brief  AT24C02指定位置读取指定长度的数据
  * @param  *ReadBuffer 读取缓存的数组
	* @param  WordAddress 指定读取数据的位置
	* @param  size 				指定读取数据的大小
  * @retval 返回值1为应答成功,返回值0为应答失败
  */
uint8_t AT24C02_ReadOrderByte(uint8_t *ReadBuffer,uint8_t WordAddress, uint8_t size)
{
	uint8_t i;
	MyI2C_Start();
	MyI2C_SendByte(AT24C02_ADDRESS|I2C_WR);
	MyI2C_ReceiveAck();
	MyI2C_SendByte(WordAddress);
	MyI2C_ReceiveAck();
	MyI2C_Start();
	MyI2C_SendByte(AT24C02_ADDRESS|I2C_RD);
	MyI2C_ReceiveAck();
	for(i=0;i<size;i++)
	{
		ReadBuffer[i] = MyI2C_ReceiveByte();
		MyI2C_SendAck(0);
	}
	MyI2C_Stop();
	if(MyI2C_ReceiveAck()==0)
		return 1;
	else 
		return 0;
}

3.3器件写操作

/**
  * @brief  AT24C02写入一个字节
  * @param  WordAddress 要写入字节的地址
  * @param  Data 要写入的数据
  * @retval 无
  */
void AT24C02_WriteByte(uint8_t WordAddress,uint8_t Data)
{
	MyI2C_Start();
	MyI2C_SendByte(AT24C02_ADDRESS);
	MyI2C_ReceiveAck();
	MyI2C_SendByte(WordAddress);
	MyI2C_ReceiveAck();
	MyI2C_SendByte(Data);
	MyI2C_ReceiveAck();
	MyI2C_Stop();
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值