找回密码
 立即注册

QQ登录

只需一步,快速开始

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

单片机+EEPROM读出保存的变量部都是255

[复制链接]
跳转到指定楼层
楼主
ID:608872 发表于 2021-10-19 17:06 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
      共6个变量,前面4个数据类型unsigned char的变量都能正常读出,说明寄存器设置应该没有问题,但1个数据类型unsigned int和一个unsigned long的变量写入任何数值,读出都是255 是不是因为这两个变量占用4个字节,应该分4次写入,然后4次读出在组合处理呢?如果是这样的话,程序应该怎么改写。

单片机源程序如下:
/**********************************
描  述:写数据到EEPROM保存
功  能:写一字节数据到ISP/IAP/EEPROM区域
**********************************/
void IapProgramByte(u32 addr, u32 dat)
{
    IAP_CONTR = ENABLE_IAP;         //使能IAP
    IAP_CMD = CMD_PROGRAM;          //设置IAP命令
    IAP_ADDRL = addr;               //设置IAP低地址
    IAP_ADDRH = addr >> 8;          //设置IAP高地址
    IAP_DATA = dat;                 //写ISP/IAP/EEPROM数据
    IAP_TRIG = 0x5a;                //写触发命令(0x5a)
    IAP_TRIG = 0xa5;                //写触发命令(0xa5)
    _nop_();                        //等待ISP/IAP/EEPROM操作完成
    IapIdle();                      //关闭IAP功能
}

/**********************************
描  述:读取EEPROM数据
功  能:从ISP/IAP/EEPROM区域读取一字节
**********************************/
u8 IapReadByte(u32 addr)
{
    u32 dat;                       //数据缓冲区
    IAP_CONTR = ENABLE_IAP;         //使能IAP
    IAP_CMD = CMD_READ;             //设置IAP命令
    IAP_ADDRL = addr;               //设置IAP低地址
    IAP_ADDRH = addr >> 8;          //设置IAP高地址
    IAP_TRIG = 0x5a;                //写触发命令(0x5a)
    IAP_TRIG = 0xa5;                //写触发命令(0xa5)
    _nop_();                        //等待ISP/IAP/EEPROM操作完成
    dat = IAP_DATA;                 //读ISP/IAP/EEPROM数据
    IapIdle();                      //关闭IAP功能
    return dat;                     //返回
}

/**********************************
描  述:保存关机前已设置参数
功  能:写入数据到EEPROM
**********************************/
void EEPROM_Data()
{
                IapEraseSector(0);         //ISP/IAP/EEPROM扇区擦除
                IapProgramByte(0,mc1);     //扇区0,数据类型unsigned char 变量范围0-25        
                IapProgramByte(1,mc_jg);   //扇区1,数据类型unsigned char 变量范围0-10
                IapProgramByte(2,mc2);     //扇区2,数据类型unsigned char 变量范围0-25
                IapProgramByte(3,zd_cf);   //扇区3,数据类型unsigned char 变量范围0-10
                IapProgramByte(4,MOS_JS);  //扇区4-7,数据类型unsigned int 变量范围0-99999
                IapProgramByte(8,MCU_V);   //扇区8-11,数据类型unsigned long 变量范围0-1500        
}


/**********************************
描  述:读取EEPROM
功  能:读取上次关机前设置的数据
**********************************/
void EEPROM_init()
{
    mc1=IapReadByte(0);    //扇区0,从ISP/IAP/EEPROM区域读取一字节
    mc_jg=IapReadByte(1);  //扇区1,从ISP/IAP/EEPROM区域读取一字节
    mc2=IapReadByte(2);    //扇区2,从ISP/IAP/EEPROM区域读取一字节
    zd_cf=IapReadByte(3);  //扇区3,从ISP/IAP/EEPROM区域读取一字节
    MOS_JS=IapReadByte(4); //扇区4-7,从ISP/IAP/EEPROM区域读取四字节
    MCU_V=IapReadByte(8);  //扇区8-11从ISP/IAP/EEPROM区域读取四字节         
}
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏1 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:883242 发表于 2021-10-19 18:02 | 只看该作者
unsigned char *p;
*p=&(unsigned char)MOS_JS; //扇区4-7,数据类型unsigned int 变量范围0-99999
IapProgramByte(4,*p++);
IapProgramByte(4,*p++);
IapProgramByte(4,*p++);
IapProgramByte(4,*p++);
回复

使用道具 举报

板凳
ID:130230 发表于 2021-10-19 18:04 | 只看该作者
读出255证明没有写成功
回复

使用道具 举报

地板
ID:624769 发表于 2021-10-19 19:39 | 只看该作者
Eeprom 读写都只能单字节。

你要对 LONG 读写的话要如下这样做子函数

void IapProgramLong(u16 addr, u32 dat)
{
    u8  i;
    IAP_CONTR = ENABLE_IAP;         //使能IAP
    IAP_CMD = CMD_PROGRAM;          //设置IAP命令
    addr+=3;
    for(i=0;i<4;i++)
    {
    IAP_ADDRL = addr;               //设置IAP低地址
    IAP_ADDRH = addr >> 8;          //设置IAP高地址
    IAP_DATA = dat;                 //写ISP/IAP/EEPROM数据
    IAP_TRIG = 0x5a;                //写触发命令(0x5a)
    IAP_TRIG = 0xa5;                //写触发命令(0xa5)
    dat >>=8;
    addr--;
    }
}


u32 IapReadLong(u16 addr)
{
    u8  i;
    u32 dat;                       //数据缓冲区
    IAP_CONTR = ENABLE_IAP;         //使能IAP
    IAP_CMD = CMD_READ;             //设置IAP命令
    for(i=0;i<4;i++)
    {
    IAP_ADDRL = addr;               //设置IAP低地址
    IAP_ADDRH = addr >> 8;          //设置IAP高地址
    IAP_TRIG = 0x5a;                //写触发命令(0x5a)
    IAP_TRIG = 0xa5;                //写触发命令(0xa5)
    dat <<=8;
    dat |= IAP_DATA;                 //读ISP/IAP/EEPROM数据

    addr++;
    }
    return dat;                     //返回
}

回复

使用道具 举报

5#
ID:261025 发表于 2021-10-19 20:13 | 只看该作者
我也遇到过读写错误  用的是12c5a60s2  第一个数据读写正确  第二个数据就错误  不管怎么换地址和给读出写入加延时都没用  换个新的单片机也没用  然后我就放弃了   
回复

使用道具 举报

6#
ID:213173 发表于 2021-10-19 21:01 | 只看该作者
EEPROM只能逐个字节写读,unsigned int和unsigned long型数据要按字节分解后写入,读取后再合并使用。
//共6个变量,前面4个数据类型unsigned char
unsigned char a,b,c,d;
//1个数据类型unsigned int
unsigned int  e;
//1个数据类型unsigned long
unsigned long f;

unsigned char dis_buf[10];//写入缓存
unsigned char dis_buf1[10];//读出缓存

        dis_buf[0]=a;
        dis_buf[1]=b;
        dis_buf[2]=c;
        dis_buf[3]=d;
        dis_buf[4]=e>>8;
        dis_buf[5]=e;
        dis_buf[6]=f>>24;
        dis_buf[7]=f>>16;
        dis_buf[8]=f>>8;
        dis_buf[9]=f;

        IapEraseSector(0x0000);//擦除EEPROM扇区中的数据
        for(i=0;i<10;i++)
        {
                IapProgramByte(0x0000+i,dis_buf[i ]);//重新写入数据
        }
        for(i=0;i<10;i++)
        {
                dis_buf1[i ]=IapReadByte(0x0000+i);//读取EEPROM中数据保存在dis_buf1
        }

以下是多字节读写的示例
  1. //使用芯片 IAP15W4K58S4 测试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);                                        //扇区擦除
  33. void InitUart();                                                                //初始化串口
  34. void SendData(uchar dat);                                                //发送串口数据
  35. void keyscan();
  36. void delayms(uint k);

  37. void main()                                                                                //主函数
  38. {                                                                        
  39.         uchar j;
  40.         P0M0 = 0x00;
  41.         P0M1 = 0x00;
  42.         P1M0 = 0x00;
  43.         P1M1 = 0x00;
  44.         P2M0 = 0x00;
  45.         P2M1 = 0x00;
  46.         P3M0 = 0x00;
  47.         P3M1 = 0x00;
  48.         P4M0 = 0x00;
  49.         P4M1 = 0x00;
  50.         P5M0 = 0x00;
  51.         P5M1 = 0x00;
  52.         P6M0 = 0x00;
  53.         P6M1 = 0x00;
  54.         P7M0 = 0x00;
  55.         P7M1 = 0x00;
  56.         InitUart();                                //初始化串口
  57.         while(1)
  58.         {
  59.                 keyscan();                                //按键程序
  60.                 if(a==1)
  61.                 {
  62.                         for(j=0;j<12;j++)
  63.                         {
  64.                                 SendData(table2[j]);//串口发送
  65.                         }
  66.                         a=0;
  67.                 }
  68.         }
  69. }

  70. void keyscan()                                        //按键扫描程序
  71. {
  72.         uchar i;                                                //临时变量
  73.         if(key==0)
  74.         {
  75.                 delayms(20);
  76.                 if(key==0)
  77.                 {
  78.                         IapEraseSector(0x0000);//擦除EEPROM扇区中的数据
  79.                         for(i=0;i<12;i++)
  80.                         {
  81.                                 IapProgramByte(0x0000+i,table1[i]);//重新写入数据
  82.                         }
  83.                         for(i=0;i<12;i++)
  84.                         {
  85.                                 table2[i]=IapReadByte(0x0000+i);//读取EEPROM中数据保存在table2
  86.                         }
  87.                         while(!key)//等待按键抬起
  88.                         a=1;
  89.                 }
  90.         }
  91. }
  92. /*----------------------------
  93.         关闭IAP功能
  94. ----------------------------*/
  95. void IapIdle()
  96. {
  97.     IAP_CONTR = 0;                  //关闭IAP功能
  98.     IAP_CMD = 0;                    //清除命令寄存器
  99.     IAP_TRIG = 0;                   //清除触发寄存器
  100.     IAP_ADDRH = 0x80;               //将地址设置到非IAP区域
  101.     IAP_ADDRL = 0;
  102. }
  103. /*----------------------------
  104. 从ISP/IAP/EEPROM区域读取一字节
  105. ----------------------------*/
  106. uchar IapReadByte(uint addr)
  107. {
  108.     uchar dat;                       //数据缓冲区

  109.     IAP_CONTR = ENABLE_IAP;         //使能IAP
  110.     IAP_CMD = CMD_READ;             //设置IAP命令
  111.     IAP_ADDRL = addr;               //设置IAP低地址
  112.     IAP_ADDRH = addr >> 8;          //设置IAP高地址
  113.     IAP_TRIG = 0x5a;                //写触发命令(0x5a)
  114.     IAP_TRIG = 0xa5;                //写触发命令(0xa5)
  115.     _nop_();                        //等待ISP/IAP/EEPROM操作完成
  116.     dat = IAP_DATA;                 //读ISP/IAP/EEPROM数据
  117.     IapIdle();                      //关闭IAP功能

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

  176. void SendData(uchar dat)
  177. {
  178.     while (!TI);                 //等待前一个数据发送完成
  179.     TI = 0;                      //清除发送标志
  180.     SBUF = dat;                  //发送当前数据
  181. }
  182. /*-------------------------------
  183.   1ms延时子程序(11.0592MHz 12T)
  184. -------------------------------*/
  185. void delayms(uint k)
  186. {
  187.         uint i,j;
  188.         for(i=k;i>0;i--)
  189.                 for(j=829;j>0;j--);
  190. }



复制代码

回复

使用道具 举报

7#
ID:592807 发表于 2021-10-20 08:30 | 只看该作者
0xff = 255.那是没写成功
回复

使用道具 举报

8#
ID:608872 发表于 2021-10-20 11:33 | 只看该作者
188610329 发表于 2021-10-19 19:39
Eeprom 读写都只能单字节。

你要对 LONG 读写的话要如下这样做子函数

请问你这个程序,读写单字节和多字节变量通用吗,还是单字节用我原来的程序
回复

使用道具 举报

9#
ID:624769 发表于 2021-10-20 11:36 来自手机 | 只看该作者
yinnan128 发表于 2021-10-20 11:33
请问你这个程序,读写单字节和多字节变量通用吗,还是单字节用我原来的程序

不通用,单字节用你原来的。这个读出来就是4字节,写进去也是4字节。
回复

使用道具 举报

10#
ID:139866 发表于 2021-10-21 13:14 | 只看该作者
用示波器看一下时序,很明显就可以看出来的,根据数据手册调整时序
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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