看到很多人在找24Cxx的程序,找了又用不了,干脆拿自己的分享算了。
以下代码功能极其强大,而且使用方便,基本上改几个参数,直接调用就行。至于原理说起来就太长了,只好自己消化吸收。
只能用24c01A~24c16A系列,容量超过的不行
/*
本程序可以一次读和写最多256个字节数据,超出会发生卷页,即从0xff回到0x00
继续写或者读,请注意
本子程序使用方法如下:
先把下面的#define numbyte 改为对应IC型号
调用Write_Flash()和Read_Flash()前,先把page07填好对应的页数,下面的
函数声明处有说明
需要在主程序处定义一些参数,如下:
bit f_rom; //eprom应答标志,=1不应答
uchar xdata epromerr; //用来统计写入出错的次数
uint xdata epadd; //用来作为rom目标写入的首地址,要进行计算
uchar xdata page07; //每256个字节当一页,请注意不要写错页
uchar xdata *ncon; //用来处理写入或读入的缓存地址
uchar xdata len1; //rom第一段数据长度,看eprom.c
uchar xdata len2; //rom中间段数据页数,看eprom.c
uchar xdata len3; //rom末尾段数据长度,看eprom.c
如果不用外部存储器件,把关键字xdata去掉,然后再修改Write_Flash()
和Read_Flash()的声明部分参数
*/
//定义使用的IC,容量超过了这些IC就不能用了
#define d_24c01a 8 //定义IC每一页的字节数
#define d_24c02 8
#define d_24c04 16
#define d_24c08a 16
#define d_24c16a 16
#define numbyte_page d_24c16a
#define WriteDeviceAddress 0xa0 //写驱动地址指令
#define ReadDeviceAddress 0xa1 //读驱动地址指令
void nod2()
{unsigned char i; //4.6us延时
for (i=0;i<13;i++)
_nop_();
}
/*-------------------------------------------------------------
功能:发起始信号
------------------------------------------------------------*/
void Start_Cond()
{
SDA = 1;
nod2();
SCL = 1;
nod2();
SDA = 0;
nod2();
SCL = 0;
nod2();
}
/*-------------------------------------------------------------
功能:发停止信号
------------------------------------------------------------*/
void Stop_Cond()
{
SDA = 0;
nod2();
SCL = 1;
nod2();
SDA = 1;
nod2();
SCL = 0;
nod2();
}
/*-------------------------------------------------------------
功能:发确认信号
------------------------------------------------------------*/
void Ack()
{
SDA = 0;
nod2();
SCL = 1;
nod2();
SCL = 0;
nod2();
SDA = 1;
nod2();
}
/*-------------------------------------------------------------
功能:发无确认信号
------------------------------------------------------------*/
void NoAck()
{
SDA = 1;
nod2();
SCL = 1;
nod2();
SCL = 0;
nod2();
SDA = 0;
nod2();
}
/*-------------------------------------------------------------
功能:读一个字节数据
------------------------------------------------------------*/
unsigned char Read8Bit()
{
unsigned char temp,rbyte=0;
for (temp = 0;temp<8;temp++)
{ SDA=1;
nod2();
SCL = 1;
nod2();
rbyte=(rbyte<<1)|SDA;
SCL = 0;
nod2();
}
return(rbyte);
}
/*-------------------------------------------------------------
功能:写一个字节数据
------------------------------------------------------------*/
Write8Bit(unsigned char input)
{
unsigned char i;
for (i=0;i<8;i++)
{ input <<= 1;
SDA = CY;
nod2();
SCL = 1;
nod2();
SCL = 0;
nod2();
SDA = 0;
nod2();
}
f_rom=0; //chack
SDA=1;
nod2();
nod2();
SCL=1;
nod2();
nod2();
f_rom=SDA;
SCL=0;
nod2();
nod2();
}
/*------------------------------------------------------------
功能:从EEPROM中给定一个地址连续读NLEN个字节数据存放在以指针
nContent开头的往下内容。
写地址为0x000~0x7ff,用参数page07代表最高位的页数(0~7)
------------------------------------------------------------*/
Read_Flash ( unsigned char xdata *nContent, unsigned char nAddr, unsigned int nLen ) large reentrant
{
unsigned char i,j;
//例如目标首地址为5,要写入20个字节,用24c02(每页8个字节)
//那么len1=8-5%8=3,第一页只能读3个字节
//len3=(20-3)%8=1,最后页只能读1个字节
//len2=(20-3-1)/8=2,中间能完整的读2页,刚好20个字节读完
//目标rom首地址离一页末要读的字节数
len1=numbyte_page-nAddr%numbyte_page;
//目标rom最后页读入的字节数
len3=(nLen-len1)%numbyte_page;
//目标rom中间能够完整读入的页数
len2=(nLen-len1-len3)/numbyte_page;
if(len1>nLen) //假如读入长度不足把第一页写完,要更正参数
{ len1=nLen;
len2=0;
len3=0;
}
epromerr=0;
wrstart2:
epromerr++;
ncon=nContent;
if(epromerr>200)
goto errdo2;
//===========================
//读第一段数据
//===========================
Start_Cond();
Write8Bit(WriteDeviceAddress+(page07<<1)); //写写控制字
if(f_rom==1)
goto wrstart2;
Write8Bit(nAddr); //写地址
if(f_rom==1)
goto wrstart2;
Start_Cond();
Write8Bit(ReadDeviceAddress+(page07<<1)); //写读控制字
if(f_rom==1)
goto wrstart2;
if(len1>1) //读第一段数据
{ for(i=0;i<(len1-1);i++)
{ *ncon=Read8Bit();
Ack();
ncon++;
}
}
*ncon=Read8Bit(); //读1个数
NoAck();
ncon++;
Stop_Cond(); //停止
nod2();
//===========================
//读中间段数据
//===========================
if(len2>0)
{ for(j=0;j<len2;j++)
{
epadd=nAddr+(numbyte_page)*j+len1; //修正写入目标偏移地址
Start_Cond();
Write8Bit(WriteDeviceAddress+(page07<<1)); //写写控制字
if(f_rom==1)
goto wrstart2;
Write8Bit(epadd); //写地址
if(f_rom==1)
goto wrstart2;
Start_Cond();
Write8Bit(ReadDeviceAddress+(page07<<1)); //写读控制字
if(f_rom==1)
goto wrstart2;
for(i=0;i<(numbyte_page-1);i++) //读numbyte_page-1个字节
{ *ncon=Read8Bit();
Ack();
ncon++;
}
*ncon=Read8Bit(); //读1个字节
NoAck();
ncon++;
Stop_Cond(); //停止
nod2();
}
}
//===========================
//读末尾段数据
//===========================
if(len3>0)
{ epadd=nAddr+(numbyte_page)*len2+len1; //修正写入目标偏移地址
Start_Cond();
Write8Bit(WriteDeviceAddress+(page07<<1)); //写写控制字
if(f_rom==1)
goto wrstart2;
Write8Bit(epadd); //写地址
if(f_rom==1)
goto wrstart2;
Start_Cond();
Write8Bit(ReadDeviceAddress+(page07<<1)); //写读控制字
if(f_rom==1)
goto wrstart2;
if(len3>1) //读末尾段数据
{ for(i=0;i<(len3-1);i++)
{ *ncon=Read8Bit();
Ack();
ncon++;
}
}
*ncon=Read8Bit(); //读1个数
NoAck();
ncon++;
Stop_Cond(); //停止
nod2();
}
/*
j=0;
restart: j++;
if (j==255)
goto errdo2;
Start_Cond(); //写开始信号
Write8Bit(WriteDeviceAddress); //写写控制字
if(f_rom==1) goto restart;
Write8Bit(nAddr); //写地址
if(f_rom==1) goto restart;
Start_Cond(); //写开始信号
Write8Bit(ReadDeviceAddress); //写读控制字
if(f_rom==1) goto restart;
for(i=0;i<(nLen-1);i++) //读7个数
{ *nContent=Read8Bit();
Ack();
nContent++;
}
*nContent=Read8Bit(); //读1个数
NoAck();
Stop_Cond(); //停止
nod2();
*/
errdo2:;//////////////////////////////////////读数据超时处理
//outr:;
}
/*-------------------------------------------------------------
功能:从EEPROM中给定一个地址nAddr,连续写NLEN个字节数据存放在以指针
nContent开头的往下内容
写地址为0x000~0x7ff,用参数page07代表最高位的页数(0~7)
------------------------------------------------------------*/
Write_Flash ( unsigned char xdata *nContent,unsigned char nAddr, unsigned int nLen) large reentrant
{
//unsigned char epromerr; //用来统计写入出错的次数
unsigned char i,j; //for循坏用
//unsigned char xdata epadd; //用来作为rom目标地址,要进行计算
//unsigned char xdata len1; //rom第一段数据长度,看eprom.c
//unsigned char xdata len2; //rom中间段数据页数,看eprom.c
//unsigned char xdata len3; //rom末尾段数据长度,看eprom.c
//例如目标首地址为5,要写入20个字节,用24c02(每页8个字节)
//那么len1=8-5%8=3,第一页只能写3个字节
//len2=(20-3)%8=1,最后页只能写1个字节
//len3=(20-3-1)/8=2,中间能完整的写2页,刚好20个字节写完
//目标rom首地址离一页末要写的字节数
len1=numbyte_page-nAddr%numbyte_page;
//目标rom最后页写入的字节数
len3=(nLen-len1)%numbyte_page;
//目标rom中间能够完整写入的页数
len2=(nLen-len1-len3)/numbyte_page;
if(len1>nLen) //假如写入长度不足把第一页写完,要更正参数
{ len1=nLen;
len2=0;
len3=0;
}
epromerr=0;
wrstart:
++epromerr;
ncon=nContent; //重新修正缓存对应地址
if(epromerr>200)
goto errdo1;
//===========================
//写第一段数据
//===========================
Start_Cond();
Write8Bit(WriteDeviceAddress+(page07<<1)); //写写控制字
if(f_rom==1)
goto wrstart;
Write8Bit(nAddr); //写地址
if(f_rom==1)
goto wrstart;
for(i=0;i<len1;i++) //写第一段数据
{ Write8Bit(*ncon);
if(f_rom==1)
goto wrstart;
ncon++;
}
Stop_Cond(); //首段写完
//===========================
//写中间的完整段数据
//===========================
if(len2>0)
{ for(j=0;j<len2;j++) //写len2页
{ epadd=nAddr+(numbyte_page)*j+len1; //修正写入目标偏移地址
Start_Cond();
Write8Bit(WriteDeviceAddress+(page07<<1)); //写写控制字
if(f_rom==1)
goto wrstart;
Write8Bit(epadd); //写地址
if(f_rom==1)
goto wrstart;
for(i=0;i<numbyte_page;i++) //写完整的一页
{ Write8Bit(*ncon);
if(f_rom==1)
goto wrstart;
ncon++;
}
Stop_Cond(); //一段写完
}
}
//===========================
//写末尾段数据
//===========================
if(len3>0)
{ epadd=nAddr+(numbyte_page)*len2+len1; //修正写入目标偏移地址
Start_Cond();
Write8Bit(WriteDeviceAddress+(page07<<1)); //写写控制字
if(f_rom==1)
goto wrstart;
Write8Bit(epadd); //写地址
if(f_rom==1)
goto wrstart;
for(i=0;i<len3;i++) //写末尾段数据
{ Write8Bit(*ncon);
if(f_rom==1)
goto wrstart;
ncon++;
}
Stop_Cond(); //末尾段写完
}
errdo1:;
}