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