STC DATAFLASH 模拟EEPROM

今天在写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的数据不会改变,始终都是最后一次写入是的值,而且我将写命令或者读命令去掉,还是正常的。我也试了网上其他人的代码,是一样的结果。不知为何。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值