找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 2916|回复: 6
打印 上一主题 下一主题
收起左侧

stc15f2k60s2单片机eeprom存取程序问题求助

[复制链接]
跳转到指定楼层
楼主
ID:842740 发表于 2021-4-7 00:46 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本人小白,初学单片机
测试数据根据菜单设置保存,上电后数据为上次菜单所保存的,
现遇到此问题,运行时候数据设置没有问题,掉电重新上电后发现数据取出后第一个数据是第三个地址上面的,第二个数据是第一个地址上面的,第三个数据是第二个地址上面的。单独存取一个地址的就没问题,疑惑中?????
部分代码

擦除、读、写等函数
void  cachu(uchar addrH,uchar addrL) //擦除指令
{      
IAP_ADDRL = addrL;  // ISP/IAP操作时的地址寄存器低八位,
    IAP_ADDRH = addrH;  // ISP/IAP操作时的地址寄存器高八位
    IAP_CONTR = 0x84;  
    IAP_CMD   = 0x03; // 用户可以对"Data Flash/EEPROM区"进行扇区擦除
     EA =0;   
    IAP_TRIG  = 0x5A;         
    IAP_TRIG  = 0xA5;         
    _nop_();
     EA = 1;
    guanbi_IAP();     // 关闭ISP/IAP

}
/////////////////////////////////////////////////////////////////////////////////
void xie(uchar addrH,uchar addrL, xxx)   //写
{
IAP_ADDRL = addrL;        
    IAP_ADDRH = addrH;  
    IAP_CONTR = 0x84;                  
    IAP_CMD   = 0x02;              // 用户可以对"Data Flash/EEPROM区"进行字节编程        
    EA = 0;
    IAP_TRIG  = 0x5A;         
    IAP_TRIG  = 0xA5;         
    IAP_DATA  = xxx;          // 数据进ISP_DATA
    _nop_();
   EA = 1;
   guanbi_IAP();                                          // 关闭ISP/IAP
}

uchar du(uchar addrH,uchar addrL)  //读
{   
IAP_ADDRL = addrL;         
    IAP_ADDRH = addrH;  
    IAP_CONTR = 0x84;                  
    IAP_CMD   = 0x01;         // 用户可以对"Data Flash/EEPROM区"进行字节读
IAP_TRIG  = 0x5A;         
    IAP_TRIG  = 0xA5;     
    _nop_();
    guanbi_IAP();                                          // 关闭ISP/IAP                  
    return IAP_DATA;
}

///////////////////////////////////////////////////////////////////////////////////



/////////////////////////////////////////////////////////////////////////////////////////////
void guanbi_IAP()
{

    IAP_CONTR = 0;      //关闭IAP 功能
    IAP_CMD   = 0;      //清命令寄存器,使命令寄存器无命令,此句可不用
    IAP_TRIG = 0;      //清命令触发寄存器,使命令触发寄存器无触发,此句可不用
    IAP_ADDRH = 0;
    IAP_ADDRL = 0;
}

////////////////////////////////////////////////////////////////////////////////////////////////


菜单设置函数
if(open==0)
    {
    if(anjianxiaodou<600)
    {
   mk=3;
    if(mk>130){mk=1;}
    anjianxiaodou=700;
    }
    cachu(0,0);  // 擦除第1个扇区
    xxx=mk;
    xie(0,0,xxx);
    xxx=tjs;
    xie(0,1,xxx);
    xxx=wjs;
    xie(0,2,xxx);          // 对EEPROM区写入

   }
   if(close==0)
    {
    if(anjianxiaodou<600)
    {
    mk=3;
    if(mk<1){mk=130;}
    anjianxiaodou=700;
    }
    cachu(0,0);  // 擦除第1个扇区
      xxx=mk;
      xie(0,0,xxx);
    xxx=tjs;
    xie(0,1,xxx);
    xxx=wjs;
    xie(0,2,xxx);                 // 对EEPROM区2002h写入

   }
   }
  
   break;
  }
  case 2:
  { if(xiajibiaozhi==0)
   {
   qian=15;
   bai=19;
   shi=0;
   ge=1;
   shumaguanxianshi();
     }
     if(caidan==0&&anjianxiaodou>500&&anjianxiaodou<600)
   {  
    xiajibiaozhi=~xiajibiaozhi;
    anjianxiaodou=700;
   }
   if(xiajibiaozhi==1)
   {
    qian=tjs/1000;
    bai=((tjs%1000)/100);
    shi=(((tjs%1000)%100)/10);
    ge=((((tjs%1000)%100)%10)/1);
    shumaguanxianshi();
    if(open==0)
     {
      if(anjianxiaodou<600)
      {
      tjs=6;
      if(tjs>15){tjs=1;}
      anjianxiaodou=700;
      }
    cachu(0,1);  // 擦除第1个扇区
    xxx=mk;
    xie(0,0,xxx);
    xxx=tjs;
    xie(0,1,xxx);
    xxx=wjs;
    xie(0,2,xxx);          // 对EEPROM区写入

    }
   if(close==0)
    {
     if(anjianxiaodou<600)
      {
      tjs=6;
      if(tjs<1){tjs=15;}
      anjianxiaodou=700;
      }
   cachu(0,1);  // 擦除第1个扇区
     xxx=mk;
      xie(0,0,xxx);
    xxx=tjs;
    xie(0,1,xxx);
    xxx=wjs;
    xie(0,2,xxx);          // 对EEPROM区写入

   }
   }
    break;
  }
    case 3:
  {
  if(xiajibiaozhi==0)
   {
   qian=15;
   bai=19;
   shi=0;
   ge=2;
   shumaguanxianshi();
     }
     if(caidan==0&&anjianxiaodou>500&&anjianxiaodou<600)
   {  
    xiajibiaozhi=~xiajibiaozhi;
    anjianxiaodou=700;
   }
   if(xiajibiaozhi==1)
   {
    qian=wjs/1000;
    bai=((wjs%1000)/100);
    shi=(((wjs%1000)%100)/10);
    ge=((((wjs%1000)%100)%10)/1);
    shumaguanxianshi();
    if(open==0)
     {
      if(anjianxiaodou<600)
      {
     wjs=9;
      if(wjs>15){wjs=1;}
      anjianxiaodou=700;
      }
      cachu(0,2);  // 擦除第1个扇区
       xxx=mk;
      xie(0,0,xxx);
    xxx=tjs;
    xie(0,1,xxx);
    xxx=wjs;
    xie(0,2,xxx);          // 对EEPROM区写入

    }
   if(close==0)
    {
     if(anjianxiaodou<600)
      {
     wjs=9;
      if(wjs<1){wjs=15;}
      anjianxiaodou=700;
      }
    cachu(0,2);  // 擦除第1个扇区
      xxx=mk;
      xie(0,0,xxx);
    xxx=tjs;
    xie(0,1,xxx);
    xxx=wjs;
    xie(0,2,xxx);          // 对EEPROM区写入

   }
   }
    break;


上电main函数直接根据地址读出
void main()
{ i=0;y=0;
led=0;
hrzhi= P0 & 0x07 ;
hezhi1=hrzhi;
mk=du(0,0);
tjs=du(0,1);
wjs=du(0,2);

maichong=0;

//////////////////////
读出来的三个数据是相互错的,数值不错,位置错。



分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:213173 发表于 2021-4-7 07:00 | 只看该作者
stc15系列EEPROM一个扇区512字节。第一扇区首地址0x0000,第二扇区首地址0x0200,第三扇区首地址0x0400,第四.........。
写数据前必须以此扇区的首地址开始擦除整个扇区。再按指定扇区内任意地址写数据,通常是按扇区首地址顺序写数据。楼主把地址参数分开写也没啥毛病,但对第1个扇区的擦除在任何情况都应该这样写成cachu(0,0);  其它cachu(0,1); cachu(0,2);写法都是错误的。

评分

参与人数 1黑币 +20 收起 理由
admin + 20 回帖助人的奖励!

查看全部评分

回复

使用道具 举报

板凳
ID:57657 发表于 2021-4-7 07:44 | 只看该作者
写eeprom,1可以写成0,0不能写成1。
擦除扇区可以将0擦除成1,一次擦除512字节。
只有扇区擦除,没有字节擦除。

另外读eeprom可以改成:
  1. uchar code  *eeprom = 0xF000;
复制代码

du() 函数可以注释不要。

评分

参与人数 1黑币 +20 收起 理由
admin + 20 回帖助人的奖励!

查看全部评分

回复

使用道具 举报

地板
ID:842740 发表于 2021-4-7 19:47 | 只看该作者
本帖最后由 18668938020 于 2021-4-7 19:58 编辑
wulin 发表于 2021-4-7 07:00
stc15系列EEPROM一个扇区512字节。第一扇区首地址0x0000,第二扇区首地址0x0200,第三扇区首地址0x0400,第 ...

嗯,明白了,但是还是这个问题弄不明白
程序内部进入菜单1或2或3
改变mk或tjs或wjs变量后执行以下:
cachu(0,0);           // 擦除第1个扇区
      xxx=mk;         //把mk赋值给XXX
      xie(0,0,xxx);   //将XXX也就是mk值写入到0x0000地址里面
     xxx=tjs;          //然后把tjs赋值给XXX
     xie(0,1,xxx);    //将XXX也就是tjs值写入到0x0001地址里面
     xxx=wjs;         //然后把wjs赋值给XXX
     xie(0,2,xxx);    //将XXX也就是wjs值写入到0x0002地址里面



main函数里面
mk=du(0,0);
tjs=du(0,1);
wjs=du(0,2);
读出数据来后
mk设定值在0x01地址里面
tjs设定值在0x02地址里面
wjs设定值在0x00地址里面


不知哪一步出的错



回复

使用道具 举报

5#
ID:213173 发表于 2021-4-7 21:16 | 只看该作者
18668938020 发表于 2021-4-7 19:47
嗯,明白了,但是还是这个问题弄不明白
程序内部进入菜单1或2或3
改变mk或tjs或wjs变量后执行以下:

这是基于STC官方例程改写的多字节EEPROM连续读写测试程序,可以对照查错。对于int型数据可以拆为两个char型数据保存,读取后再合并为一个int型数据。
  1. //测试EEPROM多字节读写,串口发送数据。
  2. #include <STC15F2K60S2.H>
  3. #include <intrins.h>
  4. #define uint unsigned int                         //宏定义无符号整型数据
  5. #define uchar unsigned char                        //宏定义无符号字符型数据
  6. //----------宏定义ISP的操作命令---------------------
  7. #define CMD_IDLE    0               //空闲模式
  8. #define CMD_READ    1               //IAP字节读命令
  9. #define CMD_PROGRAM 2               //IAP字节编程命令
  10. #define CMD_ERASE   3               //IAP扇区擦除命令
  11. //----------宏定义定时器2作为波特率发生器------------------
  12. #define     URMD    1               //0:使用定时器2作为波特率发生器
  13.                                     //1:使用定时器1的模式0(16位自动重载模式)作为波特率发生器
  14.                                     //2:使用定时器1的模式2(8位自动重载模式)作为波特率发生器
  15. /***************CPU的等待时间******************/
  16. //#define ENABLE_IAP 0x80           //if SYSCLK<30MHz
  17. //#define ENABLE_IAP 0x81           //if SYSCLK<24MHz
  18. #define ENABLE_IAP  0x82            //if SYSCLK<20MHz
  19. //#define ENABLE_IAP 0x83           //if SYSCLK<12MHz
  20. //#define ENABLE_IAP 0x84           //if SYSCLK<6MHz
  21. //#define ENABLE_IAP 0x85           //if SYSCLK<3MHz
  22. //#define ENABLE_IAP 0x86           //if SYSCLK<2MHz
  23. //#define ENABLE_IAP 0x87           //if SYSCLK<1MHz

  24. sbit key=P3^4;                                                                //按键1端口定义       

  25. uchar table1[12]={0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C};//测试数据
  26. uchar table2[12];                                        //读取EEPROM缓存
  27. uchar a=0;
  28. /*********************子函数声明********************/
  29. void IapIdle();                                                                        //关闭IAP功能
  30. uchar IapReadByte(uint addr);                                        //读取一个字节
  31. void IapProgramByte(uint addr, uchar dat);                //写一个字节
  32. void IapEraseSector(uint addr);                                        //ISP/IAP/EEPROM扇区擦除
  33. void InitUart();                                                                //初始化串口
  34. void SendData(uchar dat);                                                //发送串口数据
  35. void keyscan();
  36. void Delay10ms();

  37. void main()                                                                                //主函数
  38. {                                                                       
  39.         uchar j;
  40.         InitUart();                                //初始化串口
  41.         while(1)
  42.         {
  43.                 keyscan();                                //按键程序
  44.                 if(a==1)
  45.                 {
  46.                         for(j=0;j<12;j++)
  47.                         {
  48.                                 SendData(table2[j]);//串口发送
  49.                         }
  50.                         a=0;
  51.                 }
  52.         }
  53. }

  54. void keyscan()                                        //按键扫描程序
  55. {
  56.         uchar i;                                                //临时变量
  57.         if(key==0)
  58.         {
  59.                 Delay10ms();
  60.                 if(key==0)
  61.                 {
  62.                         IapEraseSector(0x0000);//擦除EEPROM扇区中的数据
  63.                         for(i=0;i<12;i++)
  64.                         {
  65.                                 IapProgramByte(0x0000+i,table1[i]);//重新写入密码
  66.                         }
  67.                         for(i=0;i<12;i++)
  68.                         {
  69.                                 table2[i]=IapReadByte(0x0000+i);//读取EEPROM中数据保存在table2
  70.                         }
  71.                         while(!key)//等待按键抬起
  72.                         a=1;
  73.                 }
  74.         }
  75. }
  76. /*----------------------------
  77.         关闭IAP功能
  78. ----------------------------*/
  79. void IapIdle()
  80. {
  81.     IAP_CONTR = 0;                  //关闭IAP功能
  82.     IAP_CMD = 0;                    //清除命令寄存器
  83.     IAP_TRIG = 0;                   //清除触发寄存器
  84.     IAP_ADDRH = 0x80;               //将地址设置到非IAP区域
  85.     IAP_ADDRL = 0;
  86. }
  87. /*----------------------------
  88. 从ISP/IAP/EEPROM区域读取一字节
  89. ----------------------------*/
  90. uchar IapReadByte(uint addr)
  91. {
  92.     uchar dat;                       //数据缓冲区

  93.     IAP_CONTR = ENABLE_IAP;         //使能IAP
  94.     IAP_CMD = CMD_READ;             //设置IAP命令
  95.     IAP_ADDRL = addr;               //设置IAP低地址
  96.     IAP_ADDRH = addr >> 8;          //设置IAP高地址
  97.     IAP_TRIG = 0x5a;                //写触发命令(0x5a)
  98.     IAP_TRIG = 0xa5;                //写触发命令(0xa5)
  99.     _nop_();                        //等待ISP/IAP/EEPROM操作完成
  100.     dat = IAP_DATA;                 //读ISP/IAP/EEPROM数据
  101.     IapIdle();                      //关闭IAP功能

  102.     return dat;                     //返回
  103. }
  104. /*-------------------------------
  105. 写一字节数据到ISP/IAP/EEPROM区域
  106. -------------------------------*/
  107. void IapProgramByte(uint addr, uchar dat)
  108. {
  109.     IAP_CONTR = ENABLE_IAP;         //使能IAP
  110.     IAP_CMD = CMD_PROGRAM;          //设置IAP命令
  111.     IAP_ADDRL = addr;               //设置IAP低地址
  112.     IAP_ADDRH = addr >> 8;          //设置IAP高地址
  113.     IAP_DATA = dat;                 //写ISP/IAP/EEPROM数据
  114.     IAP_TRIG = 0x5a;                //写触发命令(0x5a)
  115.     IAP_TRIG = 0xa5;                //写触发命令(0xa5)
  116.     _nop_();                        //等待ISP/IAP/EEPROM操作完成
  117.     IapIdle();                      //关闭IAP功能
  118. }
  119. /*----------------------------
  120. ISP/IAP/EEPROM扇区擦除
  121. ----------------------------*/
  122. void IapEraseSector(uint addr)
  123. {
  124.     IAP_CONTR = ENABLE_IAP;         //使能IAP
  125.     IAP_CMD = CMD_ERASE;            //设置IAP命令
  126.     IAP_ADDRL = addr;               //设置IAP低地址
  127.     IAP_ADDRH = addr >> 8;          //设置IAP高地址
  128.     IAP_TRIG = 0x5a;                //写触发命令(0x5a)
  129.     IAP_TRIG = 0xa5;                //写触发命令(0xa5)
  130.     _nop_();                        //等待ISP/IAP/EEPROM操作完成
  131.     IapIdle();                      //关闭IAP功能
  132. }
  133. /*-------------------------------------
  134. 初始化串口 晶振18.432MHz 波特率115200
  135. --------------------------------------*/
  136. void InitUart()
  137. {
  138.         SCON = 0x5a;                //设置串口为8位可变波特率
  139. #if URMD == 0
  140.         T2L = 0xd8;                 //设置波特率重装值
  141.         T2H = 0xff;                 //115200 bps(65536-18432000/4/115200)
  142.         AUXR = 0x14;                //T2为1T模式, 并启动定时器2
  143.         AUXR |= 0x01;               //选择定时器2为串口1的波特率发生器
  144. #elif URMD == 1
  145.         AUXR = 0x40;                //定时器1为1T模式
  146.         TMOD = 0x00;                //定时器1为模式0(16位自动重载)
  147.         TL1 = 0xd8;                 //设置波特率重装值
  148.         TH1 = 0xff;                 //115200 bps(65536-18432000/4/115200)
  149.         TR1 = 1;                    //定时器1开始启动
  150. #else
  151.         TMOD = 0x20;                //设置定时器1为8位自动重装载模式
  152.         AUXR = 0x40;                //定时器1为1T模式
  153.         TH1 = TL1 = 0xfb;           //115200 bps(256 - 18432000/32/115200)
  154.         TR1 = 1;
  155. #endif
  156. }
  157. /*----------------------------
  158. 发送串口数据
  159. ----------------------------*/

  160. void SendData(uchar dat)
  161. {
  162.     while (!TI);                 //等待前一个数据发送完成
  163.     TI = 0;                      //清除发送标志
  164.     SBUF = dat;                  //发送当前数据
  165. }
  166. /*-------------------------------
  167.   10ms延时子程序(@18.432MHz)
  168. -------------------------------*/
  169. void Delay10ms()
  170. {
  171.         unsigned char i, j, k;

  172.         _nop_();
  173.         _nop_();
  174.         i = 1;
  175.         j = 180;
  176.         k = 71;
  177.         do
  178.         {
  179.                 do
  180.                 {
  181.                         while (--k);
  182.                 } while (--j);
  183.         } while (--i);
  184. }




复制代码



回复

使用道具 举报

6#
ID:842740 发表于 2021-4-8 20:39 | 只看该作者
问题已解决,原因是读写子程序里面应该先写IAP_CONTR 和IAP_CMD ,再写地址,颠倒后相当于把设置数值送到下一个地址了,谢谢以上两位老师指导
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表