zengdz 发表于 2012-2-17 18:25:51

STC内部EEPROM怎么存入多组数据

这是STC的EEPROM测试程序,程序中只是写入了一个数据进去。如果要存入多组变量呢?比如一个时钟的年月日时分这些变量,怎么存入以便断电能够保存。以及如果存入的是大于255的数据,又该怎么处理呢
请指教、

#include <reg51.H>
#include <intrins.H>
typedef unsigned charINT8U;
typedef unsigned int   INT16U;
sfr IAP_DATA    = 0xC2;
sfr IAP_ADDRH   = 0xC3;
sfr IAP_ADDRL   = 0xC4;
sfr IAP_CMD   = 0xC5;
sfr IAP_TRIG    = 0xC6;
sfr IAP_CONTR   = 0xC7;

#define ENABLE_ISP 0x82 //系统工作时钟<20MHz 时,对IAP_CONTR 寄存器设置此值

#define DEBUG_DATA               0x5A//本测试程序最终存储在 EEPROM 单元的数值
#define DATA_FLASH_START_ADDRESS 0x00//STC5Axx 系列 EEPROM 测试起始地址

union union_temp16
{
    INT16U un_temp16;
    INT8Uun_temp8;
}my_unTemp16;

INT8U Byte_Read(INT16U add);            //读一字节,调用前需打开IAP 功能
void Byte_Program(INT16U add, INT8U ch);//字节编程,调用前需打开IAP 功能
void Sector_Erase(INT16U add);            //擦除扇区
void IAP_Disable();                     //关闭IAP 功能
void Delay();

void main (void)
{
    INT16U eeprom_address;
    INT8Uread_eeprom;

    P1 = 0xF0;                            //演示程序开始,让 P1 控制的灯亮
    Delay();                              //延时
    P1 = 0x0F;                            //演示程序开始,让 P1 控制的灯亮
    Delay()    ;                        //延时

    //将EEPROM 测试起始地址单元的内容读出
    eeprom_address = DATA_FLASH_START_ADDRESS;//将测试起始地址送eeprom_address
    read_eeprom = Byte_Read(eeprom_address);    //读EEPROM的值,存到read_eeprom

    if (DEBUG_DATA == read_eeprom)
    {   //数据是对的,亮P1.7 控制的灯,然后在 P1 口上将 EEPROM 的数据显示出来
      P1 = ~0x80;
      Delay()    ;                            //延时
      P1 = ~read_eeprom;
    }
    else
    {   //数据是错的,亮 P1.3 控制的灯,然后在 P1 口上将 EEPROM 的数据显示出来
      //再将该EEPROM所在的扇区整个擦除,将正确的数据写入后,亮 P1.5 控制的灯
      P1 = ~0x08;
      Delay()    ;                            //延时
      P1 = ~read_eeprom;
      Delay()    ;                            //延时

      Sector_Erase(eeprom_address);         //擦除整个扇区
      Byte_Program(eeprom_address, DEBUG_DATA);//将 DEBUG_DATA 写入 EEPROM

      P1 = ~0x20;               //熄灭 P1.3 控制的灯,亮 P1.5 控制的灯
    }

    while (1);                      //CPU 在此无限循环执行此句
}

//读一字节,调用前需打开IAP 功能,入口:DPTR = 字节地址,返回:A = 读出字节
INT8U Byte_Read(INT16U add)
{
    IAP_DATA = 0x00;
    IAP_CONTR = ENABLE_ISP;         //打开IAP 功能, 设置Flash 操作等待时间
    IAP_CMD = 0x01;               //IAP/ISP/EEPROM 字节读命令

    my_unTemp16.un_temp16 = add;
    IAP_ADDRH = my_unTemp16.un_temp8;    //设置目标单元地址的高8 位地址
    IAP_ADDRL = my_unTemp16.un_temp8;    //设置目标单元地址的低8 位地址

    //EA = 0;
    IAP_TRIG = 0x5A;   //先送 5Ah,再送A5h 到ISP/IAP 触发寄存器,每次都需如此
    IAP_TRIG = 0xA5;   //送完A5h 后,ISP/IAP 命令立即被触发起动
    _nop_();
    //EA = 1;
    IAP_Disable();//关闭IAP 功能, 清相关的特殊功能寄存器,使CPU 处于安全状态,
                  //一次连续的IAP 操作完成之后建议关闭IAP 功能,不需要每次都关
    return (IAP_DATA);
}

//字节编程,调用前需打开IAP 功能,入口:DPTR = 字节地址, A= 须编程字节的数据
void Byte_Program(INT16U add, INT8U ch)
{
    IAP_CONTR = ENABLE_ISP;         //打开 IAP 功能, 设置Flash 操作等待时间
    IAP_CMD = 0x02;               //IAP/ISP/EEPROM 字节编程命令

    my_unTemp16.un_temp16 = add;
    IAP_ADDRH = my_unTemp16.un_temp8;    //设置目标单元地址的高8 位地址
    IAP_ADDRL = my_unTemp16.un_temp8;    //设置目标单元地址的低8 位地址

    IAP_DATA = ch;                  //要编程的数据先送进IAP_DATA 寄存器
    //EA = 0;
    IAP_TRIG = 0x5A;   //先送 5Ah,再送A5h 到ISP/IAP 触发寄存器,每次都需如此
    IAP_TRIG = 0xA5;   //送完A5h 后,ISP/IAP 命令立即被触发起动
    _nop_();
    //EA = 1;
    IAP_Disable();//关闭IAP 功能, 清相关的特殊功能寄存器,使CPU 处于安全状态,
                  //一次连续的IAP 操作完成之后建议关闭IAP 功能,不需要每次都关
}

//擦除扇区, 入口:DPTR = 扇区地址
void Sector_Erase(INT16U add)
{
    IAP_CONTR = ENABLE_ISP;         //打开IAP 功能, 设置Flash 操作等待时间
    IAP_CMD = 0x03;               //IAP/ISP/EEPROM 扇区擦除命令

    my_unTemp16.un_temp16 = add;
    IAP_ADDRH = my_unTemp16.un_temp8;    //设置目标单元地址的高8 位地址
    IAP_ADDRL = my_unTemp16.un_temp8;    //设置目标单元地址的低8 位地址

    //EA = 0;
    IAP_TRIG = 0x5A;   //先送 5Ah,再送A5h 到ISP/IAP 触发寄存器,每次都需如此
    IAP_TRIG = 0xA5;   //送完A5h 后,ISP/IAP 命令立即被触发起动
    _nop_();
    //EA = 1;
    IAP_Disable();//关闭IAP 功能, 清相关的特殊功能寄存器,使CPU 处于安全状态,
                  //一次连续的IAP 操作完成之后建议关闭IAP 功能,不需要每次都关
}

void IAP_Disable()
{
    //关闭IAP 功能, 清相关的特殊功能寄存器,使CPU 处于安全状态,
    //一次连续的IAP 操作完成之后建议关闭IAP 功能,不需要每次都关
    IAP_CONTR = 0;      //关闭IAP 功能
    IAP_CMD   = 0;      //清命令寄存器,使命令寄存器无命令,此句可不用
    IAP_TRIG= 0;      //清命令触发寄存器,使命令触发寄存器无触发,此句可不用
    IAP_ADDRH = 0;
    IAP_ADDRL = 0;
}

void Delay()
{
    INT8U i;
    INT16U d=5000;
    while (d--)
    {
      i=255;
      while (i--);
    }
}

ckvlhf 发表于 2012-2-17 19:17:36

就一个个的写进去嘛,还能怎么样呢。自己想的太复杂了?

xiaobendan001 发表于 2012-2-17 19:42:58

9494

dupeiyuan 发表于 2012-2-17 19:57:17

还是C 没学好啊

zengdz 发表于 2012-2-17 19:57:34

回复【1楼】ckvlhf
-----------------------------------------------------------------------

试过了,主要是不清楚多个数据存哪去,对地址不清楚

downtoearth 发表于 2012-2-18 00:02:09

我也想了解,怎样写进多的数据,和读多个数据。关注!

heiyuu1 发表于 2012-2-18 00:34:00

uint eep2=0x200,eep4=0x400;//定义扇区,请看stc官方pdf,扇区介绍,不同款mcu的扇区大小位置都不同;

以下定义的都为uint值,都可以存入一个字节;
///////////////////////////////////////////////////////////////
void save_day_run(uint d)                        //写入定时的时间信息,不用修改了
{             Byte_Program(eep4+(d*6), hour_con_day);   
                   Byte_Program(eep4+(d*6)+1, minute_con_day);          
                   Byte_Program(eep4+(d*6)+2, second_con_day);        
                   Byte_Program(eep4+(d*6)+3, time_signal);        //信号位
                   Byte_Program(eep4+(d*6)+4, week_con_day);                   //周次
                   Byte_Program(eep4+(d*6)+5, 0xaa);                        //判断位

}



void read_day_run(uint d)                  //读取定时的时间信息,不用修改了        用于执行
{                hour_con_day1 =    Byte_Read(eep4+(d*6));
      minute_con_day1 =Byte_Read(eep4+(d*6)+1);
      second_con_day1 =Byte_Read(eep4+(d*6)+2);
      time_signal1 =   Byte_Read(eep4+(d*6)+3);
      week_con_day1 =    Byte_Read(eep4+(d*6)+4);
}

void read_day_save(uint d)                  //读取定时的时间信息       用于读取 反馈
{                hour_re_day1 =    Byte_Read(eep4+(d*6));
      minute_re_day1 =Byte_Read(eep4+(d*6)+1);
      second_re_day1 =Byte_Read(eep4+(d*6)+2);
      time_re_signal1 = Byte_Read(eep4+(d*6)+3);
      week_re_day1 =    Byte_Read(eep4+(d*6)+4);
}


这个d的值就自己去猜了吧
再有不清楚的再问,忘了很多事情了,最近搞cpu(不是mcu)搞的头痛;

heiyuu1 发表于 2012-2-18 00:36:13

还有这个eeprorm是必须先擦除扇区再写入的哦

xiaobendan001 发表于 2012-2-18 07:27:58

给你我用的两个函数,用在12C5205AD上面的很好用,可惜这个破片子只有两个扇区,调用时第一个参数只能是0x00或者0x02。第二个参数是要存入的所谓EEPROM的地址,建议放弃0x00地址。第三个参数是你要存的数据在RAM的地址,对于int或者char,可以用&获得,对于数组就是数组的名称。第四个参数是要存的数据长度,可以使用sizeof()获得。这样讲应该明白了吧。
void read(uchar sq,unsigned char * eadd,unsigned char * nbadd,unsigned char size){
unsigned char i = size;
EA = 0;
while(i--){
        IAP_ADDRH = sq;                          //0x10=使用第9扇区
        IAP_ADDRL = (char)eadd;
        IAP_CONTR = 0x80|IAP_WAIT_TIME;                        //11M
        IAP_CMD   = IAP_BYTE_READ;                                        //读命令
        IAP_TRIG= 0x5A;IAP_TRIG= 0xA5;                        //启动IAP
        *nbadd = IAP_DATA;
        nbadd++;eadd++;
        }
IAP_CONTR = 0;
IAP_CMD   = 0;
IAP_TRIG= 0;
IAP_ADDRH = 0xff;                                //重新指向第0扇区
EA = 1;
}
void save(uchar sq,unsigned char *eadd,unsigned char *nbadd,unsigned char size){
unsigned char i = size;
EA = 0;
weism |= dig;                //消隐
IAP_CONTR = 0x80|IAP_WAIT_TIME;                        //11M
IAP_ADDRH = sq;                                        //0x10=第9扇区
IAP_ADDRL = 0x00;
IAP_CMD   = IAP_SECTOR_ERASE;                                //擦除命令
IAP_TRIG= 0x5A;IAP_TRIG= 0xA5;                        //启动IAP
while(i--){
        IAP_ADDRH = sq;
        IAP_ADDRL = (char)eadd;
//        IAP_CONTR = 0x80|IAP_WAIT_TIME;                        //11M
        IAP_CMD   = IAP_BYTE_PROG;                                        //写入命令
        IAP_DATA = *nbadd;
        IAP_TRIG= 0x5A;IAP_TRIG= 0xA5;                        //启动IAP
        nbadd++;eadd++;
        }
IAP_CONTR = 0;                                                                        //关闭IAP
IAP_CMD   = 0;
IAP_TRIG= 0;
IAP_ADDRH = 0xff;                                //重新指向第0扇区
EA = 1;
}

wtiechen1969 发表于 2012-2-18 08:32:23

make

zengdz 发表于 2012-2-18 13:18:45

回复【6楼】heiyuu1
-----------------------------------------------------------------------

多谢,我去试下,不清楚再来

zengdz 发表于 2012-2-18 13:21:25

回复【8楼】xiaobendan001
-----------------------------------------------------------------------

多谢,你给的在89C52上应该没问题吧,去试试先

xiaobendan001 发表于 2012-2-18 16:45:40

这个没有试过,是STC的吗?要注意它的一些寄存器的定义是不同的。

zengdz 发表于 2012-2-18 19:34:55

问题解决了,谢谢大家的解答。使用结构体就可以存入多组变量了。

jjj2012 发表于 2012-5-8 20:16:02

我也在用,但是写入和读出的数据是不一样的,使用的是数组,现在难住了,不知道怎么办

BXAK 发表于 2012-5-8 20:59:03

用“ 数组 ”或者“ 结构体 ”

【 数组 】例如:

uint8 BUF;
uint8 N;

EROM_C( 1 );                              //擦除扇区1(0x0200 ~ 0x02FF)
EROM_W_8( 0x0230, BUF, 100 );    //将数组BUF依次写入EEPROM从0x0230开始的连续100个单元

EROM_R_8( 0x0230, BUF, 100);    //读出EEPROM从0x0230开始的连续100个单元写入数组BUF

EROM_R_8( 0x0290, N, 10);         //读出EEPROM从0x0290开始的连续10个单元写入数组N

【 结构体 】例如:

structSTR_1   
{
        uint8 sec;
        uint8 min;
        uint8 hour;
        uint8 day;
        uint8 month;
        uint8 week;
        uint8 year;
} data NOW;

EROM_C( 0 );                                     //擦除扇区0(0x0000 ~ 0x01FF)
EROM_W_8( 0x0000, &NOW.sec, 7 );   //将结构体中的秒、分、时、日、月、星期、年这7个数据依次写入EEPROM从0x0000开始的连续7个单元

EROM_R_8( 0x0000, &NOW.sec, 7 );    //读出EEPROM从0x0000开始的连续7个单元写入结构体

具体程序:STC通用EEPROM操作函数(通杀1T、12T系列所有型号,支持连续读/写)

zengdz 发表于 2012-5-9 17:27:06

BXAK 发表于 2012-5-8 20:59 static/image/common/back.gif
用“ 数组 ”或者“ 结构体 ”

【 数组 】例如:


谢谢你的解答,看了你的帖子,果然是通杀呀、
页: [1]
查看完整版本: STC内部EEPROM怎么存入多组数据