16、IIC通信协议

来源:互联网 发布:sql server 安装版 编辑:程序博客网 时间:2024/05/15 04:01

1、IIC简介

    IIC即Inter-Integrated Circuit(集成电路总线),它由飞利浦设计于80年代设计出来的,是一种半双工通信方式。(SPI是全双工方式)它是由时钟线SDA与数据线SCL构成串行总线。可以在IC与IC、IC与CPU之间进行双向传送。主机按照一定的通信协议给从机进行地址寻址及信息传输,其中数据的传输方向及传输地址都是有主机决定的。其典型的物理结构方式如下图所示:



 2、通信的起始与结束信号

起始信号:时钟线SCL处于高电平,数据线SDA下降沿;

终止信号:时钟线SCL处于高电平,数据线SDA上升沿;



3、IIC传输数据有效性

       以串行的方式进行传输,要求在时钟线SCL高电平期间,数据线SDA上的数值不可发生变化,且以数据位的最高位开始传输。



4、应答信号与非应答信号

      IIC通信中每一个字节必须保证是8位长度。数据传送时,先传送最高位(MSB),每一个被传送的字节后面都必须跟随一位应答位(即一帧共有9位)。如果一段时间内没有收到从机的应答信号,则自动认为从机已正确接收到数据。即在时钟的第九个时钟周期给主机一个应答或者非应答信号,应答信号从机发送给主机的一个低脉冲信号。

    

5、IIC完整的通信过程

      一般IIC通信包括这些过程,起始信号、发送地址、数据传送、应答(不应答)过程、停止信号。完成一个完整的字节数据传输需要9个时钟周期(8个位数据+1个应答(非应答周期))。在一个字节传输后可能会出现一个时钟的低电平,用于处理其他的事情,比如中断等事件。



6、寻址约定

    在开始信号之后的第一个字节,主机发送包含从机的地址信息及数据的写读方向读(1)、写(0);当从机发现主机发送的地址信息与自身的地址信息一致时,发送一个应答信号给主机,主机在接收到应答信号后发送访问地址,再接收到从机的应答信号,这样就算握手完成了。



7、主机发送1个字节数据给从机过程

    开始信号后,主机给所有从机发送一个包含地址与读写方向的字节数据,从机将发送的地址与自身的地址进行比较,如果一致,则发送一个应答信号给主机。主机接收到应答信号后,再发送一个要访问的地址,接收到从机的应答后开始发送数据。



8、主机接收一个来自从机数据的过程

   开始信号后,主机给所有从机发送一个包含地址及写方向的数据位,地址相同的从机发送一个应答信号之后,主机在发送寻址信息,得到应答信号后,主机在发送一次包含地址信息及读方向的字节。就可以开始发送数据,从机不发送应答信号说明一个字节的发送已经完成。


9、24C02

    串行E2PROM是基于I2C-BUS 的存储器件,遵循二线制协议,由于其具有接口方便,体积小,数据掉电不丢失等特点,在仪器仪表及工业自动化控制中得到大量的应用。其管脚配置如下:


10、24C02操作

     对于24CO2芯片,开始信号后第一个字节数据格式如下,高四位固定为1010,A2、A1、A0固定该器件在电路的地址。

11、IIC操作代码解析:

起始信号:

//产生 IIC 起始信号
void IIC_Start(void)
{
SDA_OUT();      //sda 线输出,设置该端口为输出模式
IIC_SDA=1;     
IIC_SCL=1;

delay_us(4);
IIC_SDA=0;//START:when CLK is high,DATA change form high to low 
delay_us(4);
IIC_SCL=0;//钳住 I2C 总线,准备发送或接收数据 
}   

终止信号:

//产生 IIC 停止信号
void IIC_Stop(void)
{
SDA_OUT();//sda 线输出
IIC_SCL=0;
IIC_SDA=0;//STOP:when CLK is high DATA change form low to high
delay_us(4);
IIC_SCL=1; 
IIC_SDA=1;//发送 I2C 总线结束信号
delay_us(4);                 
}

产生应答信号:

//产生 ACK 应答
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;
}        

发送一个字节:
//IIC 发送一个字节
//返回从机有无应答
//1,有应答
//0,无应答       
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(2);    //对 TEA5767 这三个延时都是必须的
IIC_SCL=1;
delay_us(2); 
IIC_SCL=0;
delay_us(2);
}   
}     

判断是否有应答信号:

//等待应答信号到来
//返回值:1,接收应答失败
//     0,接收应答成功
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;  

其中#define READ_SDA   PCin(11)  //输入SDA  即读取数据线的状态

接收一个字节:

//读1个字节,ack=1时,发送ACK,ack=0,发送nACK   
u8 IIC_Read_Byte(unsigned char ack)
{
unsigned char 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(1); 
    }  
    if (!ack)
        IIC_NAck();//发送nACK
    else
        IIC_Ack(); //发送ACK   
    return receive;
}

在24C02指定地址读取一个数据

//在AT24CXX指定地址读出一个数据
//ReadAddr:开始读数的地址  
//返回值  :读到的数据
u8 AT24CXX_ReadOneByte(u16 ReadAddr)
{  
u8 temp=0;        
    IIC_Start();  
if(EE_TYPE>AT24C16)
{
IIC_Send_Byte(0XA0);  //发送写命令
IIC_Wait_Ack();
IIC_Send_Byte(ReadAddr>>8);//发送高地址
IIC_Wait_Ack(); 
}else IIC_Send_Byte(0XA0+((ReadAddr/256)<<1));   //发送器件地址0XA0,写数据 


IIC_Wait_Ack(); 
    IIC_Send_Byte(ReadAddr%256);   //发送低地址
IIC_Wait_Ack();   
IIC_Start();    
IIC_Send_Byte(0XA1);           //进入接收模式  
IIC_Wait_Ack(); 
    temp=IIC_Read_Byte(0);   
    IIC_Stop();//产生一个停止条件    
return temp;
}

24C02写一个数据:

//在AT24CXX指定地址写入一个数据
//WriteAddr  :写入数据的目的地址    
//DataToWrite:要写入的数据
void AT24CXX_WriteOneByte(u16 WriteAddr,u8 DataToWrite)
{        
    IIC_Start();  
if(EE_TYPE>AT24C16)
{
IIC_Send_Byte(0XA0);   //发送写命令
IIC_Wait_Ack();
IIC_Send_Byte(WriteAddr>>8);//发送高地址
  }else
{
IIC_Send_Byte(0XA0+((WriteAddr/256)<<1));   //发送器件地址0XA0,写数据 
}  
IIC_Wait_Ack();  
    IIC_Send_Byte(WriteAddr%256);   //发送低地址
IIC_Wait_Ack();     
IIC_Send_Byte(DataToWrite);     //发送字节  
IIC_Wait_Ack();       
    IIC_Stop();//产生一个停止条件 
delay_ms(10);  
}

总结:严格按照时序来完成。
附上:关于IIC通讯的文章

http://www.eefocus.com/article/08-07/48416s.html

http://blog.csdn.net/chinaclock/article/details/5714595

http://blog.csdn.net/zmq5411/article/details/6085740

http://blog.csdn.net/ce123_zhouwei/article/details/6878547


0 0
原创粉丝点击