xxkj2010 发表于 2025-7-7 18:15:47

写EEPROM遇到的问题

芯片用stc8h2k12u,代码用AIapp-ISP-v6.95W中的范例修改#include "reg51.h"
#include "intrins.h"

#define FOSC      11059200UL
#define BRT         (65536 - FOSC / 115200 / 4)

sfr   P0M1    =   0x93;
sfr   P0M0    =   0x94;
sfr   P1M1    =   0x91;
sfr   P1M0    =   0x92;
sfr   P2M1    =   0x95;
sfr   P2M0    =   0x96;
sfr   P3M1    =   0xb1;
sfr   P3M0    =   0xb2;
sfr   P4M1    =   0xb3;
sfr   P4M0    =   0xb4;
sfr   P5M1    =   0xc9;
sfr   P5M0    =   0xca;

sfr   AUXR    =   0x8e;
sfr   T2H   =   0xd6;
sfr   T2L   =   0xd7;

sfr   IAP_DATA    =   0xC2;
sfr   IAP_ADDRH   =   0xC3;
sfr   IAP_ADDRL   =   0xC4;
sfr   IAP_CMD   =   0xC5;
sfr   IAP_TRIG    =   0xC6;
sfr   IAP_CONTR   =   0xC7;
sfr   IAP_TPS   =   0xF5;

void Delay1000ms(void)      //@11.0592MHz
{
      unsigned char data i, j, k;

      i = 57;
      j = 27;
      k = 112;
      do
      {
                do
                {
                        while (--k);
                } while (--j);
      } while (--i);
}



void UartInit()
{
    SCON = 0x5a;
    T2L = BRT;
    T2H = BRT >> 8;
    AUXR = 0x15;
}

void UartSend(char dat)
{
    while (!TI);
    TI = 0;
    SBUF = dat;
}

void IapIdle()
{
    IAP_CONTR = 0;                              //关闭IAP功能
    IAP_CMD = 0;                              //清除命令寄存器
    IAP_TRIG = 0;                               //清除触发寄存器
    IAP_ADDRH = 0x80;                           //将地址设置到非IAP区域
    IAP_ADDRL = 0;
}

char IapRead(int addr)
{
    char dat;

    IAP_CONTR = 0x80;                           //使能IAP
    IAP_TPS = 12;                               //设置等待参数12MHz
    IAP_CMD = 1;                              //设置IAP读命令
    IAP_ADDRL = addr;                           //设置IAP低地址
    IAP_ADDRH = addr >> 8;                      //设置IAP高地址
    IAP_TRIG = 0x5a;                            //写触发命令(0x5a)
    IAP_TRIG = 0xa5;                            //写触发命令(0xa5)
    _nop_();
    dat = IAP_DATA;                           //读IAP数据
    IapIdle();                                  //关闭IAP功能

    return dat;
}

void IapProgram(int addr, char dat)
{
    IAP_CONTR = 0x80;                           //使能IAP
    IAP_TPS = 12;                               //设置等待参数12MHz
    IAP_CMD = 2;                              //设置IAP写命令
    IAP_ADDRL = addr;                           //设置IAP低地址
    IAP_ADDRH = addr >> 8;                      //设置IAP高地址
    IAP_DATA = dat;                           //写IAP数据
    IAP_TRIG = 0x5a;                            //写触发命令(0x5a)
    IAP_TRIG = 0xa5;                            //写触发命令(0xa5)
    _nop_();
    IapIdle();                                  //关闭IAP功能
}

void IapErase(int addr)
{
    IAP_CONTR = 0x80;                           //使能IAP
    IAP_TPS = 12;                               //设置等待参数12MHz
    IAP_CMD = 3;                              //设置IAP擦除命令
    IAP_ADDRL = addr;                           //设置IAP低地址
    IAP_ADDRH = addr >> 8;                      //设置IAP高地址
    IAP_TRIG = 0x5a;                            //写触发命令(0x5a)
    IAP_TRIG = 0xa5;                            //写触发命令(0xa5)
    _nop_();                                    //
    IapIdle();                                  //关闭IAP功能
}

void Delay10ms(void)      //@11.0592MHz
{
      unsigned char data i, j;

      _nop_();
      _nop_();
      i = 144;
      j = 157;
      do
      {
                while (--j);
      } while (--i);
}

void main()
{
      char i;
    P0M0 = 0x00;
    P0M1 = 0x00;
    P1M0 = 0x00;
    P1M1 = 0x00;
    P2M0 = 0x00;
    P2M1 = 0x00;
    P3M0 = 0x00;
    P3M1 = 0x00;
    P4M0 = 0x00;
    P4M1 = 0x00;
    P5M0 = 0x00;
    P5M1 = 0x00;

    UartInit();
      Delay1000ms();
      Delay1000ms();
    IapErase(0);
      for(i=0;i<64;i++)
                UartSend(IapRead(i));
      for(i=0;i<64;i++)
      {
                IapProgram(i, i);
      }
      for(i=0;i<64;i++)
      {      
                UartSend(IapRead(i));
      }
    while (1);
}目前遇到的问题是,连续写入时,读出的数据好像被推后一个字节地址,不知道在哪个地方出问题。


工程如下:




ercircle 发表于 2025-7-7 18:26:28

楼主这个代码验证无法闭环呀~

[*]    IapErase(0);//清空一个扇区
[*]      for(i=0;i<64;i++)
[*]                UartSend(IapRead(i));//这里必然全是空,0xFF
[*]      for(i=0;i<64;i++)
[*]      {
[*]                IapProgram(i, i);//写入
[*]      }
[*]
[*]    UartSend(IapRead(i));// i64 ,并且64位置只擦除未写入,0xFF

乘风飞扬 发表于 2025-7-7 18:27:39

用附件的例子烧录到芯片里试试,串口助手文本模式打印读写结果

xxkj2010 发表于 2025-7-7 18:30:21

乘风飞扬 发表于 2025-7-7 18:27
用附件的例子烧录到芯片里试试,串口助手文本模式打印读写结果

我试试看

xxkj2010 发表于 2025-7-7 22:05:15

乘风飞扬 发表于 2025-7-7 18:27
用附件的例子烧录到芯片里试试,串口助手文本模式打印读写结果

试了,你第二次读取是写入一个字节就读一个字节的,我把它改成先多个字节写入,再多个字节读取,就出问题了,依然出现字节移位的问题
代码如下:
#include "reg51.h"
#include "intrins.h"
#include "stdio.h"

#define FOSC      11059200UL
#define BRT         (65536 - FOSC / 115200 / 4)

sfr   P0M1    =   0x93;
sfr   P0M0    =   0x94;
sfr   P1M1    =   0x91;
sfr   P1M0    =   0x92;
sfr   P2M1    =   0x95;
sfr   P2M0    =   0x96;
sfr   P3M1    =   0xb1;
sfr   P3M0    =   0xb2;
sfr   P4M1    =   0xb3;
sfr   P4M0    =   0xb4;
sfr   P5M1    =   0xc9;
sfr   P5M0    =   0xca;

sfr   AUXR    =   0x8e;
sfr   T2H   =   0xd6;
sfr   T2L   =   0xd7;

sfr   IAP_DATA    =   0xC2;
sfr   IAP_ADDRH   =   0xC3;
sfr   IAP_ADDRL   =   0xC4;
sfr   IAP_CMD   =   0xC5;
sfr   IAP_TRIG    =   0xC6;
sfr   IAP_CONTR   =   0xC7;
sfr   IAP_TPS   =   0xF5;

void Delay1000ms(void)        //@11.0592MHz
{
        unsigned char data i, j, k;

        i = 57;
        j = 27;
        k = 112;
        do
        {
                do
                {
                        while (--k);
                } while (--j);
        } while (--i);
}



void UartInit()
{
    SCON = 0x5a;
    T2L = BRT;
    T2H = BRT >> 8;
    AUXR = 0x15;
}

void UartSend(char dat)
{
    while (!TI);
    TI = 0;
    SBUF = dat;
}

void IapIdle()
{
    IAP_CONTR = 0;                              //关闭IAP功能
    IAP_CMD = 0;                              //清除命令寄存器
    IAP_TRIG = 0;                               //清除触发寄存器
    IAP_ADDRH = 0x80;                           //将地址设置到非IAP区域
    IAP_ADDRL = 0;
}

unsigned char IapRead(int addr)
{
    char dat;

    IAP_CONTR = 0x80;                           //使能IAP
    IAP_CMD = 1;                              //设置IAP读命令
    IAP_ADDRL = addr;                           //设置IAP低地址
    IAP_ADDRH = addr >> 8;                      //设置IAP高地址
    IAP_TRIG = 0x5a;                            //写触发命令(0x5a)
    IAP_TRIG = 0xa5;                            //写触发命令(0xa5)
    _nop_();
    dat = IAP_DATA;                           //读IAP数据
    IapIdle();                                  //关闭IAP功能

    return dat;
}

void IapProgram(int addr, unsigned char dat)
{
    IAP_CONTR = 0x80;                           //使能IAP
    IAP_CMD = 2;                              //设置IAP写命令
    IAP_ADDRL = addr;                           //设置IAP低地址
    IAP_ADDRH = addr >> 8;                      //设置IAP高地址
    IAP_DATA = dat;                           //写IAP数据
    IAP_TRIG = 0x5a;                            //写触发命令(0x5a)
    IAP_TRIG = 0xa5;                            //写触发命令(0xa5)
    _nop_();
    IapIdle();                                  //关闭IAP功能
}

void IapErase(int addr)
{
    IAP_CONTR = 0x80;                           //使能IAP
    IAP_CMD = 3;                              //设置IAP擦除命令
    IAP_ADDRL = addr;                           //设置IAP低地址
    IAP_ADDRH = addr >> 8;                      //设置IAP高地址
    IAP_TRIG = 0x5a;                            //写触发命令(0x5a)
    IAP_TRIG = 0xa5;                            //写触发命令(0xa5)
    _nop_();                                    //
    IapIdle();                                  //关闭IAP功能
}

void Delay10ms(void)        //@11.0592MHz
{
        unsigned char data i, j;

        _nop_();
        _nop_();
        i = 144;
        j = 157;
        do
        {
                while (--j);
        } while (--i);
}


void main()
{
        char i;
//        unsigned char a;
    P0M0 = 0x00;
    P0M1 = 0x00;
    P1M0 = 0x00;
    P1M1 = 0x00;
    P2M0 = 0x00;
    P2M1 = 0x00;
    P3M0 = 0x00;
    P3M1 = 0x00;
    P4M0 = 0x00;
    P4M1 = 0x00;
    P5M0 = 0x00;
    P5M1 = 0x00;

    UartInit();
    IAP_TPS = 11;                   //设置EEPROM操作等待参数(11.0592MHz),初始化设置一次即可       
        Delay1000ms();
        Delay1000ms();
        printf("read1:\r\n");       
        for(i=0;i<12;i++)
                printf("0x%02bx ",IapRead(i));       
        printf("\r\nread2:\r\n");       

    IapErase(0);       
        for(i=0;i<12;i++)
                printf("0x%02bx ",IapRead(i));       
        printf("\r\nread3:\r\n");       
       
        for(i=0;i<12;i++)
        {
                IapProgram(i, i);
                printf("0x%02bx ",IapRead(i));
        }
       
        Delay10ms();
        printf("\r\nread4:\r\n");       
        for(i=0;i<12;i++)
        {
                printf("0x%02bx ",IapRead(i));
        }
    while (1);
}

void UartPutc(unsigned char dat)
{
        SBUF = dat;
        while(TI == 0);
        TI = 0;
}

char putchar(char c)
{
        UartPutc(c);
        return c;
}



测试结果:


xxkj2010 发表于 2025-7-7 22:15:08

问题暂时解决:就是加长读取中的延时(增加一个或两个_nop_();)

原代码:
unsigned char IapRead(int addr)
{
    char dat;

    IAP_CONTR = 0x80;                           //使能IAP
    IAP_CMD = 1;                              //设置IAP读命令
    IAP_ADDRL = addr;                           //设置IAP低地址
    IAP_ADDRH = addr >> 8;                      //设置IAP高地址
    IAP_TRIG = 0x5a;                            //写触发命令(0x5a)
    IAP_TRIG = 0xa5;                            //写触发命令(0xa5)
        _nop_();
    dat = IAP_DATA;                           //读IAP数据
    IapIdle();                                  //关闭IAP功能
    return dat;
}改后代码:
unsigned char IapRead(int addr)
{
    char dat;

    IAP_CONTR = 0x80;                           //使能IAP
    IAP_CMD = 1;                              //设置IAP读命令
    IAP_ADDRL = addr;                           //设置IAP低地址
    IAP_ADDRH = addr >> 8;                      //设置IAP高地址
    IAP_TRIG = 0x5a;                            //写触发命令(0x5a)
    IAP_TRIG = 0xa5;                            //写触发命令(0xa5)
        _nop_();_nop_();//增加一个_nop_();
    dat = IAP_DATA;                           //读IAP数据
    IapIdle();                                  //关闭IAP功能
    return dat;
}估计是STC8执行代码的速度太快了的缘故吧!

乘风飞扬 发表于 2025-7-8 09:25:47

例程为了简化代码,一个循环完成读写操作。
你想测试写完再读,再加一个循环就好了。
    IAP_TPS = 11;       //设置EEPROM操作等待参数(11.0592MHz),初始化设置一次即可
    PrintfInit();

    printf("Read1=");   //读取EEPROM原先的内容
    for(i=0;i<10;i++)
    {
      a = IapRead(OFFSET+i);
      printf("0x%02bx ",a);
      if(a == 0xff) a = i;//如果内容为空,则写入初始化数据
      else a++;    //如果内容非空,在原先基础上加1
    }
    printf("\r\n");

    IapErase(OFFSET);   //如果擦写范围跨扇区,需要擦除两个扇区的空间
    for(i=0;i<10;i++)
    {
      IapProgram(OFFSET+i, a);
    }

    printf("Read2=");   //擦除、重写后,读取EEPROM现在的内容
    for(i=0;i<10;i++)
    {
      a = IapRead(OFFSET+i);
      printf("0x%02bx ",a);
    }
    printf("\r\n");

xxkj2010 发表于 2025-7-8 14:49:34

乘风飞扬 发表于 2025-7-8 09:25
例程为了简化代码,一个循环完成读写操作。
你想测试写完再读,再加一个循环就好了。


读取时不加长延时(添加_nop_();)时,字节0出错:


乘风飞扬 发表于 2025-7-8 15:20:22

xxkj2010 发表于 2025-7-8 14:49
读取时不加长延时(添加_nop_();)时,字节0出错:

先不要修改例子,直接用例子测试,功能验证正常后再进行修改或者移植。

xxkj2010 发表于 2025-7-8 17:06:53

乘风飞扬 发表于 2025-7-8 15:20
先不要修改例子,直接用例子测试,功能验证正常后再进行修改或者移植。 ...
我是直接下载你发的那个工程的,没有修改,结果出现小问题。我用的芯片是STC8H2K12U-SOP16,如果用STC8H8K64U,就没有问题。
页: [1]
查看完整版本: 写EEPROM遇到的问题