STC通用EEPROM操作函数(通杀1T,12T系列所有型号,支持连续读/写)
本帖最后由 BXAK 于 2012-5-8 20:35 编辑// data 指片内RAM:0x00~0x7F
// bdata指片内RAM:0x20~0x2F
// idata 指片内RAM:0x00~0xFF
// xdata一般指扩展RAM:0x0000~0xFFFF(也指STC内部扩展RAM:0x0000~0xFFFF)
// code 指程序存储区ROM:0x0000~0xFFFF
自定义数据类型
typedefunsigned charuint8;
typedefunsigned int uint16;
typedefunsigned longuint32;
#define uint8d unsigned char data
#define uint8b unsigned char bdata
#define uint8i unsigned char idata
#define uint8x unsigned char xdata
#define uint8c unsigned char code
EROM_STC.H文件
// 注:连续读、写函数参数最好不使用通用指针,明确指针指向数据类型可以减小代码和提高速度
//
// STC89C52RC EEOPROM大小: 4K,首址:0x2000,触发:0x5A,0xA5
// STC11F01E EEOPROM大小: 2K,首址:0x0000,触发:0x5A,0xA5
// STC12C5410AD EEOPROM大小:12K,首址:0x0000,触发:0x46,0xB9
// STC12C4052 EEOPROM大小:10K,首址:0x0000,触发:0x46,0xB9
// STC12C5A32S2 EEOPROM大小:28K,首址:0x0000,触发:0x5A,0xA5
// STC12C5A60S2 EEOPROM大小: 1K,首址:0x0000,触发:0x5A,0xA5
// STC15F104E EEOPROM大小: 1K,首址:0x0000,触发:0x5A,0xA5
// STC15F204EA EEOPROM大小: 1K,首址:0x0000,触发:0x5A,0xA5
#ifndef __EROM_STC_H__
#define __EROM_STC_H__
#include "STC12C5A60S2.H" //STC头文件
include<intrins.h>
#defineInterEA 1 //主程序中是否使用中断(1:是,0:否)
#defineCPU_Fosc 12000000UL //CPU工作频率
#defineEROM_Start 0x0000 //EEOPROM首址 (不同STC型号有所不同)
#defineEROM_COM 1 //EEOPROM触发命令(不同STC型号有所不同,1:,0:)
extern uint8 EROM_R( uint16 addr ); //读指定地址一字节数据
extern voidEROM_W( uint16 addr, uint8 dat ); //向指定地址写一字节数据
extern voidEROM_C( uint8 n ); //擦除指定扇区
extern voidEROM_R_8( uint16 addr, uint8i *pr, uint16 size ); //连续读数据
extern voidEROM_W_8( uint16 addr, uint8i *pr, uint16 size ); //连续写数据
#endifEROM_STC.c文件
#include "EROM_STC.H"
#if ( EROM_COM == 1 )
#defineCOM0_STC 0x5A
#defineCOM1_STC 0xA5
#else
#defineCOM0_STC 0x46
#defineCOM1_STC 0xB9
#endif
//以下是ISP/IAP操作时间宏定义选项(根据CPU工作频率选择)
#if ( CPU_Fosc <=1000000 )
#defineEN_IAP0x87 //系统时钟 <= 1MHz
#elif ( CPU_Fosc <=2000000 )
#defineEN_IAP0x86 //系统时钟 <= 2MHz
#elif ( CPU_Fosc <=3000000 )
#defineEN_IAP0x85 //系统时钟 <= 3MHz
#elif ( CPU_Fosc <=6000000 )
#defineEN_IAP0x84 //系统时钟 <= 6MHz
#elif ( CPU_Fosc <= 12000000 )
#defineEN_IAP0x83 //系统时钟 <= 12MHz
#elif ( CPU_Fosc <= 20000000 )
#defineEN_IAP0x82 //系统时钟 <= 20MHz
#elif ( CPU_Fosc <= 24000000 )
#defineEN_IAP0x81 //系统时钟 <= 24MHz
#elif ( CPU_Fosc <= 30000000 )
#defineEN_IAP0x80 //系统时钟 <= 30MHz
#else
#defineEN_IAP0x80 //系统时钟 > 30MHz 默认
#endif
/********************************************************************
函数:IAP触发命令 + 禁止IAP操作(清IAP相关寄存器)
********************************************************************/
void Command_and_Close( void )
{
#if( InterEA )
EA = 0;
#endif
IAP_TRIG = COM0_STC;
IAP_TRIG = COM1_STC;
_nop_();
_nop_();
_nop_();
#if( InterEA )
EA = 1;
#endif
IAP_CONTR = 0;
IAP_CMD = 0;
IAP_TRIG= 0;
IAP_ADDRH = 0xFF;
IAP_ADDRL = 0xFF;
}
/********************************************************************
函数:读指定地址一字节数据
输入:(地址)
返回:(地址内容)
********************************************************************/
uint8 EROM_R( uint16 addr )
{
IAP_CONTR = EN_IAP;
IAP_CMD = 1; //允许读取EEPROM
IAP_ADDRL = addr;
IAP_ADDRH = addr >> 8;
Command_and_Close();
return IAP_DATA;
}
/********************************************************************
函数:向指定地址写一字节数据
输入:(地址,数据)
********************************************************************/
void EROM_W( uint16 addr, uint8 dat )
{
IAP_CONTR = EN_IAP;
IAP_CMD = 2; //允许编写EEPROM
IAP_ADDRL = addr;
IAP_ADDRH = addr >> 8;
IAP_DATA= dat;
Command_and_Close();
}
/********************************************************************
函数:擦除指定扇区
输入:(扇区号)
********************************************************************/
void EROM_C( uint8 n )
{
IAP_CONTR = EN_IAP;
IAP_CMD = 3; //允许擦除EEPROM
IAP_ADDRL = 0x00;
IAP_ADDRH = (EROM_Start>>8) + n*0x02;
Command_and_Close();
}
/********************************************************************
函数:连续读数据
输入:(起始地址,指针指向,字节长)
备注:最好不使用通用指针,明确指针指向数据类型可以减小代码和提高速度
********************************************************************/
void EROM_R_8( uint16 addr, uint8i *pr, uint16 size )
{
while( size-- ) {*pr++ = EROM_R( addr++ ); }
}
/********************************************************************
函数:连续写数据
输入:(起始地址,指针指向,字节长)
备注:最好不使用通用指针,明确指针指向数据类型可以减小代码和提高速度
********************************************************************/
void EROM_W_8( uint16 addr, uint8i *pr, uint16 size )
{
while( size-- ) {EROM_W( addr++, *pr++ ); }
} 官方的测试代码就很好用一直用,不过楼主的代码看来也不错! 先mark一下,下次来拿,楼主威武 不错不错啊!!! 过来学习学习 顶一下线 mark一下,很有用 过来学习学习 好代码,试一下! 先顶一下。。。 好东东 够全的吗 有用!记号
有用!记号
程序不错!如有时候,方便给写个使用例子吗?我用12C5A32AD 总是不能读出正确的EEPROM数据!怀疑没有写进去!
例:EROM_W( 0x07, 12 );
delay(10);
aa=EROM_R(0x07);
然后,aa 读出的是00而不是12!
您的原文件我没有改动过,应该可以直接用到12C5A32AD上的
怎么回事呢? xtxtt 发表于 2012-11-2 12:25
程序不错!如有时候,方便给写个使用例子吗?我用12C5A32AD 总是不能读出正确的EEPROM数据!怀疑没有写进去 ...
你试试官网提供的程序看看 顶一下先~~~ 本帖最后由 xtxtt 于 2012-11-3 08:36 编辑
BXAK 发表于 2012-11-2 23:30 static/image/common/back.gif
你试试官网提供的程序看看
你好,官网的可以!也许我哪点搞错了,有空我再试下。。。多谢你!不过。。。这两句不怎么理解。。。
IAP_ADDRL = 0x00;
IAP_ADDRH = (EROM_Start>>8) + n*0x02
能注释下这两句么? xtxtt 发表于 2012-11-3 08:34 static/image/common/back.gif
你好,官网的可以!也许我哪点搞错了,有空我再试下。。。多谢你!不过。。。这两句不怎么理解。。。
I ...
STC一些型号的EEPROM起始地址不同(12T系列EEPROM起始地址差异大),为了兼容这些不同就弄个宏定义,
另,上面的代码我早淘汰不用了,已经更改新的,还有你在写之前要擦除才行
EEPROM.h//※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※
//【列举】
// STC89C52RC EEOPROM大小: 4K,首址:0x2000,触发:0x5A,0xA5
// STC11F01E EEOPROM大小: 2K,首址:0x0000,触发:0x5A,0xA5
// STC12C5410ADEEOPROM大小:12K,首址:0x0000,触发:0x46,0xB9
// STC12C4052 EEOPROM大小:10K,首址:0x0000,触发:0x46,0xB9
// STC12C5A32S2 EEOPROM大小:28K,首址:0x0000,触发:0x5A,0xA5
// STC12C5A60S2 EEOPROM大小: 1K,首址:0x0000,触发:0x5A,0xA5
// STC15F104E EEOPROM大小: 1K,首址:0x0000,触发:0x5A,0xA5
// STC15F204EA EEOPROM大小: 1K,首址:0x0000,触发:0x5A,0xA5
//※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※
// 〖注〗:
//连续读、写函数明确指针指向数据类型可以减小代码和提高速度
//5V单片机在3.7V以下禁止操作EEPROM,而单片机在3.3V以上程序仍可正常运行。
//3.3V单片机在2.4V以下禁止操作EEPROM,而单片机在2.2V以上程序仍可正常运行。
#ifndef __EEPROM_H__
#define __EEPROM_H__
#include "share_basis.H"
#defineUSE_ISR 1 //程序中是否使用中断(1:是,0:否)
#defineREADPointer //连续读函数的指针指向数据类型(方便复制:idata,xdata,code,空:通用指针)
#defineWRITEPointer //连续写函数的指针指向数据类型(方便复制:idata,xdata,code,空:通用指针)
/*=============【载减函数】================*/
#defineUSE_EROM_read_continuous 0
#defineUSE_EROM_write_continuous 0
#defineUSE_EROM_read_word 0
#defineUSE_EROM_write_word 0
/*=========================================*/
extern uint8 EROM_read_byte(uint16 addr); //读指定地址一字节数据
extern voidEROM_write_byte(uint16 addr, uint8 dat); //向指定地址写一字节数据
extern voidEROM_erase_sector(uint8 n); //擦除指定扇区
extern voidEROM_read_continuous(uint16 addr, uint8 READPointer *pr, uint8 len); //连续读出EROM内容到指定缓存
extern voidEROM_write_continuous(uint16 addr, uint8 WRITEPointer *pr, uint8 len); //将缓存内容连续写入EROM
extern uint16 EROM_read_word(uint16 addr); //读指定地址一字数据
extern voidEROM_write_word(uint16 addr, uint16 dat); //向指定地址写一字数据
//************************************************************
// 【 以下宏不要修改 】
//************************************************************
//EEOPROM首址(不同STC型号有所不同)
#if defined (__STC10xxx_H__)\
|| defined (__STC11xxx_H__)\
|| defined (__STC12xx052_H__)\
|| defined (__STC12x52xx_H__)\
|| defined (__STC12x54xx_H__)\
|| defined (__STC12x56xx_H__)\
|| defined (__STC12x5Axx_H__)\
|| defined (__STC15F104E_H__)\
|| defined (__STC15F204EA_H__)
#defineEROM_START 0x0000
#elif defined (__STC90x51_H__)
#defineEROM_START 0x1000
#elif defined (__STC89x51_H__) || defined (__STC89x52_H__) || defined (__STC90x52_H__)
#defineEROM_START 0x2000
#elif defined (__STC90x12_H__)
#defineEROM_START 0x3000
#elif defined (__STC89x54_H__) || defined (__STC90x54_H__)
#defineEROM_START 0x4000
#elif defined (__STC89x58_H__) || defined (__STC90x58_H__)
#defineEROM_START 0x8000
#elif defined (__STC89x510_H__) || defined (__STC90x510_H__)
#defineEROM_START 0xA000
#elif defined (__STC89x512_H__) || defined (__STC90x512_H__)
#defineEROM_START 0xC000
#elif defined (__STC89x514_H__) || defined (__STC90x514_H__)
#defineEROM_START 0xE000
#elif
#warning "STC型号未定义,相应宏定义 EROM_START 缺失"
#endif
//ISP触发命令(不同STC型号有所不同)
#if defined (__STC10xxx_H__)\
|| defined (__STC11xxx_H__)\
|| defined (__STC12x52xx_H__)\
|| defined (__STC12x5Axx_H__)\
|| defined (__STC15F104E_H__)\
|| defined (__STC15F204EA_H__) //STC10xxx, STC11xxx, STC12x5Axx, 12x52xx系列ISP触发命令: 0x5A,0xA5
#defineISPTRIG() ISP_TRIG = 0x5A, ISP_TRIG = 0xA5
#elif defined (__STC89_90xxx_H__)\
|| defined (__STC12xx052_H__)\
|| defined (__STC12x54xx_H__)\
|| defined (__STC12x56xx_H__) //STC89xxx, STC90xxx, STC12xx052, STC12x54xx, STC12x56xx系列ISP触发命令: 0x46,0xB9
#defineISPTRIG() ISP_TRIG = 0x46, ISP_TRIG = 0xB9
#elif
#warning "STC型号未定义,相应宏定义 ISPTRIG() 缺失"
#endif
#if ( CPU_FOSC >= 24000000 )
#defineEN_ISP0x80 //系统时钟 >= 24MHz
#elif ( CPU_FOSC >= 20000000 )
#defineEN_ISP0x81 //系统时钟 >= 20MHz
#elif ( CPU_FOSC >= 12000000 )
#defineEN_ISP0x82 //系统时钟 >= 12MHz
#elif ( CPU_FOSC >=6000000 )
#defineEN_ISP0x83 //系统时钟 >= 6MHz
#elif ( CPU_FOSC >=3000000 )
#defineEN_ISP0x84 //系统时钟 >= 3MHz
#elif ( CPU_FOSC >=2000000 )
#defineEN_ISP0x85 //系统时钟 >= 2MHz
#elif ( CPU_FOSC >=1000000 )
#defineEN_ISP0x86 //系统时钟 >= 1MHz
#else
#defineEN_ISP0x87 //系统时钟 < 1MHz
#endif
#endifEEPROM.c#include "EEPROM.H"
/********************************************************************
函数:IAP触发命令 + 禁止IAP操作(清IAP相关寄存器)
********************************************************************/
static void command_and_close( void )
{
#if (USE_ISR)
EA = 0;
#endif
ISPTRIG();
_nop_();
_nop_();
_nop_();
#if (USE_ISR)
EA = 1;
#endif
ISP_CONTR = 0;
ISP_CMD = 0;
ISP_TRIG= 0;
ISP_ADDRH = 0xFF;
ISP_ADDRL = 0xFF;
}
/********************************************************************
函数:读指定地址一字节数据
输入:(地址)
返回:(地址内容)
********************************************************************/
uint8 EROM_read_byte(uint16 addr)
{
ISP_CONTR = EN_ISP;
ISP_CMD = 1; //允许读取EEPROM
ISP_ADDRL = addr;
ISP_ADDRH = (uint8)(addr>>8) + (uint8)(EROM_START>>8);
command_and_close();
return ISP_DATA;
}
/********************************************************************
函数:向指定地址写一字节数据
输入:(地址,数据)
********************************************************************/
void EROM_write_byte(uint16 addr, uint8 dat)
{
ISP_CONTR = EN_ISP;
ISP_CMD = 2; //允许编写EEPROM
ISP_ADDRL = addr;
ISP_ADDRH = (uint8)(addr>>8) + (uint8)(EROM_START>>8);
ISP_DATA= dat;
command_and_close();
}
/********************************************************************
函数:擦除指定扇区
输入:(扇区号)
********************************************************************/
void EROM_erase_sector(uint8 n)
{
ISP_CONTR = EN_ISP;
ISP_CMD = 3; //允许擦除EEPROM
ISP_ADDRL = 0x00;
ISP_ADDRH = (uint8)(EROM_START>>8) + n*0x02;
command_and_close();
}
/********************************************************************
函数:连续读数据
输入:(起始地址,指针指向,字节长)
********************************************************************/
#if (USE_EROM_read_continuous)
void EROM_read_continuous(uint16 addr, uint8 READPointer *pr, uint8 len)
{
while (len--)
{
*pr = EROM_read_byte(addr);
pr++;
addr++;
}
}
#endif
/********************************************************************
函数:连续写数据
输入:(起始地址,指针指向,字节长)
********************************************************************/
#if (USE_EROM_write_continuous)
void EROM_write_continuous(uint16 addr, uint8 WRITEPointer *pr, uint8 len)
{
while (len--)
{
EROM_write_byte(addr, *pr);
pr++;
addr++;
}
}
#endif
/********************************************************************
函数:读指定地址一字数据
********************************************************************/
#if (USE_EROM_read_word)
uint16 EROM_read_word(uint16 addr)
{
uint16 dat;
((uint8 *)&dat) = EROM_read_byte(addr++);
((uint8 *)&dat) = EROM_read_byte(addr);
return dat;
}
#endif
/********************************************************************
函数:向指定地址写一字数据
********************************************************************/
#if (USE_EROM_write_word)
void EROM_write_word(uint16 addr, uint16 dat)
{
EROM_write_byte(addr++, ((uint8 *)&dat));
EROM_write_byte(addr, ((uint8 *)&dat));
}
#endif 路过,学习下,这是个好东东
mark{:smile:} {:smile:}记号,有用 搞数字电路,都成了软件工程师了 自己只写过两种,不过,看看楼主的,学习哈!~~~ mark mark
MARK,学习了。 听说STC单片机内部EEP不是很稳定,不知道是不是真的。 好东西先收藏 留个记号。 写得不错 虽然没用过STC,但还是记号一下~ mark,学习了,谢咯哈 记号,有用!谢谢 mark,很好 标志下! 记号 必须顶,实用啊! mark 记得有人说过很容易掉数据 不错,高手来的! 很好!学习了! 代码应该能用,但没什么亮点,STC的EEPRON最大的缺点就是片擦除,无论你是要写一个字节还是512字节,都要进行一次片擦除,而且片擦除的时间相当的长,好像是21ms,太长了! 不错的整理。 mark{:handshake:} 我没忍住! 果然好使呀 mark一下,下次来拿,楼主威 我还是菜鸟,看不懂,还得慢慢研究。 好资料,收了备用!!!! MARK STC>>>>>>>>>>>> 值得 学习!赞一个! 好资料正想用,我想把128个数据连续保存在eeprom中,掉电后在调用,看了这个例子,有点思路了,好好研究下{:biggrin:} 你好,“stc通用eeprom操作函数”这个帖子里面你新写的EEPROM.h头文件中有一句#include "share_basis.H",是不是漏掉了,我把你的头文件编译的时候编译不了,麻烦告知一下 楼主新写的eeprom头文件编译不了,能否给个能编译的。我想请教一下怎样把一个数组(128个数)保存在eeprom中,头文件有点复杂,看不明白。 顶啊,好样的 现在都不敢用STC内部的EEPROM啦,会出问题的,多次上电读数据时,几十次会有一次数据全是255,麻烦死了。 mark Mark, mark,以后会用到 这个还是不错的。 markmark!!!!!!!! 真是好东西! 支持字节写不影响同一扇区内的其他内容吗? 收了,谢楼主 学习记号备用,谢谢分享 先mark一下,下次来拿,楼主威武 学习了, 有用, 做个记号吧,但是每次都要擦除扇区,很是坑爹,一个扇区512字节,我要先把里面存的东西都读出来,再擦除,再把读出来的数据和要写入的数据一起写入,极其浪费时间不说,还经常碰到内存没那么大,无法全读出来的情况。。。坑爹啊!!! STC都是扇区修改的,有些麻烦,LZ的程序有参考价值,值得借鉴下~ mask simidaaa!~ 好代码,试一下! 标记,STC,EEPROM读写通用程序 这是个好东西!已用! mark 喜欢下面的代码~ lswhome 发表于 2014-1-31 15:05
做个记号吧,但是每次都要擦除扇区,很是坑爹,一个扇区512字节,我要先把里面存的东西都读出来,再擦除, ...
确实有这种情况,内部RAM不够用,但是需要更新一个扇区内小部分数据,保留大部分数据,就只能在EEPROM开辟一个缓冲区,先把缓冲区擦除,然后转移需要保留的数据,擦除原扇区,写入新数据;在CPU空闲的而且暂时不用中断的时候,擦除缓冲区内容。 mark 有帮助,谢谢! 官网的代码很早就开始拿来用了,楼主自己写的看起来更简洁哈!!! 写代码的风格很好。我见过的代码通杀所有单片机和EEPROM,可惜是我师傅写的,弄不出来源码 很好的东西,解决了我的问题,谢谢分享 不错,谢谢楼主分享 马克xian 看看和滚阿方的有什么不同~~ 谢谢,等下试用一下! 这个有用 通杀所以单片机的也可以做到 不错,学习了~ 不错不错啊!!! 灰常不错啊 mark一下 这个不错挺方便的,谢谢楼主 通用性很好,拷贝下来用哈,谢过。。。。 写得不错 不知為何!見到用 "STCEEPR0M" 的標題就反感!
為和明知都要誤導他人!! 刚好可以用上,测试一下,“拿来主义” 看起来不错,有空试试。 easier 发表于 2016-6-30 11:18
不知為何!見到用 "STCEEPR0M" 的標題就反感!
為和明知都要誤導他人!!
以前认识不足,所以……
而现在久了帖子已经无法再编辑
刚刚用了IAP15F的 芯片EEPROM跟程序空间一起的 !写入的时候 一定要小心!尽量 使用后面的地址,免得把程序给改了 好东西,多谢分享! STC11刚出来的时候,对着规格书写了一个函数一直用到现在,我只需要写几个字节... 好代码,有空要研究一下,现在正好用stc的片子
页:
[1]
2