找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 3577|回復(fù): 9
收起左側(cè)

單片機(jī)+EEPROM讀出保存的變量部都是255

[復(fù)制鏈接]
ID:608872 發(fā)表于 2021-10-19 17:06 | 顯示全部樓層 |閱讀模式
      共6個變量,前面4個數(shù)據(jù)類型unsigned char的變量都能正常讀出,說明寄存器設(shè)置應(yīng)該沒有問題,但1個數(shù)據(jù)類型unsigned int和一個unsigned long的變量寫入任何數(shù)值,讀出都是255 是不是因?yàn)檫@兩個變量占用4個字節(jié),應(yīng)該分4次寫入,然后4次讀出在組合處理呢?如果是這樣的話,程序應(yīng)該怎么改寫。

單片機(jī)源程序如下:
/**********************************
描  述:寫數(shù)據(jù)到EEPROM保存
功  能:寫一字節(jié)數(shù)據(jù)到ISP/IAP/EEPROM區(qū)域
**********************************/
void IapProgramByte(u32 addr, u32 dat)
{
    IAP_CONTR = ENABLE_IAP;         //使能IAP
    IAP_CMD = CMD_PROGRAM;          //設(shè)置IAP命令
    IAP_ADDRL = addr;               //設(shè)置IAP低地址
    IAP_ADDRH = addr >> 8;          //設(shè)置IAP高地址
    IAP_DATA = dat;                 //寫ISP/IAP/EEPROM數(shù)據(jù)
    IAP_TRIG = 0x5a;                //寫觸發(fā)命令(0x5a)
    IAP_TRIG = 0xa5;                //寫觸發(fā)命令(0xa5)
    _nop_();                        //等待ISP/IAP/EEPROM操作完成
    IapIdle();                      //關(guān)閉IAP功能
}

/**********************************
描  述:讀取EEPROM數(shù)據(jù)
功  能:從ISP/IAP/EEPROM區(qū)域讀取一字節(jié)
**********************************/
u8 IapReadByte(u32 addr)
{
    u32 dat;                       //數(shù)據(jù)緩沖區(qū)
    IAP_CONTR = ENABLE_IAP;         //使能IAP
    IAP_CMD = CMD_READ;             //設(shè)置IAP命令
    IAP_ADDRL = addr;               //設(shè)置IAP低地址
    IAP_ADDRH = addr >> 8;          //設(shè)置IAP高地址
    IAP_TRIG = 0x5a;                //寫觸發(fā)命令(0x5a)
    IAP_TRIG = 0xa5;                //寫觸發(fā)命令(0xa5)
    _nop_();                        //等待ISP/IAP/EEPROM操作完成
    dat = IAP_DATA;                 //讀ISP/IAP/EEPROM數(shù)據(jù)
    IapIdle();                      //關(guān)閉IAP功能
    return dat;                     //返回
}

/**********************************
描  述:保存關(guān)機(jī)前已設(shè)置參數(shù)
功  能:寫入數(shù)據(jù)到EEPROM
**********************************/
void EEPROM_Data()
{
                IapEraseSector(0);         //ISP/IAP/EEPROM扇區(qū)擦除
                IapProgramByte(0,mc1);     //扇區(qū)0,數(shù)據(jù)類型unsigned char 變量范圍0-25        
                IapProgramByte(1,mc_jg);   //扇區(qū)1,數(shù)據(jù)類型unsigned char 變量范圍0-10
                IapProgramByte(2,mc2);     //扇區(qū)2,數(shù)據(jù)類型unsigned char 變量范圍0-25
                IapProgramByte(3,zd_cf);   //扇區(qū)3,數(shù)據(jù)類型unsigned char 變量范圍0-10
                IapProgramByte(4,MOS_JS);  //扇區(qū)4-7,數(shù)據(jù)類型unsigned int 變量范圍0-99999
                IapProgramByte(8,MCU_V);   //扇區(qū)8-11,數(shù)據(jù)類型unsigned long 變量范圍0-1500        
}


/**********************************
描  述:讀取EEPROM
功  能:讀取上次關(guān)機(jī)前設(shè)置的數(shù)據(jù)
**********************************/
void EEPROM_init()
{
    mc1=IapReadByte(0);    //扇區(qū)0,從ISP/IAP/EEPROM區(qū)域讀取一字節(jié)
    mc_jg=IapReadByte(1);  //扇區(qū)1,從ISP/IAP/EEPROM區(qū)域讀取一字節(jié)
    mc2=IapReadByte(2);    //扇區(qū)2,從ISP/IAP/EEPROM區(qū)域讀取一字節(jié)
    zd_cf=IapReadByte(3);  //扇區(qū)3,從ISP/IAP/EEPROM區(qū)域讀取一字節(jié)
    MOS_JS=IapReadByte(4); //扇區(qū)4-7,從ISP/IAP/EEPROM區(qū)域讀取四字節(jié)
    MCU_V=IapReadByte(8);  //扇區(qū)8-11從ISP/IAP/EEPROM區(qū)域讀取四字節(jié)         
}
回復(fù)

使用道具 舉報(bào)

ID:883242 發(fā)表于 2021-10-19 18:02 | 顯示全部樓層
unsigned char *p;
*p=&(unsigned char)MOS_JS; //扇區(qū)4-7,數(shù)據(jù)類型unsigned int 變量范圍0-99999
IapProgramByte(4,*p++);
IapProgramByte(4,*p++);
IapProgramByte(4,*p++);
IapProgramByte(4,*p++);
回復(fù)

使用道具 舉報(bào)

ID:130230 發(fā)表于 2021-10-19 18:04 | 顯示全部樓層
讀出255證明沒有寫成功
回復(fù)

使用道具 舉報(bào)

ID:624769 發(fā)表于 2021-10-19 19:39 | 顯示全部樓層
Eeprom 讀寫都只能單字節(jié)。

你要對 LONG 讀寫的話要如下這樣做子函數(shù)

void IapProgramLong(u16 addr, u32 dat)
{
    u8  i;
    IAP_CONTR = ENABLE_IAP;         //使能IAP
    IAP_CMD = CMD_PROGRAM;          //設(shè)置IAP命令
    addr+=3;
    for(i=0;i<4;i++)
    {
    IAP_ADDRL = addr;               //設(shè)置IAP低地址
    IAP_ADDRH = addr >> 8;          //設(shè)置IAP高地址
    IAP_DATA = dat;                 //寫ISP/IAP/EEPROM數(shù)據(jù)
    IAP_TRIG = 0x5a;                //寫觸發(fā)命令(0x5a)
    IAP_TRIG = 0xa5;                //寫觸發(fā)命令(0xa5)
    dat >>=8;
    addr--;
    }
}


u32 IapReadLong(u16 addr)
{
    u8  i;
    u32 dat;                       //數(shù)據(jù)緩沖區(qū)
    IAP_CONTR = ENABLE_IAP;         //使能IAP
    IAP_CMD = CMD_READ;             //設(shè)置IAP命令
    for(i=0;i<4;i++)
    {
    IAP_ADDRL = addr;               //設(shè)置IAP低地址
    IAP_ADDRH = addr >> 8;          //設(shè)置IAP高地址
    IAP_TRIG = 0x5a;                //寫觸發(fā)命令(0x5a)
    IAP_TRIG = 0xa5;                //寫觸發(fā)命令(0xa5)
    dat <<=8;
    dat |= IAP_DATA;                 //讀ISP/IAP/EEPROM數(shù)據(jù)

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

回復(fù)

使用道具 舉報(bào)

ID:261025 發(fā)表于 2021-10-19 20:13 | 顯示全部樓層
我也遇到過讀寫錯誤  用的是12c5a60s2  第一個數(shù)據(jù)讀寫正確  第二個數(shù)據(jù)就錯誤  不管怎么換地址和給讀出寫入加延時都沒用  換個新的單片機(jī)也沒用  然后我就放棄了   
回復(fù)

使用道具 舉報(bào)

ID:213173 發(fā)表于 2021-10-19 21:01 | 顯示全部樓層
EEPROM只能逐個字節(jié)寫讀,unsigned int和unsigned long型數(shù)據(jù)要按字節(jié)分解后寫入,讀取后再合并使用。
//共6個變量,前面4個數(shù)據(jù)類型unsigned char
unsigned char a,b,c,d;
//1個數(shù)據(jù)類型unsigned int
unsigned int  e;
//1個數(shù)據(jù)類型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扇區(qū)中的數(shù)據(jù)
        for(i=0;i<10;i++)
        {
                IapProgramByte(0x0000+i,dis_buf[i ]);//重新寫入數(shù)據(jù)
        }
        for(i=0;i<10;i++)
        {
                dis_buf1[i ]=IapReadByte(0x0000+i);//讀取EEPROM中數(shù)據(jù)保存在dis_buf1
        }

以下是多字節(jié)讀寫的示例
  1. //使用芯片 IAP15W4K58S4 測試EEPROM多字節(jié)讀寫,串口發(fā)送數(shù)據(jù)。
  2. #include <STC15F2K60S2.H>
  3. #include <intrins.h>
  4. #define uint unsigned int                                 //宏定義無符號整型數(shù)據(jù)
  5. #define uchar unsigned char                        //宏定義無符號字符型數(shù)據(jù)
  6. //----------宏定義ISP的操作命令---------------------
  7. #define CMD_IDLE    0               //空閑模式
  8. #define CMD_READ    1               //IAP字節(jié)讀命令
  9. #define CMD_PROGRAM 2               //IAP字節(jié)編程命令
  10. #define CMD_ERASE   3               //IAP扇區(qū)擦除命令
  11. //----------宏定義定時器2作為波特率發(fā)生器------------------
  12. #define     URMD    1               //0:使用定時器2作為波特率發(fā)生器
  13.                                     //1:使用定時器1的模式0(16位自動重載模式)作為波特率發(fā)生器
  14.                                     //2:使用定時器1的模式2(8位自動重載模式)作為波特率發(fā)生器                             
  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數(shù)據(jù)緩存
  27. uchar a=0;
  28. /*********************子函數(shù)聲明********************/
  29. void IapIdle();                                                                        //關(guān)閉IAP功能
  30. uchar IapReadByte(uint addr);                                        //讀取一個字節(jié)
  31. void IapProgramByte(uint addr, uchar dat);                //寫一個字節(jié)
  32. void IapEraseSector(uint addr);                                        //扇區(qū)擦除
  33. void InitUart();                                                                //初始化串口
  34. void SendData(uchar dat);                                                //發(fā)送串口數(shù)據(jù)
  35. void keyscan();
  36. void delayms(uint k);

  37. void main()                                                                                //主函數(shù)
  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]);//串口發(fā)送
  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扇區(qū)中的數(shù)據(jù)
  79.                         for(i=0;i<12;i++)
  80.                         {
  81.                                 IapProgramByte(0x0000+i,table1[i]);//重新寫入數(shù)據(jù)
  82.                         }
  83.                         for(i=0;i<12;i++)
  84.                         {
  85.                                 table2[i]=IapReadByte(0x0000+i);//讀取EEPROM中數(shù)據(jù)保存在table2
  86.                         }
  87.                         while(!key)//等待按鍵抬起
  88.                         a=1;
  89.                 }
  90.         }
  91. }
  92. /*----------------------------
  93.         關(guān)閉IAP功能
  94. ----------------------------*/
  95. void IapIdle()
  96. {
  97.     IAP_CONTR = 0;                  //關(guān)閉IAP功能
  98.     IAP_CMD = 0;                    //清除命令寄存器
  99.     IAP_TRIG = 0;                   //清除觸發(fā)寄存器
  100.     IAP_ADDRH = 0x80;               //將地址設(shè)置到非IAP區(qū)域
  101.     IAP_ADDRL = 0;
  102. }
  103. /*----------------------------
  104. 從ISP/IAP/EEPROM區(qū)域讀取一字節(jié)
  105. ----------------------------*/
  106. uchar IapReadByte(uint addr)
  107. {
  108.     uchar dat;                       //數(shù)據(jù)緩沖區(qū)

  109.     IAP_CONTR = ENABLE_IAP;         //使能IAP
  110.     IAP_CMD = CMD_READ;             //設(shè)置IAP命令
  111.     IAP_ADDRL = addr;               //設(shè)置IAP低地址
  112.     IAP_ADDRH = addr >> 8;          //設(shè)置IAP高地址
  113.     IAP_TRIG = 0x5a;                //寫觸發(fā)命令(0x5a)
  114.     IAP_TRIG = 0xa5;                //寫觸發(fā)命令(0xa5)
  115.     _nop_();                        //等待ISP/IAP/EEPROM操作完成
  116.     dat = IAP_DATA;                 //讀ISP/IAP/EEPROM數(shù)據(jù)
  117.     IapIdle();                      //關(guān)閉IAP功能

  118.     return dat;                     //返回
  119. }
  120. /*-------------------------------
  121. 寫一字節(jié)數(shù)據(jù)到ISP/IAP/EEPROM區(qū)域
  122. -------------------------------*/
  123. void IapProgramByte(uint addr, uchar dat)
  124. {
  125.     IAP_CONTR = ENABLE_IAP;         //使能IAP
  126.     IAP_CMD = CMD_PROGRAM;          //設(shè)置IAP命令
  127.     IAP_ADDRL = addr;               //設(shè)置IAP低地址
  128.     IAP_ADDRH = addr >> 8;          //設(shè)置IAP高地址
  129.     IAP_DATA = dat;                 //寫ISP/IAP/EEPROM數(shù)據(jù)
  130.     IAP_TRIG = 0x5a;                //寫觸發(fā)命令(0x5a)
  131.     IAP_TRIG = 0xa5;                //寫觸發(fā)命令(0xa5)
  132.     _nop_();                        //等待ISP/IAP/EEPROM操作完成
  133.     IapIdle();                      //關(guān)閉IAP功能
  134. }
  135. /*----------------------------
  136. ISP/IAP/EEPROM扇區(qū)擦除
  137. ----------------------------*/
  138. void IapEraseSector(uint addr)
  139. {
  140.     IAP_CONTR = ENABLE_IAP;         //使能IAP
  141.     IAP_CMD = CMD_ERASE;            //設(shè)置IAP命令
  142.     IAP_ADDRL = addr;               //設(shè)置IAP低地址
  143.     IAP_ADDRH = addr >> 8;          //設(shè)置IAP高地址
  144.     IAP_TRIG = 0x5a;                //寫觸發(fā)命令(0x5a)
  145.     IAP_TRIG = 0xa5;                //寫觸發(fā)命令(0xa5)
  146.     _nop_();                        //等待ISP/IAP/EEPROM操作完成
  147.     IapIdle();                      //關(guān)閉IAP功能
  148. }
  149. /*-------------------------------------
  150. 初始化串口 晶振18.432MHz 波特率115200
  151. --------------------------------------*/
  152. void InitUart()
  153. {
  154.         SCON = 0x5a;                //設(shè)置串口為8位可變波特率
  155. #if URMD == 0
  156.         T2L = 0xd8;                 //設(shè)置波特率重裝值
  157.         T2H = 0xff;                 //115200 bps(65536-18432000/4/115200)
  158.         AUXR = 0x14;                //T2為1T模式, 并啟動定時器2
  159.         AUXR |= 0x01;               //選擇定時器2為串口1的波特率發(fā)生器
  160. #elif URMD == 1
  161.         AUXR = 0x40;                //定時器1為1T模式
  162.         TMOD = 0x00;                //定時器1為模式0(16位自動重載)
  163.         TL1 = 0xd8;                 //設(shè)置波特率重裝值
  164.         TH1 = 0xff;                 //115200 bps(65536-18432000/4/115200)
  165.         TR1 = 1;                    //定時器1開始啟動
  166. #else
  167.         TMOD = 0x20;                //設(shè)置定時器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. 發(fā)送串口數(shù)據(jù)
  175. ----------------------------*/

  176. void SendData(uchar dat)
  177. {
  178.     while (!TI);                 //等待前一個數(shù)據(jù)發(fā)送完成
  179.     TI = 0;                      //清除發(fā)送標(biāo)志
  180.     SBUF = dat;                  //發(fā)送當(dāng)前數(shù)據(jù)
  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. }



復(fù)制代碼

回復(fù)

使用道具 舉報(bào)

ID:592807 發(fā)表于 2021-10-20 08:30 | 顯示全部樓層
0xff = 255.那是沒寫成功
回復(fù)

使用道具 舉報(bào)

ID:608872 發(fā)表于 2021-10-20 11:33 | 顯示全部樓層
188610329 發(fā)表于 2021-10-19 19:39
Eeprom 讀寫都只能單字節(jié)。

你要對 LONG 讀寫的話要如下這樣做子函數(shù)

請問你這個程序,讀寫單字節(jié)和多字節(jié)變量通用嗎,還是單字節(jié)用我原來的程序
回復(fù)

使用道具 舉報(bào)

ID:624769 發(fā)表于 2021-10-20 11:36 來自手機(jī) | 顯示全部樓層
yinnan128 發(fā)表于 2021-10-20 11:33
請問你這個程序,讀寫單字節(jié)和多字節(jié)變量通用嗎,還是單字節(jié)用我原來的程序

不通用,單字節(jié)用你原來的。這個讀出來就是4字節(jié),寫進(jìn)去也是4字節(jié)。
回復(fù)

使用道具 舉報(bào)

ID:139866 發(fā)表于 2021-10-21 13:14 | 顯示全部樓層
用示波器看一下時序,很明顯就可以看出來的,根據(jù)數(shù)據(jù)手冊調(diào)整時序
回復(fù)

使用道具 舉報(bào)

您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規(guī)則

手機(jī)版|小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術(shù)交流QQ群281945664

Powered by 單片機(jī)教程網(wǎng)

快速回復(fù) 返回頂部 返回列表