当前位置:   article > 正文

IIC基础知识_iic 非应答

iic 非应答

IIC协议基础

1. IIC的物理层

  • 一个IIIC总线使用两条总线线路,一条双向串行数据线,一条串行时钟线,数据线用来接收以及发送数据,时钟线用来同步数据的收发。
  • 每个连接到主机的设备都有一个独立的地址,主机可以通过这个地址对不同的设备进行访问以及操作。也就是说,主机是通过每一个连接在总线上的不同设备的不同地址来对其进行区分。地址可以是7位或者是10位。

2. 物理层的特点

  • 总线通过上拉电阻接到电源,一般为大小为4.7K的电阻,IIC设备空闲时,会输出高阻态,对应之前学习GPIO时的开漏输出,高阻态相当于接了一个很大的电阻,近似于一个断开的状态。IIC中的逻辑1并不是高电平的状态,而是高阻态。接上拉电阻的目的主要是为了防止不同的设备间出现短路的状态。

3. IIC的协议层

  • IIC的协议定义了通讯的起始和停止信号、数据有效性、响应、仲裁、时钟同步以及地址广播等环节。

IIC的基本读写过程

  • 主机写数据到从机:首先发送一个开始信号之后传输从机的地址,然后紧跟着一个读写信号,‘0’代表写,‘1’代表读。发送完这三部分相当于通过总线对地址进行了广播。广播完成后,相应地址的设备接收到主机发来的通讯请求后会向主机发送应答信号,接收到应答信号后,便可以向设备发送相应的数据了,在主机发送完每一个字节后,从机都会向主机发送一个应答信号,主机还还可以继续向设备发送数据;如果由于某些原因,设备不需要再接收数据或出现了其他的问题,设备返回了一个非应答信号,此时主机接收到后便会发送一个停止信号,中断通讯。
  • 主机从设备中读取数据:大致流程与写数据相同,首先广播地址,主要在读写位上会有不同-'1’代表的是读;发送完读写位后,紧跟设备会发送一个应答信号并将数据传输给主机,主机接收完毕第一个字节的数据后,如果还要继续向设备读取数据,主机就要紧接着发送一个应答信号,之后从机便会继续向主机发送数据,在之后的每一字节的数据读取完毕后,若要继续读取都需要发送应答信号,直达主机不需要再继续读设备的数据。若不需要继续读数据,在最后一字节数据后发送一个非应答信号,并发送停止信号即可中断通讯。
  • 通讯复合格式:起始状态基本上是由写方向构成,这一部分一般是存储单元的地址或者传感器的寄存器地址,不同于设备地址,存储器或者传感器的寄存器地址是以传输数据的形式发送出去,也就是先广播设备地址然后将存储器的内部地址或传感器的寄存器地址作为数据发送。然后重复读写过程即可对设备的某一个内部地址进行读写。

通讯的起始以及停止信号:

  • 起始:SCL为高电平,SDA由高电平向低电平切换。
  • 停止:SCL为高电平,SDA由低电平向高电平切换。
    数据的有效性:
  • IIC是通过SDA线来传输数据的,SCL线用来对数据进行同步,SDA数据线在SCL的每个时钟周期传输一位数据。SCL为低电平时SDA数据无效,此时SDA状态发生改变。

地址及数据方向:

  • MSB:从机地址
  • LSB:读写位
  • 在起始信号后可以直接将地址以及读写位组合成一个8位或11位的数据直接发送。

响应:

  • IIC的地址传输以及数据传输都带响应,响应又包括应答信号和非应答信号;在传输时主机产生时钟信号,在第九个时钟周期,数据发送端释放对SDA的控制权,由数据接收端对SDA的状态进行控制,若SDA为高电平,表示的是非应答信号;SDA为低电平,则表示的是应答信号。
  • 在读数据时则是由主机控制应答信号的发送。

4.IIC协议函数表达(STM32)

  • 通过BSRR寄存器和BSR寄存器对端口输出数据寄存器ODR寄存器的某一个位独立设置或清楚,BSRR对应着库函数中的GPIO_SetBits函数而,BSR对应着库函数中的GPIO_ResetBits函数。

  • 通过GPIOB->BSRR=GPIO_Pin_6即可将引脚PB6设置为1的逻辑状态。通过宏定义表示IO口的高低低电平。

  • I2C总线延迟

static void i2c_Delay(void)
{
	uint8_t i;
	for (i = 0; i < 10; i++);//通过具体的工作频率确定具体的时钟周期
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 起始信号
void i2c_Start(void)
{
	EEPROM_I2C_SDA_1();//SDA为高
	EEPROM_I2C_SCL_1();//SCL为高
	i2c_Delay();
	EEPROM_I2C_SDA_0();//当SCL为高电平,SDA由高到低转换表示起始信号。
	i2c_Delay();
	EEPROM_I2C_SCL_0();
	i2c_Delay();
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 结束信号
void i2c_Stop(void)
{
	EEPROM_I2C_SDA_0();//SDA为低
	EEPROM_I2C_SCL_1();//SCL为高
	i2c_Delay();
	EEPROM_I2C_SDA_1();//SDA由低向高转换,SCL为高,表示结束信号
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 向IIC总线设备发送1字节数据
void i2c_SendByte(uint8_t _ucByte)
{
	uint8_t i;
	for (i = 0; i < 8; i++)//0X80代表1000 0000 ,通过下面代码的左移和位与通过SDA总线将数据发送出去
	                       //数据每次与操作,1000 0000 中只有1的与操作有效,通过循环移位将每次与的结果发送
	{		
		if (_ucByte & 0x80)
		{
			EEPROM_I2C_SDA_1();
		}
		else
		{
			EEPROM_I2C_SDA_0();
		}
		i2c_Delay();
		EEPROM_I2C_SCL_1();
		i2c_Delay();	
		EEPROM_I2C_SCL_0();//SCL由1到0,表示SDA数据线状态可能发生改变
		if (i == 7)
		{
			 EEPROM_I2C_SDA_1(); // 释放总线
		}
		_ucByte <<= 1;	/* 左移一个bit */
		i2c_Delay();
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 从IIC总线设备读取一个字节
uint8_t i2c_ReadByte(void)
{
	uint8_t i;
	uint8_t value;
	/* 读到的第一个bit为数据的bit7 */
	value = 0;
	for (i = 0; i < 8; i++)//通过循环对SDA总线的状态进行判断,为1值++;为0移位补0,直到成为一个八位数据        
	                       //二进制中100+1为110,++实现8位数据中1的增加
	{
		value <<= 1;
		EEPROM_I2C_SCL_1();
		i2c_Delay();
		if (EEPROM_I2C_SDA_READ())
		{
			value++;
		}
		EEPROM_I2C_SCL_0();
		i2c_Delay();
	}
	return value;
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 读取器件的应答信号
uint8_t i2c_WaitAck(void)
{
	uint8_t re;

	EEPROM_I2C_SDA_1();	// CPU释放SDA总线,操作BSRR寄存器不仅可以设置IO状态,还可以将其某一位设置为可写入
	i2c_Delay();
	EEPROM_I2C_SCL_1();	/* CPU驱动SCL = 1, 此时器件会返回ACK应答 */
	i2c_Delay();
	if (EEPROM_I2C_SDA_READ())	/* CPU读取SDA口线状态,此时的SDA总线可受外部设备控制 */
	{
		re = 1;//1为有应答
	}
	else
	{
		re = 0;
	}
	EEPROM_I2C_SCL_0();
	i2c_Delay();
	return re;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 主机产生一个应答信号
void i2c_Ack(void)
{
	EEPROM_I2C_SDA_0();	/* CPU驱动SDA = 0 */
	i2c_Delay();
	EEPROM_I2C_SCL_1();	/* CPU产生1个时钟 */
	i2c_Delay();
	EEPROM_I2C_SCL_0();
	i2c_Delay();
	EEPROM_I2C_SDA_1();	/* CPU释放SDA总线 */
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 主机产生一个非应答信号
void i2c_NAck(void)
{
	EEPROM_I2C_SDA_1();	/* CPU驱动SDA = 1 */
	i2c_Delay();
	EEPROM_I2C_SCL_1();	/* CPU产生1个时钟 */
	i2c_Delay();
	EEPROM_I2C_SCL_0();
	i2c_Delay();	
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小蓝xlanll/article/detail/205669
推荐阅读
相关标签
  

闽ICP备14008679号