I2C总线是一种简单、双向二线制同步串行总线。它只需要两根线即SCL(时钟信号线)和SDA(数据线),就可在连接于总线上的器件之间传送信息。
I2C采用的是主从式通信方式,通信的过程完全由主设备决定。通讯的起始信号和终止信号都由主设备发送。
起始信号:在SCL时钟信号在高电平期间,SDA信号产生一个下降沿,起始之后SDA和SCL都为0。
1 void I2C_Start() 2 { 3 I2C_SDA = 1; 4 I2C_Delay10us(); 5 I2C_SCL = 1; 6 I2C_Delay10us(); //建立时间是I2C_SDA保持时间>4.7us 7 8 I2C_SDA = 0; //保持时间是>4us 9 I2C_Delay10us(); 10 I2C_SCL = 0; 11 I2C_Delay10us(); 12 }
终止信号:在SCL时钟信号在高电平期间,SDA信号产生一个上升沿,终止后保持SDA和SCL都为1,表示总线空闲。
1 void I2C_Stop() 2 { 3 I2C_SDA = 0; 4 I2C_Delay10us(); 5 I2C_SCL = 1; 6 I2C_Delay10us(); //建立时间是I2C_SDA保持时间>4.7us 7 8 I2C_SDA = 1; 9 I2C_Delay10us(); 10 }
I2C总线上可以挂多个从设备,为了区分从设备,每个设备都有自己的地址编码。当主从通讯时,主设备必须先发送一个从设备的地址。在SCL时钟信号线处于低电平时,SDA数据线上的地址信息要开始准备了。I2C在传送地址信息时都是从高位开始传送。
SCL时钟信号低电平转换为高电平再转换为低电平,一个bit的数据传送完毕。如果数据传送成功,从设备将会返回一个应答信号,此时,总线应该要处于空闲状态,等待应答信号。
1 uchar I2C_SendByte(uchar dat, uchar ack) 2 { 3 uchar a = 0, b = 0;//最大255,一个机器周期1us 最大延时255us 4 5 for(a=0; a<8; a++) 6 { 7 I2C_SDA = dat >> 7; 8 dat = dat << 1; 9 I2C_Delay10us(); 10 I2C_SCL = 1; 11 I2C_Delay10us();//建立时间>4.7us 12 I2C_SCL = 0; 13 I2C_Delay10us();//建立时间>4us 14 } 15 16 I2C_SDA = 1; 17 I2C_Delay10us(); 18 I2C_SCL = 1; 19 I2C_Delay10us(); 20 21 while(I2C_SDA && (ack == 1)) // 等待应答,也就是等待从设备把I2C_SDA拉低 22 { 23 b++; 24 if(b > 200) 25 { 26 I2C_SCL = 0; 27 I2C_Delay10us(); 28 return 0; 29 } 30 } 31 32 I2C_SCL = 0; 33 I2C_Delay10us(); 34 return 1; 35 }
当从设备需要读取从设备数据时,总线同样需要处于空闲状态。当SCL低电平转换为高电平时,读取一个bit的数据,SCL再次转换为低电平时,读取结束。数据从高位开始读取。
1 uchar I2C_ReadByte() 2 { 3 uchar a = 0, dat = 0; 4 I2C_SDA = 1; //起始和发送一个字节之后I2C_SCL都是0 5 I2C_Delay10us(); 6 for(a=0; a<8; a++) 7 { 8 I2C_SCL = 1; 9 I2C_Delay10us(); 10 dat <<= 1; 11 dat |= I2C_SDA; 12 I2C_Delay10us(); 13 I2C_SCL = 0; 14 I2C_Delay10us(); 15 } 16 return dat; 17 18 }