IIC,inter ic bus,两线制串行总线标准,由一根串行数据线SDA和一根串行时钟线SCL组成,可以在一条总线上连接多个外设,主机通过器件地址识别从机。
发送数据之前,需要有一个启动信号start,
IIC总线上的主机在启动信号之后发送一个或多个字节的数据,字节的高位在前,低位在后。
主机每发送完一个字节(包括地址数据和普通数据)就要等待从机返回一个应答信号。
应答信号是在从机接收到主机发送的一个字节后在下一次时钟到来时,SDA信号线上给出一个低电平。主机必须等待从机回应一个应答信号,如果没有收到应答信号,则主机必须发送停止信号或者再次重新启动。
发送完一字节数据,主机如果还想继续发送数据,则可以继续发送数据。如果想向其他器件发送数据,则可以再次发送地址,其后通讯流程同上。
数据传输信号 数据传输:SCL为高电平时,SDA线若保持稳定,那么SDA上是在传输数据bit; 若SDA发生跳变,则用来表示一个会话的开始或结束(后面讲) 数据改变:SCL为低电平时,SDA线才能改变传输的bit,此时SDA数据无效,SCL为高时数据有效。
开始和结束信号 开始信号:SCL为高电平时,SDA由高电平向低电平跳变,开始传送数据。 结束信号:SCL为高电平时,SDA由低电平向高电平跳变,结束传送数据。
应答信号
Master每发送完8bit数据后等待Slave的ACK。 即在第9个clock,若从IC发ACK,SDA会被拉低。 若没有ACK,SDA会被置高,这会引起Master发生RESTART或STOP流程,如下所示:
关于SDA和SCL,当SCL位高电平时,SDA上的数据才有效,SCL位低电平时SDA的数据被忽略。
关于IIC总线的器件地址
总线上的主机在发送数据前先发送要与之通讯的从机的器件地址,主机通过对这个地址的呼叫来确定对总线上拥有该地址的器件进行数据交换。
进行IIC通信时发送启动信号后发送的一字节地址数据,地址数据时规范的。
7 - 1位地址,第7位是地址的最高位,第0位表示数据的传送方向,
= 0 ,表示写,数据从主机到从机
= 1,表示读,数据从从机到主机。
有一个特殊的地址叫广播地址,如果使用该地址进行通讯,则总线上所有的器件均能收到。广播地址全0.
关于IIC总线的冲突仲裁
由于总线上挂载了多个器件,所以有可能同一时刻多个器件争取总线控制权。注意,总线上挂接的器件都有权利成为主机。
最后附上模拟IIC的C语言实现:
//产生起始信号 void I2C_Start(void) { I2C_SDA_OUT();//配置一下引脚,引脚设置为输出 I2C_SDA_H;//把数据线拉高 I 2C_SCL_H;//把时钟线拉高 delay_us(5);//延时5微秒,要求大于4.7微秒 I2C_SDA_L; //拉低,产生下降沿 delay_us(6);//这个过程大于4微秒 I2C_SCL_L;//最后一定要把这个时钟线拉低,因为只有时钟线拉低的时候才允许数据变化。 } //产生停止信号 void I2C_Stop(void) { I2C_SDA_OUT(); I2C_SCL_L; I2C_SDA_L; I2C_SCL_H; delay_us(6); I2C_SDA_H; delay_us(6); } //主机产生应答信号ACK void I2C_Ack(void) { I2C_SCL_L; I2C_SDA_OUT(); I2C_SDA_L; delay_us(2); I2C_SCL_H; delay_us(5); I2C_SCL_L; } //主机不产生应答信号NACK void I2C_NAck(void) { I2C_SCL_L; I2C_SDA_OUT(); I2C_SDA_H; delay_us(2); I2C_SCL_H; delay_us(5); I2C_SCL_L; } //等待从机应答信号,我们只负责主机应答信号的产生,从机应答信号 //我们不控制。 //返回值:1 接收应答失败 // 0 接收应答成功 u8 I2C_Wait_Ack(void) { u8 tempTime=0; I2C_SDA_IN(); //配置为上拉输入。 I2C_SDA_H; //主机释放数据总线,等待从机产生应答信号 delay_us(1); I2C_SCL_H; delay_us(1); //等待从机对数据总线的操作。低电平代表应答 while(GPIO_ReadInputDataBit(GPIO_I2C,I2C_SDA)) { tempTime++; //这个属于软件延时,不一定准确。 if(tempTime>250) //如果时间超时,没有应答就停止。 { I2C_Stop(); return -1; //没有响应的话返回-1. } } I2C_SCL_L; return 0; //如果有响应的话就返回0. } //编程要点:
无论是发送启动信号还是停止信号,或者发送数据,最后都要保证SCL=0,为低电平,因为只有SCL位低电平时SDA的数据才能发生变化,这一操作相当于交出总线控制权。