4ki2c串行i2c写eeprom全0xff芯片老化后编程失效是什么原因

Data&&&Video Transceivers
设计与模拟工具
ClockWorks& Configurator
1 Mb&64 Mb
1 Mb&64 Mb
64 Kb&1 Mb
512 Kb&1 Mb
耐用性(擦/写周期)
1,000,000+
I2C&、SPI、Microwire和UNI/O&总线
SPI、Dual和SQI& Flash
SPI、SDI和SQI&
时钟频率/访问时间
0.4&20 MHz
20&104 MHz
32和48引脚
数据保存时间
20年以上(使用电池)
典型待机电流
1.65V&1.95V, 2.7V&3.6V, 2.3V&3.6V
1.65V&1.95V, 2.7V&3.6V, 4.5V&5.5V
1.65V&1.95V, 2.5V&5.5V
-40&C至+125&C
-40&C至+105&C
-40&C至+85&C
-40&C至+85&C
-40&C至+85&C
Microchip Technology Inc. All rights reserved.自制单片机之六……串行I2C总线E2PROM AT24CXXX的应用
自制单片机之六……串行I2C总线E2PROM AT24CXXX的应用
[摘要:那一篇先容I2C存储器的应用。首要是先容AT24CXX系列器件,它分为两类,首要是经过被存储容量地点去分的,一类是AT24C02-AT24C16,它的存储容量从256字节到2048字节。另外一类是AT24C32-A]
  这一篇介绍I2C存储器的使用。主要是介绍AT24CXX系列器件,它分为两类,主要是通过被存储容量地址来分的,一类是AT24C02-AT24C16,它的存储容量从256字节到2048字节。另一类是AT24C32-AT24C1024,容量从4K-128K。(理论上好像可以达到最高512K字节容量,但现在网上最高也就能看到AT24C1024也就是128K字节容量)原理:  I2C总线是一种用于IC器件之间连接的二线制总线。它通过SDA(串行数据线)及SCL(串行时钟线)两根线在连到总线上的器件之间传送信息,并根据地址识别每个器件:不管是单片机、存储器、LCD驱动器还是键盘接口。I2C总线接口电路结构如图所示。
SDA和SCL均为双向I/O线,通过上拉电阻接正电源。当总线空闲时,两根线都是高电平。连接总线的器件的输出级必须是集电极或漏极开路,以具有线&与&功能。I2C总线的数据传送速率在标准工作方式下为100kbit/s,在快速方式下,最高传送速率可达400kbit/s。  在I2C总线技术规范中,开始和结束信号(也称启动和停止信号)的定义如图所示。当时钟线SCL为高电平时,数据线SDA由高电平跳变为低电平定义为&开始&信号;当SCL线为高电平时,SDA线发生低电平到高电平的跳变为&结束&信号。开始和结束信号都是由主器件产生。在开始信号以后,总线即被认为处于忙状态;在结束信号以后的一段时间内,总线被认为是空闲的。
I2C总线的数据传送格式是:在I2C总线开始信号后,送出的第一个字节数据是用来选择从器件地址的,其中4-7位为器件码,如1010就是代表串行E2PROM器件。1-3位为存储器的片选地址或存储器内的块地址码,如何区分?后面再做详细说明,第8位为方向位(R/W)。方向位为&0&表示发送,即主器件把信息写到所选择的从器件;方向位为&1&表示主器件将从从器件读信息。开始信号后,系统中的各个器件将自己的地址和主器件送到总线上的地址进行比较,如果与主器件发送到总线上的地址一致,则该器件即为被主器件寻址的器件,其接收信息还是发送信息则由第8位(R/W)确定。一个字节的写操作的过程:首先器件发出起始信号后,发送器件识别控制字节,即A00(最低位置0,即R/W读写控制位为低电平0),然后等待应答信号指示从器件被寻址。再发送一个AT24CXX存储器将要写入的位置地址。再次等待AT24CXX应答信号以后,将发送数据字节,AT24CXX接收到后写入到刚刚指定的存储器地址。然后主器件再次等待AT24CXX的应答信号。主器件最后发出停止信号。  在I2C总线上每次传送的数据字节数不限,但每一个字节必须为8位,而且每个传送的字节后面必须跟一个认可位(第9位),也叫应答位(ACK)。数据的传送过程如图所示。每次都是先传最高位,通常从器件在接收到每个字节后都会作出响应,即释放SCL线返回高电平,准备接收下一个数据字节,主器件可继续传送。如果从器件正在处理一个实时事件而不能接收数据时,(例如正在处理一个内部中断,在这个中断处理完之前就不能接收I2C总线上的数据字节)可以使时钟SCL线保持低电平,从器件必须使SDA保持高电平,此时主器件产生1个结束信号,使传送异常结束,迫使主器件处于等待状态。当从器件处理完毕时将释放SCL线,主器件继续传送。
  当主器件发送完一个字节的数据后,接着发出对应于SCL线上的一个时钟(ACK)认可位,在此时钟内主器件释放SDA线,一个字节传送结束,而从器件的响应信号将SDA线拉成低电平,使SDA在该时钟的高电平期间为稳定的低电平。从器件的响应信号结束后,SDA线返回高电平,进入下一个传送周期。  I2C总线还具有广播呼叫地址用于寻址总线上所有器件的功能。若一个器件不需要广播呼叫寻址中所提供的任何数据,则可以忽略该地址不作响应。如果该器件需要广播呼叫寻址中提供的数据,则应对地址作出响应,其表现为一个接收器。  5.总线竞争的仲裁 总线上可能挂接有多个器件,有时会发生两个或多个主器件同时想占用总线的情况。例如,多单片机系统中,可能在某一时刻有两个单片机要同时向总线发送数据,这种情况叫做总线竞争。I2C总线具有多主控能力,可以对发生在SDA线上的总线竞争进行仲裁,其仲裁原则是这样的:当多个主器件同时想占用总线时,如果某个主器件发送高电平,而另一个主器件发送低电平,则发送电平与此时SDA总线电平不符的那个器件将自动关闭其输出级。总线竞争的仲裁是在两个层次上进行的。首先是地址位的比较,如果主器件寻址同一个从器件,则进入数据位的比较,从而确保了竞争仲裁的可靠性。由于是利用I2C总线上的信息进行仲裁,因此不会造成信息的丢失。
器件说明:AT24CXXX系列引脚图如下
现在我先来说说AT24CXX的具体使用&&&&& 假设用AT89S51的P0.0做SDA总线,P0.1做SCL总线。有若干个I2C器件挂接在SDA和SCL总线上。现在要对E2PROM_01存储器进行写字节操作看看它是如何找到的。上面说过在发送完一个开始信号后接着发送一个字节的器件识别信号。这一个字节的4-7位就是器件识别码。1010就是对应E2PROM器件,其它器件就不再理会了。1-3位是器件的物理地址,也就是说如果是E2PROM,它可以在I2C总线上挂接(000-111)8个E2PROM。在这里就得详细说说AT24CXX上的A0,A1,A2和这个器件识别字节之间的关系了。上面说过存储器的寻址范围是一个字节,也就256个,AT24C02的存储容量为256字字,刚刚好将一个字节的地址用完。器件电路上A0,A1,A2三个管脚通过接高电平或低电平来和AT89S51发送过来的器件识别控制字节相匹配,从而得以识别出AT89S51将要操作的那个存储器。现在AT24C04的容量是512个字节,那不是一个字节的地址不够用了吗?其实它是将512个字节为成两个页,每页256字节,而页地址就是器件识别控制字节的1位。前面说了这个1-3位不是和器件上的A0,A1,A2匹配来识别器件的吗?是的,但存储器容量超过256字节情况就有变了。AT24C04上的A0这时就废弃不用了,只用A1和A2,这样就只能接(00-11)四个AT24C04了,同样AT24C08容量为1K字节分为4页了,于是页地址就是器件识别控制字节的1-2位,器件上的A0,A1废弃不用,只用A2,就只能接两个AT24C08了。AT24C16容量为2K字节,分为8页。页地址是器件识别控制字节的1-3位,全用了。器件上的A0,A1,A2,就无效了,只能接一只AT24C16。
我这么说能明白吗?
  对于大容量AT24C32-1024的存储器。器件的存储寻址地址为两个字节,所以它的一页为65536(64K)。AT24C32-64的容量为4K字节-8K字节,在一页范围,可以接8只器件。从AT24C128-1024的器件代号也由1010改为10100,多了一位,识别控制字节的器件物理地址就少了一位,变为1-2位,相应的在器件管脚上A2也废弃空着了,因此最多只能接四只器件。AT24C128-512只有两位器件地址所以最多只能接四只器件。而AT24C1024的容量为128K,分为两页,识别控制字节的的1位为页地址,器件的A0脚废弃不用,只用了A1。因此只能接2只器件。
&&&  下面我们进行具体的制做先准备好器件如下图 ,我用的是AT24C16
原先的板子如下图
好!下面我们进行调试:插上主电源。但AT24C16的电源短路帽不接,在短路帽两个针之间接上万用表的电流档检查是否有短路和静态电流的大小。实测静态电流几乎为零,改变两个数据线的电平时,电流会有所上升,说明电路基本正常。
现在我们接上电源短路帽把AT24C16电源接好。将两个数据线用跳线接到P1.6和P1.7口上(接到哪个口上可以自己选的)。注意分清哪个是SDA哪个是SCL。别弄错了。
把LCD12864装上,后面我们就要进行软件的调试了。
后面一篇,我们进行软件件部分的调试。
先将源代码附上。前面部分LCD12864的代码基本不变,添加上AT24C16的代码。
//LCD12864
//**********************************************************
//连线表: CPU=89S51
SysClock=12MHz
//DB0-DB7=P3.0-P3.7
/Reset=InBoard
//**********************************************************
//**********************************************************
//连线表: CPU=89S51
SysClock=12MHz
//SDA=P1.6
//**********************************************************
#include &reg52.h&
#include &stdlib.h&
#include &intrins.h&
#include &stdio.h&
#include &math.h&
#define uchar unsigned char
#define uint unsigned int
/****************LCD12864引脚定义*****************/
#define DataPort P3
//LCD128*64 I/O 信号管脚
//数据指令
CSL =P2^3;
CSR =P2^4;
uchar code BMP1[];
uchar code HZK_12[];
//12&12阵点字模
uchar code ASC_5x7[];
//5&7阵点字模
uchar str[4];
/**************AT24C16引脚定义*****************/
SDA =P1^6;
SCL =P1^7;
/***********************************************/
/****************LCD12864函数定义*******************/
void BusyL(void);
//左屏检测忙
void BusyR(void);
//右屏检测忙
void CheckBusy(void);
//读取忙信号
void Delay(uint MS);
void Locatexy(void);
//将屏幕横向0-12纵向0-7转换成左、右屏的的X、Y
void WriteCommandL( uchar CommandByte );
//向左屏写入指令
void WriteCommandR( uchar CommandByte );
//向右屏写入指令
uchar ReadData( void );
void WriteData( uchar DataByte );
void LcmClear( void );
void LcmInit( void );
void LcmPutBMP( uchar *puts );
//显示一幅图
void LcmReverseBMP( void );
//将整屏反显
void LcmPutHZ_12( uchar x,uchar y,uchar HZcode ); //在屏幕上任意点显示一个12&12汉字
uchar * uchartostr(unsigned char unm);
//将值转成字符串
void LcmPutAsc( uchar asc );
//显示一个5&7的ASC字符
void LcmPutstr( uchar row,uchar y,uchar * str );
//在设定位置显示字符串
void LcmPutpoint( uchar ro,uchar lie,uchar colour );
//在设定位置显示一个点
/****************AT24C16函数定义*******************/
/****向总线上发送n字节数***/
bit write_nbyte(uchar block_addr,uchar addr,uchar *s,uchar numb);
/****从总线上读取n个字节数******/
bit read_nbyte(uchar block_addr,uchar addr,uchar *s,uchar numb);
/*****************************
block_addr
存储器的块地址选0-8
存储器的存储地址
一般是用在数组的首地址
要写入的字节数
********************************/
/***************************/
/*检查Busy
/***************************/
void BusyL(void)
CheckBusy();
void BusyR(void)
CheckBusy();
void CheckBusy(void)
DataPort= 0xFF;
//输出0xff以便读取正确
while(0);//DataPort & 0x80);
//Status Read Bit7 = BUSY
/********************************************************/
/*根据设定的坐标数据,定位LCM上的下一个操作单元位置
/********************************************************/
void Locatexy(void)
uchar x,y;
switch (Col&0xc0)
/* col.and.0xC0
/*条件分支执行
{BusyL();break;}/*左区 */
case 0x40:
{BusyR();break;}/*右区 */
x = Col&0x3F|0x40;
/* col.and.0x3f.or.Set Y Address*/
y = Page&0x07|0xB8;
/* row.and.0x07.or.set Page
CheckBusy();
/* waitting for enable */
DataPort =
//设置页面地址
CheckBusy();
/* waitting for enable */
DataPort =
//设置列地址
/***************************/
/***************************/
void WriteCommandL( uchar CommandByte )
DataPort = CommandB
void WriteCommandR( uchar CommandByte )
DataPort = CommandB
/***************************/
/***************************/
uchar ReadData( void )
uchar DataB
Locatexy();
/*坐标定位,返回时保留分区状态不变
/*数据输出*/
DataPort = 0xFF;
//输出0xff以便读取正确
/*读入到LCM*/
DataByte = DataP /*数据读出到数据口P1 */
return DataB
/***************************/
/***************************/
void WriteData( uchar DataByte )
Locatexy();
/*坐标定位,返回时保留分区状态不变
/*数据输出*/
/*写输出 */
DataPort = DataB /*数据输出到数据口 */
/*写入到LCM*/
void LcmClear( void )
for(Page=0;Page&8;Page++)
for(Col=0;Col&128;Col++)
WriteData(0);
void LcmInit( void )
Delay(200);
//等待复位
WriteCommandL(0x3f);
WriteCommandR(0x3f);
WriteCommandL(0xc0);
//设置起始地址=0
WriteCommandR(0xc0);
WriteCommandL(0x3f);
WriteCommandR(0x3f);
LcmClear();
Locatexy();
void LcmPutBMP( uchar *puts )
for(Page=0;Page&8;Page++)
for(Col=0;Col&128;Col++)
WriteData( puts[X] );
void LcmReverseBMP( void )
for(Page=0;Page&8;Page++)
for(Col=0;Col&128;Col++)
temp = ReadData();
//空读一次
temp = ReadData();
WriteData(temp);
void LcmPutHZ_12( uchar x,uchar y,uchar HZcode )
uchar offset,Rd,Wt,m,tmp,i;
if(x&117&y&53)
Page=(y & 0x38)&&3;
n = 0x18*HZ
offset=y&0x07;
if(offset&5)
for(i=12;i&0;i--)
Rd=ReadData();
Rd=ReadData();
m=HZK_12[n];
Wt=Rd&(0xff&&(8-offset))|(m&&offset);
WriteData(Wt);
m=HZK_12[n];
Rd=ReadData();
Rd=ReadData();
Wt=tmp&&(8-offset)|(m&&offset)|(Rd&(0xff&&(offset+4)));
WriteData(Wt);
for(i=12;i&0;i--)
Rd=ReadData();
Rd=ReadData();
m=HZK_12[n];
Wt=Rd&(0xff&&(8-offset))|(m&&offset);
WriteData(Wt);
m=HZK_12[n];
Wt=tmp&&(8-offset)|(m&&offset);
WriteData(Wt);
Rd=ReadData();
Rd=ReadData();
Wt=m&&(8-offset)|(Rd&(0xff&&(offset-4)));
WriteData(Wt);
Page=Page-2;//恢复位置
Col++; //修正下一个汉字的起始位置
uchar * uchartostr(uchar unm)
uchar x00,xx,x0,x,n;
x00=unm/100;
xx=unm%100;
if(x00!=0)
{ str[n]=x00+48; //值加48即为字符
if(!(x00==0&x0==0))
{ str[n]=x0+48;
str[n]=x+48;
str[n]='';
void LcmPutAsc( uchar asc )
x = 5*(asc-32);
for(j=0;j&5;j++)
WriteData(ASC_5x7[x]);
WriteData(0x00);
void LcmPutstr( uchar row,uchar y,uchar * str )
{ unsigned char *
while(*x!='')
{ LcmPutAsc( *x );
void LcmPutpoint( uchar ro,uchar lie,uchar colour )
//画点函数
if((ro&64)&(lie&128))
uchar modbyte,outB
//列等于lie
Page=(ro & 0x38)&&3;
//页等于行数row与B再右移3位
offsetbit=ro&0x07;
//偏移量为行数与
modbyte=1;
modbyte&&=
//输出位的模左移offsetbit位
outByte=ReadData();
outByte=ReadData();
if(colour==0)
outByte=modbyte&outB
//输出位不影响其它位
else outByte=modbyte|ReadData();
//输出位不影响其它位
WriteData(outByte);
void Delay(uint MS)
while(MS!=0)
while(usn!=0)
while (us!=0){us--;};
//下面是24c016的函数
//**********************************************************
//连线表: CPU=89C51
SysClock=12MHz
//SDL=P1.6
//**********************************************************
/********起始信号*********/
void start_iic()
/*************************/
/********停止信号*********/
void stop_iic()
/***********************/
/*******产生应答信号********/
void ack_iic()
/*************************/
/*****产生非应答信号******/
void nack_iic()
/************************/
/****向总线上发送一个字节数据****/
write_byte(uchar c)
for(i=0;i&8;i++)
if(c&0x80) SDA=1;
else SDA=0;
if(SDA==1) F0=0;
else F0=1;
/*************************/
/*****从总线上读取一个字节数据*******/
uchar read_byte()
uchar r=0;
for(i=0;i&8;i++)
if(SDA==1) r++;
/*******************************/
/****向总线上发送n字节数据*****/
bit write_nbyte(uchar block_addr,uchar addr,uchar *s,uchar numb)
/*****************************
block_addr
存储器的块地址选0-8
存储器的存储地址
一般是用在数组的首地址
要写入的字节数
********************************/
start_iic();
slave=0xa0|(block_addr&&1);
write_byte(slave);
if(F0==0) return 0;
write_byte(addr);
if(F0==0) return 0;
for(i=0;i&i++)
write_byte(*s);
if(F0==0) return 0;
stop_iic();
return (1);
/***************************/
/****从总线上读取n个字节数据***/
bit read_nbyte(uchar block_addr,uchar addr,uchar *s,uchar numb)
/******变量说明:
block_addr
存储器的块地址选0-8
存储器的存储地址
一般是用在数组的首地址
要写入的字节数
start_iic();
slave=0xa0|(block_addr&&1);
write_byte(slave);
if(F0==0) return 0;
write_byte(addr);
if(F0==0) return 0;
start_iic();
slave=0xa1|(block_addr&&1);
write_byte(slave);
if(F0==0) return 0;
for(i=0;i&numb-1;i++)
*s=read_byte();
ack_iic();
*s=read_byte();
nack_iic();
stop_iic();
return (1);
/**************************/
void Main( void )
uchar x,i;
uchar abcd[9];
LcmInit();
LcmClear();
//write_nbyte(0,0,ascii,8);
read_nbyte(0,0,ascii,8);
LcmClear();
LcmPutBMP(BMP1);
Delay(3000);
LcmClear();
//LcmReverseBMP();
Delay(1000);
//LcmClear();
for(i=0;i&8;i++)
LcmPutHZ_12(x,i*7,i);
LcmPutstr( 3,40,ascii );
LcmPutstr( 5,40,"AT24C16!" );
Delay(5000);
unsigned char code BMP1[]={
//字节倒序
//-- 调入一幅图像:E:!Program!BmpSample12864.bmp
//宽度x高度=1264
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x80,0xE0,0xF0,0xFC,0xFE,0xFE,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0x9F,0xCF,0xDF,0x9F,
0x9E,0x3E,0xFF,0xFE,0xFE,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFA,0xFC,0xF8,0xE0,0xC0,0x80,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x80,0xC0,0xF0,0xF8,0xFC,0xFE,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xDF,0xEF,
0xCF,0xDF,0x9F,0x0F,0x1F,0x7F,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFE,0xFC,0xF0,0xC0,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0xC0,0xFC,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x10,0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFD,0xFB,0xFF,
0xFF,0xFF,0xFF,0xFE,0xF8,0xFE,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xBF,0x3F,
0x37,0x37,0x37,0x27,0x63,0x43,0x03,0x03,
0x03,0x03,0x03,0x07,0x67,0x27,0x0F,0x0F,
0x1F,0x3F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0x80,0x80,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x10,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0x7F,0x7F,0x7F,
0x7F,0x7F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,
0x3F,0x3F,0x3F,0x3F,0x3F,0x7F,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x7F,0x3F,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x80,0xE0,0xFC,0xFE,0xFE,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xDF,0x0F,0x07,0x07,0x03,
0x03,0x03,0x03,0x02,0xC0,0xAC,0xBF,0xA0,
0x80,0x00,0x00,0x00,0x02,0x02,0x06,0x06,
0x04,0x00,0x3F,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFE,0xFC,0xF0,0xE0,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x01,0x03,0x07,0x0F,0x1F,0x3F,0x3F,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xBF,0x3F,0x3F,0x3D,
0x7D,0xF8,0xF0,0xF0,0xC0,0x00,0x00,0x00,
0x08,0x8C,0xFC,0xFE,0xEE,0xE6,0xC2,0xC0,
0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x01,
0x1F,0x1F,0x87,0x0D,0x7D,0x70,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xC0,
0xF0,0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFC,0xE0,0x00,
0x00,0x00,0x02,0xE7,0xE7,0xE7,0xE7,0xC3,
0xC3,0xC1,0x82,0x87,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0xE3,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFC,0xF8,0xE0,0xC0,0x80,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,
0x7F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xDF,0x1F,0x1F,0x1F,0x1B,0xF9,
0xF9,0xFF,0xFF,0xFF,0xFF,0x80,0x00,0x00,
0x00,0x01,0x01,0x03,0x03,0x83,0x83,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x01,0x03,0x00,0x00,0x00,0x00,
0xF8,0xFC,0xFC,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFE,0xFC,0xF8,0xFE,0x8F,0x8F,0x0E,0x06,
0x0E,0x0C,0x0C,0x00,0x01,0x00,0x00,0x80,
0xC0,0xF0,0xFC,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,0xFC,
0xF8,0xF0,0xF0,0xE0,0x00,0x00,0x00,0x00,
0x00,0x03,0x07,0x0F,0x1F,0x1F,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFE,0xFC,0xFC,0xFE,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xDF,0xCF,0xDE,
0xD4,0xC2,0x82,0x80,0x80,0x83,0xC7,0xC7,
0x0F,0x04,0x00,0x00,0x00,0x00,0x00,0x00,
0xC0,0xF4,0xFC,0xFC,0xFC,0xFC,0xF8,0xF8,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0x7F,0x3F,0x1F,0x1F,0xDF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x3F,0x1E,
0x1E,0x0E,0x0C,0x04,0x02,0x06,0x1F,0xFF,
0xFF,0xCF,0x0F,0x0F,0x0F,0x1F,0x3F,0x7F,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0x7F,0x1F,0x1F,0x03,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x80,0xC1,0xE7,
0xEF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFB,0xFB,
0xF3,0xF9,0x71,0x31,0x00,0x00,0x00,0x01,
0x00,0x00,0x00,0x00,0x00,0x80,0xE0,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0x03,0x07,0x0F,0x1F,0x1F,0x3F,0x3F,0x1F,
0x1F,0x1F,0x0F,0x4F,0x67,0x27,0x33,0x31,
0x38,0x38,0x78,0x7C,0x7E,0x7F,0x7F,0x7F,
0x7F,0x7F,0x7F,0x7F,0x3F,0x3F,0x7F,0x7F,
0x7F,0x7F,0x7D,0x79,0x79,0x70,0x70,0x70,
0x70,0x70,0x70,0x78,0x78,0x3C,0x5E,0x6F,
0x3F,0x77,0x0F,0x0C,0x7C,0x78,0x78,0x40,
0x00,0x01,0x01,0x03,0x07,0x0F,0x1F,0x1F,
0x1F,0x1F,0x1F,0x1F,0x0F,0x07,0x03,0x00,
0x00,0x00,0x00,0x40,0x60,0x70,0x70,0x78,
0x78,0x7C,0x7E,0x7F,0x7F,0x7F,0x7F,0x7F,
0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,
0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7C,
0x7C,0x7C,0x78,0x78,0x70,0x58,0x00,0x00,
0x40,0x70,0x78,0x7C,0x7F,0x7F,0x7F,0x7F,
0x7F,0x7F,0x07,0x07,0x0F,0x1F,0x3F,0x7F
uchar code ASC_5x7[]={
0x00, 0x00, 0x00, 0x00, 0x00, //
0x00, 0x00, 0x4F, 0x00, 0x00, //
0x00, 0x07, 0x00, 0x07, 0x00, //
0x14, 0x7F, 0x14, 0x7F, 0x14, //
0x24, 0x2A, 0x7F, 0x2A, 0x12, //
0x23, 0x13, 0x08, 0x64, 0x62, //
0x36, 0x49, 0x55, 0x22, 0x50, //
0x00, 0x05, 0x03, 0x00, 0x00, //
0x00, 0x1C, 0x22, 0x41, 0x00, //
0x00, 0x41, 0x22, 0x1C, 0x00, //
0x14, 0x08, 0x3E, 0x08, 0x14, //
0x08, 0x08, 0x3E, 0x08, 0x08, //
0x00, 0x50, 0x30, 0x00, 0x00, //
0x08, 0x08, 0x08, 0x08, 0x00, //
0x00, 0x60, 0x60, 0x00, 0x00, //
0x20, 0x10, 0x08, 0x04, 0x02, //
0x3E, 0x51, 0x49, 0x45, 0x3E, //
0x00, 0x42, 0x7F, 0x40, 0x00, //
0x42, 0x61, 0x51, 0x49, 0x46, //
0x21, 0x41, 0x45, 0x4B, 0x31, //
0x18, 0x14, 0x12, 0x7F, 0x10, //
0x27, 0x45, 0x45, 0x45, 0x39, //
0x3C, 0x4A, 0x49, 0x49, 0x30, //
0x01, 0x01, 0x79, 0x05, 0x03, //
0x36, 0x49, 0x49, 0x49, 0x36, //
0x06, 0x49, 0x49, 0x29, 0x1E, //
0x00, 0x36, 0x36, 0x00, 0x00, //
0x00, 0x56, 0x36, 0x00, 0x00, //
0x08, 0x14, 0x22, 0x41, 0x00, //
0x14, 0x14, 0x14, 0x14, 0x14, //
0x00, 0x41, 0x22, 0x14, 0x08, //
0x02, 0x01, 0x51, 0x09, 0x06, //
0x32, 0x49, 0x79, 0x41, 0x3E, //
0x7E, 0x11, 0x11, 0x11, 0x7E, //
0x41, 0x7F, 0x49, 0x49, 0x36, //
0x3E, 0x41, 0x41, 0x41, 0x22, //
0x41, 0x7F, 0x41, 0x41, 0x3E, //
0x7F, 0x49, 0x49, 0x49, 0x49, //
0x7F, 0x09, 0x09, 0x09, 0x01, //
0x3E, 0x41, 0x41, 0x49, 0x7A, //
0x7F, 0x08, 0x08, 0x08, 0x7F, //
0x00, 0x41, 0x7F, 0x41, 0x00, //
0x20, 0x40, 0x41, 0x3F, 0x01, //
0x7F, 0x08, 0x14, 0x22, 0x41, //
0x7F, 0x40, 0x40, 0x40, 0x40, //
0x7F, 0x02, 0x0C, 0x02, 0x7F, //
0x7F, 0x06, 0x08, 0x30, 0x7F, //
0x3E, 0x41, 0x41, 0x41, 0x3E, //
0x7F, 0x09, 0x09, 0x09, 0x06, //
0x3E, 0x41, 0x51, 0x21, 0x5E, //
0x7F, 0x09, 0x19, 0x29, 0x46, //
0x26, 0x49, 0x49, 0x49, 0x32, //
0x01, 0x01, 0x7F, 0x01, 0x01, //
0x3F, 0x40, 0x40, 0x40, 0x3F, //
0x1F, 0x20, 0x40, 0x20, 0x1F, //
0x7F, 0x20, 0x18, 0x20, 0x7F, //
0x63, 0x14, 0x08, 0x14, 0x63, //
0x07, 0x08, 0x70, 0x08, 0x07, //
0x61, 0x51, 0x49, 0x45, 0x43, //
0x00, 0x7F, 0x41, 0x41, 0x00, //
0x02, 0x04, 0x08, 0x10, 0x20, //
0x00, 0x41, 0x41, 0x7F, 0x00, //
0x04, 0x02, 0x01, 0x02, 0x04, //
0x40, 0x40, 0x00, 0x40, 0x40, //
0x01, 0x02, 0x04, 0x00, 0x00, //
0x20, 0x54, 0x54, 0x54, 0x78, //
0x7F, 0x48, 0x44, 0x44, 0x38, //
0x38, 0x44, 0x44, 0x44, 0x28, //
0x38, 0x44, 0x44, 0x48, 0x7F, //
0x38, 0x54, 0x54, 0x54, 0x18, //
0x00, 0x08, 0x7E, 0x09, 0x02, //
0x0C, 0x52, 0x52, 0x4C, 0x3E, //
0x7F, 0x08, 0x04, 0x04, 0x78, //
0x00, 0x44, 0x7D, 0x40, 0x00, //
0x20, 0x40, 0x44, 0x3D, 0x00, //
0x00, 0x7F, 0x10, 0x28, 0x44, //
0x00, 0x41, 0x7F, 0x40, 0x00, //
0x7C, 0x04, 0x78, 0x04, 0x78, //
0x7C, 0x08, 0x04, 0x04, 0x78, //
0x38, 0x44, 0x44, 0x44, 0x38, //
0x7E, 0x0C, 0x12, 0x12, 0x0C, //
0x0C, 0x12, 0x12, 0x0C, 0x7E, //
0x7C, 0x08, 0x04, 0x04, 0x08, //
0x58, 0x54, 0x54, 0x54, 0x64, //
0x04, 0x3F, 0x44, 0x40, 0x20, //
0x3C, 0x40, 0x40, 0x3C, 0x40, //
0x1C, 0x20, 0x40, 0x20, 0x1C, //
0x3C, 0x40, 0x30, 0x40, 0x3C, //
0x44, 0x28, 0x10, 0x28, 0x44, //
0x1C, 0xA0, 0xA0, 0x90, 0x7C, //
0x44, 0x64, 0x54, 0x4C, 0x44, //
0x00, 0x08, 0x36, 0x41, 0x00, //
0x00, 0x00, 0x77, 0x00, 0x00, //
0x00, 0x41, 0x36, 0x08, 0x00, //
0x02, 0x01, 0x02, 0x04, 0x02, //
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, //
unsigned char code HZK_12[]={
//字节颠倒
//-- 文字: 鹰 --*
//- 宋体11; 此字体下对应的点阵为:宽x高=11x
0x42,0x00,0x22,0x00,0x12,0x00,0xFA,0x07,0x4E,0x01,0x4B,0x01,0x4A,0x01,0x4A,0x05,
0xFA,0x07,0x02,0x00,0x02,0x00,0x00,0x00,/*"有",{0}*/
0x42,0x04,0xAE,0x04,0x93,0x04,0x9A,0x02,0xA6,0x01,0xC0,0x00,0xA6,0x04,0x9A,0x04,
0x8A,0x04,0x96,0x03,0x20,0x00,0x00,0x00,/*"努",{1}*/
0x00,0x04,0x08,0x04,0x08,0x02,0x08,0x01,0xC8,0x00,0x3F,0x00,0x08,0x04,0x08,0x04,
0x08,0x04,0xFC,0x03,0x08,0x00,0x00,0x00,/*"力",{2}*/
0x02,0x02,0xFA,0x01,0x4B,0x04,0xCA,0x07,0x7A,0x01,0x02,0x04,0x08,0x03,0xFF,0x00,
0xC8,0x07,0x0E,0x04,0x08,0x07,0x00,0x00,/*"就",{3}*/
0x42,0x00,0x22,0x00,0x12,0x00,0xFA,0x07,0x4E,0x01,0x4B,0x01,0x4A,0x01,0x4A,0x05,
0xFA,0x07,0x02,0x00,0x02,0x00,0x00,0x00,/*"有",{4}*/
0x00,0x04,0xFC,0x03,0x24,0x01,0x24,0x02,0xE4,0x01,0x04,0x04,0x7F,0x02,0x84,0x01,
0x45,0x02,0x36,0x04,0x04,0x07,0x00,0x00,/*"成",{5}*/
0x02,0x01,0x02,0x01,0xFE,0x00,0x82,0x04,0x82,0x04,0x08,0x02,0x88,0x01,0x7F,0x04,
0x08,0x04,0x08,0x04,0xF8,0x03,0x00,0x00,/*"功",{6}*/
0x00,0x00,0x1C,0x00,0x7E,0x03,0x7E,0x03,0x1C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00/*"!",{7}*/
上面代码的各个函数部分我就不说了,只说说AT24C16的调试,也就是主函数部分:
void Main( void )
uchar x,i;
uchar *   //先定义一个字符型指针变量
uchar abcd[]="iic test";
//定义一个字符数组内容为&iic test&
LcmInit();
LcmClear();
//将字符数组的首地址交给指针变量
write_nbyte(0,0,ascii,8); //向AT24C16写进以ascii为首地址的八个字节数据。
//read_nbyte(0,0,ascii,8); //读AT24C16语句补注释掉了
LcmClear();
LcmPutBMP(BMP1);
Delay(3000);
LcmClear();
//LcmReverseBMP();
Delay(1000);
//LcmClear();
for(i=0;i&8;i++)
LcmPutHZ_12(x,i*7,i);
LcmPutstr( 3,40,ascii );
//向LCD12864显示所定义的字符数组(这时还不是从AT2416内读取的)
LcmPutstr( 5,40,"AT24C16!" );
Delay(5000);
对代码进行编译成HEX文件写入S51后运行:
好!数据已写入AT24C16内,下面修改程序,看看读取出的内容是否正确。
void Main( void )
uchar x,i;
uchar abcd[9];
//定义一个字符数组,内容为空
LcmInit();
LcmClear();
//将字符数组的首地址交给指针变量
//write_nbyte(0,0,ascii,8);
//写AT24C16语句被注释掉
read_nbyte(0,0,ascii,8);
//从AT24C16读取8个字节的数据存入以ascii为首地址的abcd变量内
LcmClear();
LcmPutBMP(BMP1);
Delay(3000);
LcmClear();
//LcmReverseBMP();
Delay(1000);
//LcmClear();
for(i=0;i&8;i++)
LcmPutHZ_12(x,i*7,i);
LcmPutstr( 3,40,ascii );
//显示从AT24C16内读取的内容
LcmPutstr( 5,40,"AT24C16!" );
Delay(5000);
重新编译后写入S51芯片运行:
OK,成功!这次"iic test"这行字符是从AT24C16内读取的。你可以试着拔掉那两根SDA,SCL的数据线,再按下复位键重新运行,你会发现那行&iic test&没有显示了。说明没有读取到数据。再装上数据线,重按复位键运行,又正常了。后面就可以将存储在S51代码段的字模,图形数据等,都写到AT24C16里了。
在网上找到一个写的不错的读写AT24CXXX的通用程序函数,也很好用,程序见下面:
#include &AT89X52.H&
#include &intrins.h&
#define uchar unsigned char
#define uint unsigned int
#define ERRORCOUNT 10
enum eepromtype {M,M,M,M,M24256};
enum eepromtype mT
RW24XX(unsigned char *DataBuff,unsigned char ByteQuantity,unsigned int Address,
unsigned char ControlByte,enum eepromtype mType);
//DataBuff为读写数据输入/输出缓冲区的首址
//ByteQuantity 为要读写数据的字节数量
//Address 为EEPROM的片内地址
//ControlByte 为EEPROM的控制字节,具体形式为(1)(0)(1)(0)(A2)(A1)(A0)(R/W),其中R/W=1,
//表示读操作,R/W=0为写操作,A2,A1,A0为EEPROM的页选或片选地址;
//EepromType为枚举变量,需为M2401至M24256中的一种,分别对应24C01至24C256;
//函数返回值为一个位变量,若返回1表示此次操作失效,0表示操作成功;
//ERRORCOUNT为允许最大次数,若出现ERRORCOUNT次操作失效后,则函数中止操作,并返回1
//SDA和SCL由用户自定义,这里暂定义为P0^0和P0^1;
//其余的用户不用管,只要把只子程序放在你的程序中并调用它就可以了;
/***********************************************************************************/
RW24XX(unsigned char *DataBuff,unsigned char ByteQuantity,unsigned int Address,
unsigned char ControlByte,enum eepromtype mType)
void Delay1(uchar DelayCount);
void IICStart(void);
void IICStop(void);
bit IICRecAck(void);
void IICNoAck(void);
void IICAck(void);
unsigned char IICReceiveByte(void);
void IICSendByte(unsigned char sendbyte);
unsigned char data j,i=ERRORCOUNT;
errorflag=1;
while(i--)
IICStart();
IICSendByte(ControlByte&0xfe);
if(IICRecAck())
if(mType&M2416)
IICSendByte((unsigned char)(Address&&8));
if(IICRecAck())
IICSendByte((unsigned char)Address);
if(IICRecAck())
if(!(ControlByte&0x01))
errorflag=0;
//********clr errorflag
while(j--)
IICSendByte(*DataBuff++);
if(!IICRecAck())
errorflag=1;
if(errorflag==1)
IICStart();
IICSendByte(ControlByte);
if(IICRecAck())
while(--ByteQuantity)
*DataBuff++=IICReceiveByte();
*DataBuff=IICReceiveByte();
//read last byte data
IICNoAck();
errorflag=0;
IICStop();
if(!(ControlByte&0x01))
Delay1(255);
Delay1(255);
Delay1(255);
Delay1(255);
return(errorflag);
/*****************以下是对IIC总线的操作子程序***/
/*****************启动总线**********************/
void IICStart(void)
/*****************停止IIC总线****************/
void IICStop(void)
/**************检查应答位*******************/
bit IICRecAck(void)
//因为返回值总是放在CY中的
return(CY);
/***************对IIC总线产生应答*******************/
void IICACK(void)
/*****************不对IIC总线产生应答***************/
void IICNoAck(void)
/*******************向IIC总线写数据*********************/
void IICSendByte(unsigned char sendbyte)
unsigned char data j=8;
for(;j&0;j--)
sendbyte&&=1;
//无论C51怎样实现这个操作,始终会使CY=sendbyte^7;
/**********************从IIC总线上读数据子程序**********/
unsigned char IICReceiveByte(void)
register receivebyte,i=8;
while(i--)
receivebyte=(receivebyte&&1)|SDA;
return(receivebyte);
/***************一个简单延时程序************************/
void Delay1(uchar DelayCount)
while(--DelayCount);
  但实际使用中发现它有个严重的错误。就是没有考虑到不同的I2C器件在写页操作时,是有一页数据限制的,AT24C01是8个字节,AT24C02-16是16个字节,AT24C33-64是32个字节。AT24C128-256是64个字节。AT24C512是128个字节。AT24C个字节。  这是器件说明书上的资料,我手上只有AT24C02、AT24C16和AT24C256,实际使用了一下,AT24C02的页限制是8个字节。另两个是和说明书上一致的。当我写的数据量超出页限制时,地址指针就会回到起始点覆盖原来的数据。例如我以页方式写10个字节的数据到AT24C02时。前8个字节的数据正常写入,第9、第10个数据就回头覆盖掉了第一、第二个数据。  你如果把265个字节的数据往AT24C02进行写页操作,它也不报错,就一个劲地反复覆盖你8个字节的空间,再比如你往AT24C256里输入一个字节的地址,或往AT24C02里输入两个字节的地址,它也不报错,就这么胡乱地把地址当数据或把数据当成地址往里一阵乱写。当你读取数据时才发现里面混乱不堪。这使得上面那个读写AT24CXXX器件的程序怎么运行都不会出错。我觉得这是AT24CXX器件设计上比较弱智的地方。
所以上面的程序得修改。
感谢关注 Ithao123精品文库频道,是专门为互联网人打造的学习交流平台,全面满足互联网人工作与学习需求,更多互联网资讯尽在 IThao123!
Laravel是一套简洁、优雅的PHP Web开发框架(PHP Web Framework)。它可以让你从面条一样杂乱的代码中解脱出来;它可以帮你构建一个完美的网络APP,而且每行代码都可以简洁、富于表达力。
Hadoop是一个由Apache基金会所开发的分布式系统基础架构。
用户可以在不了解分布式底层细节的情况下,开发分布式程序。充分利用集群的威力进行高速运算和存储。
Hadoop实现了一个分布式文件系统(Hadoop Distributed File System),简称HDFS。HDFS有高容错性的特点,并且设计用来部署在低廉的(low-cost)硬件上;而且它提供高吞吐量(high throughput)来访问应用程序的数据,适合那些有着超大数据集(large data set)的应用程序。HDFS放宽了(relax)POSIX的要求,可以以流的形式访问(streaming access)文件系统中的数据。
Hadoop的框架最核心的设计就是:HDFS和MapReduce。HDFS为海量的数据提供了存储,则MapReduce为海量的数据提供了计算。
产品设计是互联网产品经理的核心能力,一个好的产品经理一定在产品设计方面有扎实的功底,本专题将从互联网产品设计的几个方面谈谈产品设计
随着国内互联网的发展,产品经理岗位需求大幅增加,在国内,从事产品工作的大部分岗位为产品经理,其实现实中,很多从事产品工作的岗位是不能称为产品经理,主要原因是对产品经理的职责不明确,那产品经理的职责有哪些,本专题将详细介绍产品经理的主要职责
IThao123周刊}

我要回帖

更多关于 i2c eeprom 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信