关于IIC的那些事

IIC简介

IIC由飞利浦公司开发的,有引脚少,硬件实现简单,扩展性强的特点,不需要有特殊的外部收发设备,目前也被广泛的应用于集成电路之间的通讯。IIC多应用于小数据场合,传输的距离短,在任意时刻只能有一个主机,主要适用于低速设备通信,其传输速率是比不上SPI的。

主要有以下特点:

两根通信线SCL(Serial Clock)、SDA(Serial Data)。

属于同步、半双工的通信。

支持总线挂载多设备(一主多从、多主多从)

带数据应答

从设备都挂载在SCL、SDA的总线上,因此IIC可以支持多个通讯主机及多个通讯从机。在IIC中是有地址的,每一个设备都有一个独立的地址,主机可以利用这个地址对不同的设备进行访问。

在物理层中可以见到,当IIC的设备空闲的时候,输出的为高阻态,这样做是为了避免总线冲突。可以这样理解,SDA线上有个弹簧,当他们要说话的时候,把线拉下来说话,不说话的时候,放开线SDA弹上去为电源电平,表示总线是空闲的。也就是说只要有人在说话,就需要拉下那根线,拉下后其他人也就不能说话了,这只是自己的一些理解。

因此在这里的GPIO输出要设置成为开漏输出的模式,具备线与的特性,当有很多个开漏模式连接在一起的时候,只有所有的引脚都输出高阻态,其上拉电阻才提供高电平。

对于IIC的高阻态

 漏极开路即高阻态,适用于输入/输出,其可独立输入/输出低电平和高阻状态,若需要产生高电平,需要使用外部上拉电阻,以下是其他作者的介绍:

高阻状态:高阻状态是三态门电路的一种状态。逻辑门的输出除有高、低电平两种状态外,还有第三种状态——高阻状态的门电路。电路分析时高阻态可做开路理解。

我们知道IIC的所有设备是接在一根总线上的,那么我们进行通信的时候往往只是几个设备进行通信,那么这时候其余的空闲设备可能会受到总线干扰,或者干扰到总线,怎么办呢?

为了避免总线信号的混乱,IIC的空闲状态只能有外部上拉, 而此时空闲设备被拉到了高阻态,也就是相当于断路, 整个IIC总线只有开启了的设备才会正常进行通信,而不会干扰到其他设备

IIC的各个组成

IIC的通讯基本有三种,主机写数据到从机、主机由从机里读数据、IIC的复合格式。在程序的设计当中我们应该是先对各个部分进行实现,然后根据这三种模式的需要进行拼凑即可(这里是 指的软件模拟IIC)。

要完成软件模拟IIC,那么我们对其SCL、SDA应进行封装,函数如下,并且应加入一段时间的演示,是由于开漏输出的模式下,电平转换的时间是较慢的。所有应加入一段延时。

void MyI2C_W_SCL(uint8_t BitValue)
{
	GPIO_WriteBit(GPIOB, GPIO_Pin_10, (BitAction)BitValue);
	Delay_us(10);
}

void MyI2C_W_SDA(uint8_t BitValue)
{
	GPIO_WriteBit(GPIOB, GPIO_Pin_11, (BitAction)BitValue);
	Delay_us(10);
}

uint8_t MyI2C_R_SDA(void)
{
	uint8_t BitValue;
	BitValue = GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_11);
	Delay_us(10);
	return BitValue;
}

在起始信号和停止信号中,起始信号是SCL在高电平期间,SDA由高电平变化成为低电平,停止信号也是SCL在高电平情况下,SDA由低电平变化为高电平。起始信号和停止信号非常的有特点。

起始信号和停止信号都是在时钟线在高电平期间,SDA发生电平变化,恰好区别于在数据传输的过程中,SCL处于高电平时,SDA电平不能发送变化的特点。

 


void MyI2C_Start(void)
{
	MyI2C_W_SDA(1);
	MyI2C_W_SCL(1);
	MyI2C_W_SDA(0);
	MyI2C_W_SCL(0);
}

void MyI2C_Stop(void)
{
	MyI2C_W_SDA(0);
	MyI2C_W_SCL(1);
	MyI2C_W_SDA(1);
}

在数据传输的过程中,SCL在高电平情况下,SDA是不允许发送变化的,此时是读取SDA的电平。在SCL低电平情况下,SDA发送电平变化。也就是说在SCL电平为1的时候,数据线上SDA的任何电平变化都会看作为总线的起始信号或者停止信号。

 

应答信号

接收应答:每当主机向从机发送完一个字节的数据,主机总是要等到从机给出一个应答的信号,来确认从机是否成功的接收到了数据,数据0表示应答,数据1表示非应答,在主机接收前需要释放SDA,也就是主机SCL拉高,读取从机的SDA电平,为低电平的时候为应答。

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

void MyIIC_SendAck(uint8_t AckBit) //1是非应答 0是应答
{
	MyIIC_W_SDA(AckBit);
	MyIIC_W_SCL(1);
	MyIIC_W_SCL(0);
}



/*!
 *  @brief主机在发送完一个字节之后,在下一个时钟接收一位数据
          判断从机是否应答  主机在接收前要释放SDA  0表示应答 1 表示非应答   
 *  @param   
 *  @param    
 *  @param     
 *  @since   
 *  Sample usage:   
 */

uint8_t MyIIC_ReceiveAck(void)
{
	uint8_t AckBit;
	MyIIC_W_SDA(1);
	MyIIC_W_SCL(1);
	AckBit = MyIIC_R_SDA();
	MyIIC_W_SCL(0);
	return AckBit;
}

IIC的数据传送

SDA线上的数据在SCL时钟“高”期间必须是稳定的,只有当SCL线上的时钟信号为低时,数据线上的“高”或“低”状态才可以改变。输出到SDA线上的每个字节必须是8位,数据传送时,先传送最高位(MSB),每一个被传送的字节后面都必须跟随一位应答位(即一帧共有9位)

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);
	}
}

uint8_t MyI2C_ReceiveByte(void)
{
	uint8_t i, Byte = 0x00;
	MyI2C_W_SDA(1);
	for (i = 0; i < 8; i ++)
	{
		MyI2C_W_SCL(1);
		if (MyI2C_R_SDA() == 1){Byte |= (0x80 >> i);}
		MyI2C_W_SCL(0);
	}
	return Byte;
}

 多数从设备的地址为7位或者10位,一般都用七位,八位的设备地址=7位从机地址+读/写位

0表示主设备向从设备写数据

1表示主设备向从设备读数据

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值