IC串行总线一般有两根信号线,一根是双向的数据线SDA,另一根是时钟线SCL,其时钟信号是由主控器件产生。所有接到IIC总线设备上的串行数据SDA都接到总线的SDA上,各设备的时钟线SCL接到总线的SCL上。对于并联在一条总线上的每个IC都有唯一的地址。
一般情况下,数据线SDA和时钟线SCL都是处于上拉电阻状态。因为:在总线空闲状态时,这两根线一般被上面所接的上拉电阻拉高,保持着高电平。
IIC协议
IIC总线在传输数据的过程中一共有三种类型信号,分别为:开始信号、结束信号和应答信号。这些信号中,起始信号是必需的,结束信号和应答信号,都可以不要。同时我们还要介绍其空闲状态、数据的有效性、数据传输。
先来看一下IIC总线的时序图:
空闲状态
当IIC总线的
数据线
SDA和
时钟线
SCL两条信号线同时处于
高电平时,规定为总线的空闲状态
。此时各个器件的输出级场效应管均处在截止状态,即释放总线,由两条信号线各自的上拉电阻把电平拉高。
起始信号与停止信号
起始信号:当时钟线SCL为高期间,数据线SDA由高到低的跳变;启动信号是一种电平跳变时序信号,而不是一个电平信号;
停止信号:当时钟线SCL为高期间,数据线SDA由低到高的跳变;停止信号也是一种电平跳变时序信号,而不是一个电平信号。
应答信号
发送器每发送一个字节(8个bit),就在时钟脉冲9期间释放数据线,由接收器反馈一个应答信号。
应答信号为低电平时,规定为有效应答位(ACK,简称应答位),表示接收器已经成功地接收了该字节;
应答信号为高电平时,规定为非应答位(NACK),一般表示接收器接收该字节没有成功。
对于反馈有效应答位ACK的要求是:接收器在第9个时钟脉冲之前的低电平期间将数据线SDA拉低,并且确保在该时钟的高电平期间为稳定的低电平。 如果接收器是主控器,则在它收到最后一个字节后,发送一个NACK信号,以通知被控发送器结束数据发送,并释放数据线SDA,以便主控接收器发送一个停止信号P。
数据有效性
IIC总线进行数据传送时,
时钟信号为高电平期间,数据线上的数据必须保持稳定
;只有在时钟线上的信号为低电平期间,数据线上的高电平或低电平状态才允许变化。
即:数据在时钟线SCL的上升沿到来之前就需准备好。并在在下降沿到来之前必须稳定。
数据的传达
在IIC总线上传送的每一位数据都有一个时钟脉冲相对应(或同步控制),即在SCL串行时钟的配合下,在SDA上逐位地串行传送每一位数据。数据位的传输是边沿触发。
延时时间
IIC总线的数据传送
IIC总线上的每一个设备都可以作为主设备或者从设备,而且每一个设备都会对应一个唯一的地址(地址通过物理接地或者拉高),主从设备之间就通过这个地址来确定与哪个器件进行通信,在通常的应用中,我们把CPU带I2C总线接口的模块作为主设备,把挂接在总线上的其他设备都作为从设备。
也就是说,
主设备在传输有效数据之前要先指定从设备的地址,地址指定的过程和上面数据传输的过程一样,只不过大多数从设备的地址是7位的,然后协议规定再给地址添加一个最低位用来表示接下来数据传输的方向,0表示主设备向从设备写数据,1表示主设备向从设备读数据。
主设备往从设备中写数据。数据传输格式如下:
淡蓝色部分表示数据由主机向从机传送,粉红色部分则表示数据由从机向主机传送。写用0来表示(高电平),读用1来表示(低电平)。
主设备从从设备中读数据。数据传输格式如下:
在从机产生响应时,主机从发送变成接收,从机从接收变成发送。之后,数据由从机发送,主机接收,每个应答由主机产生,时钟信号仍由主机产生。若主机要终止本次传输,则发送一个非应答信号,接着主机产生停止条件。
主设备往从设备中写数据,然后重启起始条件,紧接着从从设备中读取数据;或者是主设备从从设备中读数据,然后重启起始条件,紧接着主设备往从设备中写数据。数据传输格式如下:
#include "STC15.h"
#include <intrins.h>
#include "IIC.h"
#include "delay.h"
//总线引脚定义
sbit SDA = P3^3; /* 数据线 */
sbit SCL = P3^2; /* 时钟线 */
//总线启动条件
void IIC_start(void)
{
SDA = 1;
SCL = 1;//SCL输入和SDA下降沿启动 SDA下降沿和SCL下降沿启动
delay5us();
SDA = 0;
delay5us();
SCL = 0;
}
//总线停止条件
void IIC_stop(void)
{
SDA = 0;
SCL = 1;
delay5us();
SDA = 1;
}
//主机非应答 用于主机读取从机数据时停止前信号
void IICNoAck(void)
{
SDA = 1;//释放总线,用来检测从机的应答信号
delay5us();
SCL = 1;
delay5us();
SCL = 0;
delay5us();
SDA = 1;
}
//等待从机应答
bit IIC_WaitAck(void) //应答返回1,不应答停止总线并返回0
{
SDA = 1;
delay5us();
SCL = 1;
delay5us();
if(SDA)
{
SCL = 0;
IIC_stop();
return 0;
}
else
{
SCL = 0;
return 1;
}
}
//通过I2C总线发送数据
void IIC_writebyte(unsigned char byt)
{
unsigned char i;
for(i=0;i<8;i++)
{
if(byt&0x80)
{
SDA = 1;
}
else
{
SDA = 0;
}
delay5us();
SCL = 1;
byt <<= 1;
delay5us();
SCL = 0;
}
}
//从I2C总线上接收数据
unsigned char IIC_readbyte(void)
{
unsigned char da;
unsigned char i;
for(i=0;i<8;i++)
{
SCL = 1;
delay5us();
da <<= 1;
if(SDA)
da |= 0x01;
SCL = 0;
delay5us();
}
return da;
}