IIC
型号 容量 器件/业面寻址字节 可寻址位 模块
24C01 128B (1010)(A2)(A1)(A0)(0或1) 3 128B
24C02 256B (1010)(A2)(A1)(A0)(0或1) 3 256B
24C04 512B (1010)(A2)(A1)(P0)(0或1) 2 2X256B
24C08 1024B (1010)(A2)(P1)(P0)(0或1) 1 4X256B
24C16 2048B (1010)(P2)(P1)(P0)(0或1) 0 8X256B
解析:IIC总线接口器件24C系列非易失性存储器与89C51接口采用软件模拟IIC。24C系列
存储器器件地址统一为1010XXXX,不要问为什么,这是厂家出厂的时候规定好的了。至
于24C的引脚功能和89C51的接口我就不多说了,本文的重点主要是如何应用。
上面说了,器件的地址字节的高位是1010,那么低4位呢?先说最后一位吧,最后一
位为0的时候表示89C51要写数据入存储器,1的时候表示要从存储器读数据。还剩下中
三位A2,A1和A0。它们的高低电平取决于24C的A2,A1,A0是接高电平还是接地。A2,
A1 和A0有8个组合,因此可以扩展8个相同的器件,根据A2、A1、A0的不同,一样的器件
也会有不同的地址。那么是不是每一个24C都可以扩展8个呢?不是的。注意上表,24C01
有三个可寻址位,A2,A1,A0,所以可以扩展8个,24C02也一样。而04则只可以扩展4个
08只可以扩展2个,16就没有扩展了,只可以挂一片24C16。为什么呢?因为访问24C系列
除了访问器件地址外,还要访问器件内的字节的地址。例如24C01,要对其操作,就先选
选中它的地址,然后操作第一个字节或其他字节,这些字节也是有地址的,分模块,用
一个字节表示,最多可以操作256个字节。24C01和24C02不大于256个字节,对其操作就
简单得多了。但24C04,08和16呢?他们都大于256个字节,怎么办?分模块。注意到上
表的P0,P1,P3没有?把04分成两个模块,2X256B,08四个模块,16就八个模块。究竟
怎么
模块操作呢?拿24C08为例,有A2 P1 P0。A2只可以0或1,所以只能扩展2个24C08,其
内有4个256字节的模块,要操作哪个模块取决于P1,P0的组合。例如,24C08的地址字节
为1010000X第一个字节地址为0,第256个地址为255,如果地址字节是1010001X,那么第
256个字节的地址为0,第512个字节的地址为255。就如此。
再用24C08举例说明如何扩展,当两个24C08的A2脚分别接高电平和地的时候,就可
以了,这样就扩展了,他们的器件地址分别是1010000X和1010100X。当要读第一个(A2
接地)
24C08的的第一个模块的数据时候,单片机先发送地址字节10100001;当要把数据写
进第二个(A2接高电平)24C08的第二个模块的时候,应发送10101010地址字节。
不再说了,再说我疯了,看程序吧。这是对24C16操作的例子。*/
24C01 128B (1010)(A2)(A1)(A0)(0或1) 3 128B
24C02 256B (1010)(A2)(A1)(A0)(0或1) 3 256B
24C04 512B (1010)(A2)(A1)(P0)(0或1) 2 2X256B
24C08 1024B (1010)(A2)(P1)(P0)(0或1) 1 4X256B
24C16 2048B (1010)(P2)(P1)(P0)(0或1) 0 8X256B
解析:IIC总线接口器件24C系列非易失性存储器与89C51接口采用软件模拟IIC。24C系列
存储器器件地址统一为1010XXXX,不要问为什么,这是厂家出厂的时候规定好的了。至
于24C的引脚功能和89C51的接口我就不多说了,本文的重点主要是如何应用。
上面说了,器件的地址字节的高位是1010,那么低4位呢?先说最后一位吧,最后一
位为0的时候表示89C51要写数据入存储器,1的时候表示要从存储器读数据。还剩下中
三位A2,A1和A0。它们的高低电平取决于24C的A2,A1,A0是接高电平还是接地。A2,
A1 和A0有8个组合,因此可以扩展8个相同的器件,根据A2、A1、A0的不同,一样的器件
也会有不同的地址。那么是不是每一个24C都可以扩展8个呢?不是的。注意上表,24C01
有三个可寻址位,A2,A1,A0,所以可以扩展8个,24C02也一样。而04则只可以扩展4个
08只可以扩展2个,16就没有扩展了,只可以挂一片24C16。为什么呢?因为访问24C系列
除了访问器件地址外,还要访问器件内的字节的地址。例如24C01,要对其操作,就先选
选中它的地址,然后操作第一个字节或其他字节,这些字节也是有地址的,分模块,用
一个字节表示,最多可以操作256个字节。24C01和24C02不大于256个字节,对其操作就
简单得多了。但24C04,08和16呢?他们都大于256个字节,怎么办?分模块。注意到上
表的P0,P1,P3没有?把04分成两个模块,2X256B,08四个模块,16就八个模块。究竟
怎么
模块操作呢?拿24C08为例,有A2 P1 P0。A2只可以0或1,所以只能扩展2个24C08,其
内有4个256字节的模块,要操作哪个模块取决于P1,P0的组合。例如,24C08的地址字节
为1010000X第一个字节地址为0,第256个地址为255,如果地址字节是1010001X,那么第
256个字节的地址为0,第512个字节的地址为255。就如此。
再用24C08举例说明如何扩展,当两个24C08的A2脚分别接高电平和地的时候,就可
以了,这样就扩展了,他们的器件地址分别是1010000X和1010100X。当要读第一个(A2
接地)
24C08的的第一个模块的数据时候,单片机先发送地址字节10100001;当要把数据写
进第二个(A2接高电平)24C08的第二个模块的时候,应发送10101010地址字节。
不再说了,再说我疯了,看程序吧。这是对24C16操作的例子。*/
复制内容到剪贴板
代码:
#include <reg51.h>
/* 全局符号定义 */
#define WRITE 0xA0 /* 定义24C016的器件地址SLA和方向位W */
#define READ 0xA1 /* 定义24C04的器件地址SLA和方向位R */
#define BLOCK_SIZE 100 /* 定义指定字节个数 */
#define uchar unsigned char
#define HIGH 1
#define LOW 0
#define FALSE 0
#define TRUE ~FALSE
sbit SCL =P3^4; //T0
sbit SDA =P3^5; //T1
uchar xdata EAROMImage[BLOCK_SIZE]={0}; /* 在外部RAM中定义发送存储映象单元 */
void delayi2c( void ) {
;
}
void I_start( void ) {
SCL = HIGH ;
delayi2c() ;
SDA = LOW ;
delayi2c() ;
SCL = LOW ;
delayi2c() ;
}
void I_stop( void ) {
SDA = LOW ;
delayi2c() ;
SCL = HIGH ;
delayi2c() ;
SDA = HIGH ;
delayi2c() ;
SCL = LOW ;
delayi2c() ;
}
//初始化
void I_init( void ) {
SCL = LOW ;
I_stop() ;
}
bit I_clock( void ) {
bit sample ;
SCL = HIGH ;
delayi2c() ;
sample = SDA ;
SCL = LOW ;
delayi2c() ;
return ( sample ) ;
}
//发送8位数据
bit I_send( uchar I_data ) {
uchar i ;
/* 发送8位数据 */
for ( i=0 ; i<8 ; i++ ) {
SDA = (bit)( I_data & 0x80 ) ;
I_data = I_data << 1 ;
I_clock() ;
}
/* 请求应答信号ACK */
SDA = HIGH ;
return ( ~I_clock() );
}
//接受8位数据
uchar I_receive( void ) {
uchar I_data = 0 ;
register uchar i ;
for ( i=0 ; i<8 ; i++ ) {
I_data *= 2 ;
if (I_clock()) I_data++ ;
}
return ( I_data ) ;
}
//应答
void I_Ack( void ) {
SDA = LOW;
I_clock();
SDA = HIGH;
}
void wait_5ms( void ) {
int i ;
for ( i=0 ; i<1000 ; i++ )
{
;
}
}
//向24C04写入器件地址和一个指定的字节地址。
bit E_address(uchar page ,uchar Address )
{
I_start() ;
if ( I_send( WRITE +page) )
return ( I_send( Address ) ) ;
else
return ( FALSE ) ;
}
//参数的含义:从第几个模块(不超过3),模块中第几个字节(不超过255)
// 写到RAM映象的第几个字节和读的长度
bit E_read_block(uchar page, uchar addr,uchar arraypoint,uchar longth)
{
uchar i ;
/* 从地址0开始读取数据 */
if ( E_address(page, addr ) ) {
/* 发送重复启动信号 */
I_start() ;
if ( I_send( READ+page ) ) {
for ( i=0; i<=longth ;i++ )
{
EAROMImage[arraypoint+i] =I_receive();
if ( i != longth ) I_Ack() ;
else {
I_clock() ;
I_stop() ;
}
}
return ( TRUE ) ;
}
else {
I_stop() ;
return ( FALSE ) ;
}
}
else
I_stop() ;
return ( FALSE ) ;
}
bit E_write_block(uchar page,uchar addr,uchar arraypoint,uchar longth) {
uchar i ;
for ( i=addr; i<=addr+longth ; i++ ) {
if ( E_address(page,i) && I_send( EAROMImage[arraypoint+i-addr] ) ) {
I_stop() ;
wait_5ms();
}
else
return ( FALSE ) ;
}
return ( TRUE ) ;
}
//test
void main() {
EAROMImage[39]=0xfe;
SCON = 0x5a;
TMOD = 0x20;
TCON = 0x69;
TH1 = 0xfd;
I_init(); // I2C 总线初始化
P1=0xFF;
if (E_write_block(0,8,39,1))
P1=0xFE;//p10
else
{}
if (E_read_block(0,8,55,1))
{}
else
P1=P1&0xFD;
if(EAROMImage[55]==0xfe)
P1=P1&0x0FB;
while(1);
}