IIC是一种通信是一种由 PHILIPS 公司开发的两线式串行总线。IIC是用来传输数据的,也是一种通信协议。
IIC的特点:
IIC总线简单而有效,占用的PCB(印制电路板)空间很小,芯片引脚数量少,设计成本低。IIC总线支持多主控(Multi-Mastering)模式,任何能够进行发送和接收的设备都可以成为主设备。主控能够控制数据的传输和时钟频率,在任意时刻只能有一个主控。高速 IIC 总线一般可达 400kbps 以上。
I2C 总线在传送数据过程中共有三种类型信号, 它们分别是:开始信号、结束信号和应答信号。
这些信号中,起始信号是必需的,结束信号和应答信号,都可以不要。
硬件IIC:
硬件IIC也就是说它的通信时序由硬件完成,不需要软件干预。也就是说什么起始信号、结束信号、应答信号我们不用管,它们都是由硬件完成的。
硬件IIC的优缺点:
优点:通信速度快、效率高。
缺点:只能是拥有IIC功能的IO口可以用,移植起来很麻烦。
软件IIC:
软件IIC是指用软件去控制单片机IO口的电平的高低转换以及高低电平的时间去模拟出一个IIC通信的时序。也就说IIC的起始信号、结束信号、应答/非应答信号都是用软件编程写出来的。
软件IIC的优点:可移植性高;是个单片机都能用,任何普通的IO口都可以进行软件IIC通信(像51单片机这一类,就必须用软件IIC了)。
缺点:通信效率慢了点,但是几us完全可以忽略不计。
前面我们就有说IIC的起始信号是必需的,结束信号和应答信号,都可以不要,在这里就看看IIC起始信号的代码。
这里是AT24Cxx芯片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_SDA和IIC_SCL用宏定义定义了单片机的引脚,比如:#define IIC_SCL PBout(8) //SCL
这样的代码移植起来非常方便,假如你想把stm32的例程移植到51单片机的时候,只需要把引脚定义改一改,另外再写一个精确的延时函数即可,非常简单方便。所以我极力推荐大家使用软件IIC通信。
引脚功能:
题外:NC代表引脚可悬空(NC代表无用引脚,在设计时不用连接)在使用大于2K的AT24C系列芯片时, A0-A2会有几个引脚为无用,具体可看芯片手册。
为什么这样设计,引脚为什么这样连?这就要问问芯片手册了。
翻译如下:(加入了个人理解,可能会有错误)
引脚描述:
串行时钟(SCL): SCL输入用于将正边缘时钟数据输入每个EEPROM设备,将负边缘时钟数据输出每个设备。
串行数据(SDA): SDA引脚是双向串行数据传输。这种引脚是开漏驱动的,可以与任意数量的其他开漏或开集电极装置相连。
设备/页面地址(A2, A1, A0): A2, A1和A0引脚是AT24CO1A和AT24C02硬连接的设备地址输入。多达八台1K/2K设备可以在一个总线系统上被寻址(设备寻址在设备寻址部分下被详细讨论)。(A2, A1, A0,3个位代表8个地址,其实就是2^3=8,所以可以AT24C01/2可以接8个设备)
写保护(WP): AT24C01A/02/04/08A/16A有一个写保护pin,提供硬件数据保护。当连接到地(GND)时,写保护pin允许正常的读/写操作。当写保护引脚连接到Vcc时,写保护功能启用。
设备地址的第8位是读/写操作选择位(R/W位)。
按照我们原理图的接法,我们可以知道:
2、A2, A1和A0引脚都是接地,芯片高四位统一为1010(十六进制为A)所以器件地址就是:1010 000X
字节写:
字节写操作首先发送设备地址字和写确认(也就是0XA0));在收到这个地址,EEPROM将响应一个“0”。
然后发送8位数据储存地址(在容量大于2K的芯片是word adress,也就是字地址,一个字为两个字节,所以一次是写两个字节地址,分别为要写入地址的高8位和低八位共16位地址);在收到两个8位数据字地址之后,EEPROM将再输出一个“0”响应。最后发送数据,发送结束后产生一个0的应答。
寻址设备,如微控制器,在收到这些操作后必须以停止条件终止写序列。此时EEPROM进入到非易失性存储器的内部定时写周期twp。在这个写周期中,所有输入都被禁用,直到写完成,EEPROM才会响应(参见第10页的图8)。
//在AT24CXX指定地址写入一个数据
//WriteAddr :写入数据的目的地址
//DataToWrite:要写入的数据
void AT24CXX_WriteOneByte(u16 WriteAddr,u8 DataToWrite)
{
IIC_Start(); //产生IIC起始信号
//发送外设地址0XA0(末位为0表示写数据) +储存地址高8位
IIC_Send_Byte(0XA0+((WriteAddr/256)<<1));
IIC_Wait_Ack(); //等待应答
IIC_Send_Byte(WriteAddr%256); //发送储存地址低8位
IIC_Wait_Ack();
IIC_Send_Byte(DataToWrite); //发送字节
IIC_Wait_Ack();
IIC_Stop(); //产生停止信号
delay_ms(10);
}
程序里面把器件地址(对应word adress)分开为两次发(因为IIC每次是写入8位),第一次是(WriteAddr/256)<<1)把地址左移一位。
**注意:**其实在使用AT24C02时,不需要那么麻烦。只需以下操作:
void AT24CXX_WriteOneByte(u16 WriteAddr,u8 DataToWrite)
{
IIC_Start(); //产生IIC起始信号
IIC_Send_Byte(0XA0); //发送外设地址0XA0
IIC_Wait_Ack(); //等待应答
IIC_Send_Byte(WriteAddr); //发送储存地址
IIC_Wait_Ack();
IIC_Send_Byte(DataToWrite); //发送字节
IIC_Wait_Ack();
IIC_Stop(); //产生停止信号
delay_ms(10);
}
所以多出来的那几个语句只是为了兼容后面容量大的芯片。
页写:(没有例程)
页写:1K/2K EEPROM能够进行8字节的页写,而4K、8K和16K设备能够进行16字节的页写。页写的初始化与字节写的初始化是一样的,但是微控制器不会在第一个数据字被写入后发送一个停止条件。相反,在EEPROM确认接收到第一个数据字后,微控制器可以发送最多服务器(1K/2K)或15个(4K、8K、16K)更多的数据字。EEPROM在收到每个数据字后将以一个“O”响应。微控制器必须使用停止条件终止页写序列(参见第10页上的图9)。数据字地址较低的三位(1K/2K)或四位(4K, 8K, 16K)位在收到每个数据字后内部递增。较高的数据字地址位不递增,保持内存页行位置。当内部生成的单词address到达页面边界时,下面的字节被放置在同一页面的开头。如果超过8个(1K/2K)或16个(4K, 8K, 16K)数据字被传输到EEPROM,数据字地址将“滚动”,之前的数据将被覆盖
读的时序:有3种:1、当前地址读 2、随机读3、顺序读
//在AT24CXX指定地址读出一个数据
//ReadAddr:开始读数的地址
//返回值 :读到的数据
u8 AT24CXX_ReadOneByte(u16 ReadAddr)
{
u8 temp=0; //用于保存读取到的数据的变量
IIC_Start(); //产生一个起始信号
IIC_Send_Byte(0XA0+((ReadAddr/256)<<1)); //发送器件地址0XA0,末位为0代表写数据
IIC_Wait_Ack(); //产生一个应答信号
IIC_Send_Byte(ReadAddr%256); //发送低地址
IIC_Wait_Ack();
IIC_Start(); //再次产生一个起始信号
IIC_Send_Byte(0XA1); //发送器件地址,末位为1代表读数据进入接收模式
IIC_Wait_Ack();
temp=IIC_Read_Byte(0);
IIC_Stop();//产生一个停止条件
return temp;
}
关于ReadAddr%256和ReadAddr/256也是为了兼容容量大的AT24C系列芯片,具体在前面写操作时有写,这里就不再赘述了。