//***********************************************************
///读EEPROM的指定单元模块
// 入口参数:addr:待读取数据的地址
// 返回值类型:UCHAR
//***********************************************************
UCHAR Byte_Read(UINT addr)
{
UCHAR TEMPB;
FLASHCON=1;
XPAGE = 0;
TEMPB=*(unsigned char code *)(addr);
FLASHCON=0;
return(TEMPB; // return data
}
//*********************************************************
// 从EEPROM中读出若干数据子程序
// 入口参数:dest:读出后数据的临时存放地址(在RAM中开辟)
// src: 待读取数据的地址
// numbytes:待读取数据的个数
//返回值类型:字节
//*********************************************************
char * FLASH_Read (char *dest, UINT src, unsigned int numbytes)
{
UINT i;
for (i = 0; i < numbytes; i++) {
*dest++ = Byte_Read (src+i);
}
return dest;
}
//**********************************************************
//向EEPROM的指定地址单元写入一个字节模块
//字节编程
//入口参数:addr = 待写入字节地址, byte= 须编程字节的数据
//**********************************************************
void Byte_Write(UINT addr, UCHAR byte)
{
Ssp_Flag=0x5A;
CY=EA;
EA=0; // disable Interrupts during write
FLASHCON=1;
XPAGE = 0; //选择类EEPROM扇区0
IB_OFFSET = addr&0xff;
IB_DATA = byte;
if(Ssp_Flag!=0x5A)
{
IB_CON2=0;
goto Write_Err;
}
IB_CON1 = 0x6E;
IB_CON2 = 0x05;
IB_CON3 = 0x0A;
IB_CON4 = 0x09;
IB_CON5 = 0x06;
_nop_();
_nop_();
_nop_();
_nop_();
Write_Err:
Ssp_Flag=0;
FLASHCON=0;
XPAGE=0;
EA = CY;
}
//*********************************************************
// 向EEPROM中写入若干待存数据子程序
// 入口参数:dest:写入后数据的存放地址
// src: 待写数据的临时存放地址(在RAM中开辟)
// numbytes:待写入数据的个数:
//*********************************************************
void FLASH_Write (UINT dest, char *src, unsigned int numbytes)
{
UINT i;
for (i = dest; i < dest+numbytes; i++) {
Byte_Write (i, *src++);
}
}
//**********************************************************
// 檫除指定的EEPROM页(256字节/每页)子程序
// 擦除扇区, 入口:addr = 扇区地址
//**********************************************************
void Sector_Erase(UCHAR addr)
{
Ssp_Flag=0xA5;
CY=EA;
EA=0;
FLASHCON=1;
XPAGE = addr; //addr=0-->表示檫除第0页
if(Ssp_Flag!=0xA5)
{
IB_CON2=0;
goto Erase_Err;
}
IB_CON1 = 0xE6;
IB_CON2 = 0x05;
IB_CON3 = 0x0A;
IB_CON4 = 0x09;
IB_CON5 = 0x06;
_nop_();
_nop_();
_nop_();
Erase_Err:
Ssp_Flag=0;
FLASHCON=0;
XPAGE=0;
EA = CY;
}
以上例程可以用来写多个整型参数到EEPROM,当然写字节数据肯定也没有问题,写入后读出都正确,重新下载也不会冲掉EEPROM里原有的参数,我已经测试通过,大家可以放心使用。
注意:如果重复写数据到一个扇区里的同一个地址,必须先檫除整个扇区,然后才可以写新数据进去,切记,切记。顺序写多个数据到一个扇区的不同地址,则不需要檫除扇区(前提是这些地址处都没有数据,否则也得先檫除扇区)
后话:刚开始调试老是不成功,看了中颖的数据手册和使用指南都不行,把我搞得头疼。中颖的数据手册说明不是很清楚很到位,中颖人的语文水平太差,哎,搞技术的,英文学的不怎么样,国语怎么也这么差呢。手册里说类EEPROM操作流程有问题啊,比如手册流程如下:
1.关闭中断;
2.按相应的待编程扇区号设置XPAGE,IB_OFFSET;
3.按编程需要,设置IB_DATA;
4.按照顺序,设置IB_CON1-5;
5.添加4个NOP指令;
6.开始编程,CPU进入IDLE模式,编程完成后自动退出IDLE模式;
7.如需继续写入数据,跳转至第3步;
8.XPAGE寄存器清0,恢复中断设置。
其中第7步的说法有问题,如果要继续写入数据,怎么能直接跳转至第3步呢,你连继续要写入的地址都没有更新指明,要跳也应该是跳转至第2步。此类问题还有很多,比如还是8.4节的SSP部分的说明:一旦该扇区被编程,则在该扇区被檫除之前不能被再次编程。这句话说法也有问题:如果我要写入5个整型参数到EEPROM,写了第一个,再写后面的,难道也要先檫除整个扇区,才能继续写后面4个参数吗?我的理解应该是这样:一旦该扇区中的某个地址被编程,想继续在同一个地址编程,必须先檫除整个扇区,才可以在原来的地址编程新数据,如果是在后续地址编程,则不必先檫除整个扇区(前提是后续地址都没有被编程);或者是一旦该扇区256个字节都被编程,想重新在该扇区编程,也必须先檫除该扇区才可以。希望中颖能重新写一下EEPROM流程,我理解的框架思路如下:
1.重复编程数据到同一个地址处,必须先檫除整个扇区,才可以编程;
2.编程多个参数到同一扇区的不同地址,只需更改IB_OFFSET地址即可,不需要檫除整个扇区,除非该扇区都写满了。 |