您的位置:首页 > 其它

STC DATAFLASH 模拟EEPROM

2015-06-27 04:17 274 查看
今天在写STC的EEPROM,一直调不出来结果,但是还是很有收获的,放上代码,慰劳自己一天的努力,主要还是参考STC的开发手册

#include <reg51.h>
#include<intrins.h>

//定义EEPROM的命令
#define CMD_READ    0x01
#define CMD_WRITE   0x02
#define CMD_ERASE   0x03

//定义ISP_CONTR的等待时间和最高位
#define ENABLE_ISP  0x82

//定义FLASH的基地址
#define Sector_BaseAddr     0x2000
#define Sector_EndAddr      0x2fff
#define Sector_BlockSize    16

//定义FLASH的寄存器
sfr ISP_DATA    = 0xe2;//数据寄存器,FLASH的读写都通过这个寄存器
sfr ISP_ADDRH   = 0xe3;//地址高八位寄存器
sfr ISP_ADDRL   = 0xe4;//地址低八位寄存器
sfr ISP_CMD     = 0xe5;//命令寄存器
sfr ISP_TRIG    = 0xe6;//命令触发寄存器
sfr ISP_CONTR   = 0xe7;//控制寄存器

sbit LED = P0^0;
//FLASH在擦除是存储已经存在的数据
static unsigned char FLASH_BUFF[Sector_BlockSize];

//ISP的使能
void ISP_Disable()
{
ISP_CONTR = 0;
ISP_CMD = 0;
ISP_TRIG = 0;

EA = 1;
}

//ISP的命令触发,只有命令触发了,命令才可以执行
void ISP_Trigger()
{
EA = 0;//由于下面两个是一起的,所以先把中断关闭
ISP_TRIG = 0x46;
ISP_TRIG = 0xb9;
_nop_();

}
void ISP_Sector_Erase(unsigned short addr)
{

ISP_CONTR = ENABLE_ISP;
ISP_CMD = CMD_ERASE;

/*
16的地址先向右移动9位,就只有高7位还保持原来的数据
其余的数据都移出去了,再向左移动9位数据,相当于高8位
只有原来的7位数据,低8位都为零
*/
addr = addr & 0xfe00;
ISP_ADDRH = addr >> 8;
ISP_ADDRL = 0x00;

ISP_Trigger();
ISP_Disable();
}
//ISP读一个字节
void ISP_Write_Byte(unsigned short beginaddr,unsigned char pBuf)
{
ISP_CONTR = ENABLE_ISP;//使能控制寄存器
ISP_CMD = CMD_WRITE;//给命令寄存器输入写命令
ISP_ADDRH = beginaddr >> 8;//写入地址
ISP_ADDRL = beginaddr;
ISP_Trigger();//命令触发

ISP_DATA = pBuf;//写入数据

ISP_Disable();//开启中断并且初始化

}

unsigned char ISP_Read_Byte(unsigned short beginaddr)
{
ISP_CONTR = ENABLE_ISP;
ISP_CMD = CMD_READ;

ISP_ADDRH = (unsigned char)(beginaddr >> 8);
ISP_ADDRL = (unsigned char)beginaddr;

ISP_Trigger();

ISP_Disable();

return ISP_DATA;

}
void ISP_Read(unsigned short beginaddr,unsigned char* pBuf,unsigned short nBytes)
{
ISP_CONTR = ENABLE_ISP;
ISP_CMD = CMD_READ;
ISP_DATA=0;
while(nBytes--)
{
ISP_ADDRH = (unsigned char)(beginaddr >> 8);
ISP_ADDRL = (unsigned char)beginaddr;

ISP_Trigger();

*pBuf = ISP_DATA;
if(ISP_DATA == 1) LED = 0;
pBuf++;
beginaddr++;

}
ISP_Disable();
}

void ISP_Write_NoCheck(unsigned short beginaddr,unsigned char* pBuf,unsigned short nBytes)
{
ISP_CONTR = ENABLE_ISP;
ISP_CMD = CMD_WRITE;

while(nBytes--)
{
ISP_ADDRH = beginaddr >> 8;
ISP_ADDRL = beginaddr;
ISP_Trigger();
ISP_DATA = *pBuf;
pBuf++;
beginaddr++;

}
ISP_Disable();
}
void ISP_Write(unsigned short beginaddr,unsigned char* pBuf,unsigned short nBytes)
{
/*
判断是否需要擦除,如果需要找到需要擦除的起始地址
将这个扇区之前的数据先读到缓冲区,待会写入的时候再一起写入,
这样防止擦除扇区的时候将之前的数据被擦除
*/
unsigned short i = 0;
unsigned char sector = (beginaddr - Sector_BaseAddr) / Sector_BlockSize;    //得到扇区号
unsigned short offset = beginaddr - (sector * Sector_BlockSize);            //得到数据在扇区中的偏移
unsigned short remain = Sector_BlockSize - offset;                      //得到余留下来的数据位置

if(nBytes < remain) remain = nBytes;

while(1)
{
ISP_Read(beginaddr & 0xfe00,FLASH_BUFF,Sector_BlockSize);           //将整个扇区的数据读到缓冲区

for(i = 0; i < remain; i++)                                         //将扇区中的数据一一比对
{
if(FLASH_BUFF[offset + i] != 0xff)
break;
}

if(i < remain)//如果中间有不是0xff的地址
{
ISP_Sector_Erase(beginaddr);                                    //检测到有没有清空的地方,擦除整个扇区

for(i = 0; i < remain; i++)                                     //将数据拷贝到缓冲区
{
FLASH_BUFF[offset + i] = pBuf[i];
}
ISP_Write_NoCheck(sector * Sector_BlockSize,FLASH_BUFF,Sector_BlockSize);//将数据全部写入扇区
}
else//否则都是干净的地址
{
ISP_Write_NoCheck(beginaddr,pBuf,remain);//从后面直接写入,就不需要擦除了
}
if(nBytes == remain) break;//如果写入的字节小于一个扇区余留下来的空间,那么一次就写完了,就可以退出来了
else
{
sector++;//下一个扇区
offset = 0;//偏移为0
pBuf += remain;//已经写了remain个字节,所以要偏移一些
beginaddr += remain;//起始地址也偏移
nBytes -= remain;//字节数减少

if(nBytes > Sector_BlockSize) remain = Sector_BlockSize;//如果不能写入到下一个扇区,那就直接写入一个扇区的数据
else remain = nBytes;//如果能的话,那就直接写入剩余的数据
}
}

}

void main()
{
unsigned short addr = 0;
unsigned char msg[5] = {1,2,3,4,2};
unsigned char mm[5];

ISP_Write_NoCheck(0x2c00,msg,5); //写5个数据
ISP_Read(0x2c00,mm,5);//读出这5个数据

if(mm[0] == 1)
{
LED = 0;
}

}


我一直调试到现在,发现读数据是ISP_DATA的数据不会改变,始终都是最后一次写入是的值,而且我将写命令或者读命令去掉,还是正常的。我也试了网上其他人的代码,是一样的结果。不知为何。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: