IIC协议介绍
Posted icaowu
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了IIC协议介绍相关的知识,希望对你有一定的参考价值。
总线信号 :
SDA :串行数据线
SCL :串行时钟
总线空闲状态 :
SDA :高电平
SCL :高电平
起始位:SCL为高电平期间 SDA出现下降沿
终止位:SCL为高电平期间 SDA出现上升沿
数据传输 :SDA的数据在SCL高电平期间被写入从机。所以SDA的数据变化要发生在SCL低电平期间。
IIC时钟频率:不高于400K
应答:当IIC主机(不一定是发送端还是接受端)将8位数据或命令传出后,会将SDA信号设置为输入,等待从机应答(等待SDA由高电平拉为低电平)
若从机正确应答,表明数据或者命令传输成功,否则传输失败,注意,应答信号是数据接收方发送给数据发送方的。
IIC器件地址:每一个IIC器件都有一个器件地址,有的器件地址在出厂时地址就设定好了,用户不可以更改,比如OV7670的
地址为0x42。有的器件例如EEPROM,前四个地址已经确定为1010,后三个地址是由硬件链接确定的,所以一
个IIC总线最多能连8个EEPROM芯片。
图上开始信号之后,七位地址代表器件地址,第八位代表读或者写,0为写,1代表读,然后跟着响应位。
IIC器件单字节写时序:
IIC器件多字节地址写时序:多字节地址比单字节地址在时序上就多了一块写地址
单字节器件读时序:注意最后产生无应答信号,另外多字节地址读时序跟单字节类似,只不过是多了几个地址字节而已。
//产生起始信号 void I2C_Start(void) { I2C_SDA_OUT();//配置一下引脚,引脚设置为输出 I2C_SDA_H;//把数据线拉高 I2C_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. }
再增加几个操作函数
/************************************************ 函数名称 : I2C_Delay 功 能 : I2C延时(非标准延时,请根据MCU速度 调节大小) 参 数 : 无 返 回 值 : 无 作 者 : strongerHuang *************************************************/ static void I2C_Delay(void) { uint16_t cnt = 10; while(cnt--); } /************************************************ 函数名称 : I2C_GPIO_Configuration 功 能 : I2C引脚配置(开漏输出) 参 数 : 无 返 回 值 : 无 作 者 : strongerHuang *************************************************/ void I2C_GPIO_Configuration(void) { GPIO_Init(PORT_I2C_SCL, (GPIO_Pin_TypeDef)PIN_I2C_SCL, GPIO_MODE_OUT_OD_HIZ_FAST); GPIO_Init(PORT_I2C_SDA, (GPIO_Pin_TypeDef)PIN_I2C_SDA, GPIO_MODE_OUT_OD_HIZ_FAST); } /************************************************ 函数名称 : I2C_Initializes 功 能 : I2C初始化 参 数 : 无 返 回 值 : 无 作 者 : strongerHuang *************************************************/ void I2C_Initializes(void) { I2C_GPIO_Configuration(); I2C_SCL_HIGH; //置位状态 I2C_SDA_HIGH; } /************************************************ 函数名称 : I2C_WriteByte 功 能 : I2C写一字节 参 数 : Data --- 数据 返 回 值 : 无 作 者 : strongerHuang *************************************************/ void I2C_WriteByte(uint8_t Data)//时钟低的时候先准备好数据,再打开时钟(读取应答位无判断?) { uint8_t cnt; for(cnt=0; cnt<8; cnt++) { I2C_SCL_LOW; //SCL低(SCL为低电平时变化SDA有效) I2C_Delay(); if(Data & 0x80) I2C_SDA_HIGH; //SDA高 else I2C_SDA_LOW; //SDA低 Data <<= 1; I2C_Delay(); I2C_SCL_HIGH; //SCL高(发送数据) I2C_Delay(); } I2C_SCL_LOW; //SCL低(等待应答信号) I2C_Delay(); I2C_GetAck(); //读取应答位 } /************************************************ 函数名称 : I2C_ReadByte 功 能 : I2C读一字节 参 数 : ack --------- 产生应答(或者非应答)位 返 回 值 : data -------- 读取的一字节数据 作 者 : strongerHuang *************************************************/ uint8_t I2C_ReadByte(uint8_t ack)//时钟低的时候先准备好数据,然后地址也弄高。然后等时钟高了再读取 { uint8_t cnt; uint8_t data; I2C_SCL_LOW; //SCL低 I2C_Delay(); I2C_SDA_HIGH; //释放SDA(开漏模式有效) for(cnt=0; cnt<8; cnt++) { I2C_SCL_HIGH; //SCL高(读取数据) I2C_Delay(); data <<= 1; if(I2C_SDA_READ) data |= 0x01; //读取SDA的状态 //SDA为高(数据有效) I2C_SCL_LOW; //SCL低 I2C_Delay(); } I2C_PutAck(ack); //产生应答(或者非应答)位 return data; //返回数据 }
以上是关于IIC协议介绍的主要内容,如果未能解决你的问题,请参考以下文章