1.IIC物理连接
I2C总线是由NXP(原PHILIPS)公司设计,有十分简洁的物理层定义,其特性如下:
- 只要求两条总线线路:一条串行数据线SDA,一条串行时钟线SCL;
- 每个连接到总线的器件都可以通过唯一的地址和一直存在的简单的主机/从机关系软件设定地址,主机可以作为主机发送器或主机接收器;
- 它是一个真正的多主机总线,如果两个或更多主机同时初始化,数据传输可以通过冲突检测和仲裁防止数据被破坏;
- 串行的8 位双向数据传输位速率在标准模式下可达100kbit/s,快速模式下可达400kbit/s,高速模式下可达3.4Mbit/s;
- 连接到相同总线的IC 数量只受到总线的最大电容400pF 限制。
通过对SCL和SDA线高低电平时序的控制,来产生I2C总线协议所需要的信号进行数据的传递。在总线空闲状态时,这两根线一般被上面所接的上拉电阻拉高,保持着高电平。
其典型的接口连线如下:
2.IIC总线协议:
协议发送数据图示
1】起始和结束信号总是由主设备产生
起始信号:SCL高电平空闲,SDA由高变低;(SDA拉低后SCL再拉低)
结束信号:SCL高电平空闲,SDA由低变高;(SCL拉高后SDA再拉低)
//起始信号传输
void MyIIC_start(void)
{
SDA_OUT();
IIC_SCL=1;
IIC_SDA=1;
delay_us(4);
IIC_SDA=0;
delay_us(4);
IIC_SCL=0;
}
//停止信号
void MyIIC_stop(void)
{
SDA_OUT();
IIC_SCL=1;
IIC_SDA=0;
delay_us(4);
IIC_SDA=1;
delay_us(4);
IIC_SCL=0;
}
2】数据发送与接收
SDA的数据在SCL高电平期间被写入从机。所以SDA的数据变化要发生在SCL低电平期间。
//发送一个字节8位数据
void IIC_Send_Byte(u8 txd)
{
u8 t;
SDA_OUT();
IIC_SCL=0;//拉低时钟开始数据传输
for(t=0;t<8;t++)
{
IIC_SDA=(txd&0x80)>>7;//获取从高位到低位
txd<<=1;
delay_us(4);//等待稳定
IIC_SCL=1;//拉高信号线
delay_us(4); //信号延时
IIC_SCL=0;//拉低信号线
delay_us(4);//等待下一个数据
}
}
//读取1个字节8位数据
u8 IIC_Read_Byte(void)
{
u8 i,receive=0;
SDA_IN();//SDA设置为输入
for(i=0;i<8;i++ )
{
IIC_SCL=0; //拉低信号线
delay_us(2);
IIC_SCL=1;//拉高数据线
receive<<=1;//数据左移
if(READ_SDA)receive++;//获取当前数据位并进行记录
delay_us(2); //等待数据线拉低
}
return receive;
}
3】应答信号
发送器每发送一个字节,就在时钟脉冲9期间释放数据位置,由接收器反馈一个应答信号。应答信号为低电平时,规定为有效应答位(ACK简称应答位),表示接收器已经成功接收了该字节;应答信号为高电平时,规定为非应答位(NACK),一般表示接收器接收该字节没有成功。
如果接收器是主控器,则在它收到最后一个字节后,发送一个NACK信号,以通知被控发送器结束数据发送,并释放SDA线,以便主控接收器发送一个停止信号P。
对于反馈有效应答位ACK的要求是,接收器在第9个时钟脉冲之前的低电平期间将SDA线拉低,并且确保在该脉冲期间保持低电平。
//读取应答信号
u8 IIC_Wait_Ack(void)
{
u8 ucErrTime=0;
SDA_IN(); //SDA设置为输入
IIC_SDA=1;delay_us(1);
IIC_SCL=1;delay_us(1);
while(READ_SDA)
{
ucErrTime++;
if(ucErrTime>250)
{
IIC_Stop();
return 1;
}
}
IIC_SCL=0;//时钟输出0
return 0;
}
//产生应答信号
void IIC_Ack(void)
{
IIC_SCL=0;
SDA_OUT();
IIC_SDA=0;
delay_us(2);
IIC_SCL=1;
delay_us(2);
IIC_SCL=0;
}
//不产生应答信号
void IIC_NAck(void)
{
IIC_SCL=0;
SDA_OUT();
IIC_SDA=1;
delay_us(2);
IIC_SCL=1;
delay_us(2);
IIC_SCL=0;
}
4】一个完整发送与接收周期
//写入8位数据并读取ACK,可以写入地址位,有对应地址的设备返回0,反之返回其他
u8 IIC_Send_Data(u8 data)
{
u8 flag=0;
MyIIC_start();
IIC_Send_Byte(data);//发送数据
if(IIC_Wait_Ack()==1) return 1;
else return 0;
}
数据传送完毕后,成功配置地址的设备必须发送“ACK”。否则否则一定时间之后主机视为超时,将放弃数据传送,发送停止信号或者重新发送数据。
//读取8位数据并设置ACK
void IIC_Read_Data(u8 flag)
{
u8 temp;
MyIIC_start();
temp = IIC_Read_Byte();
if(flag) IIC_Ack();
else IIC_NAck();
MyIIC_stop();
}
3.工作流程
约定读command为0x01,写command位0x00;约定主机发起通信后,第一个从机address字节收到ack后,紧跟的一个字节为command,再下面一个字节为address。
1】读数据过程
- 主机先发起一次通信,将(设备地址+command(0x01))和需要读取的寄存器地址address写入从机;(主机发出读操作)。
- 从机的处理,返回ack信号,将command和address分别提取出来;判断command的含义(是读指令还是写指令)
- 根据收到的的address,将该从机对应地址的数据放入IIC输出。
- 主机再次发起一次通信,读取从机的数据;(主机发出读操作)。
2】写一个数据过程
- 主机先发起一次通信,将(设备地址+command(0x00))和需要操作从设备地址address以及要写入的数据写入IIC;(主机发出写操作)。
- 从机的处理,返回ack信号,将command、address和data分别提取出来;判断command的含义(是读指令还是写指令)
- 根据收到的的address,将获取到的data存入对应地址内。
- 主机再次发起一次通信,给从机写入数据;(主机发出写操作)。