15270454439 发表于 2025-9-21 23:48:10

AI8H2K12U的EEPROM地址0x0000无法使用问题|已解决

求助帖~!

AI8H2K12U的EEPROM在ISP中配置为0.5K,使用EEPROM地址0x0001时程序功能正常,0x0000时EEPROM无法保存,测试过修改EEPROM配置从0.5~2K,结果一样;
注释掉的测试代码,在主程序开始前直接在地址0x0000写入5后能够正常读取,地址0x0000的写入和其它地址有什么不一样么?测试除0x0000意外随机的地址也都正常使用{:4_178:}




附代码:





#include <AI8H.H>
#include "Delay.h"
#include "STC8H_PWM.h"
#include "INT0and1.h"               
#include "STC8_EEPROM.h"

#define PWM6_E0x0001//PWM6档位的EEPROM存储地址(0x0000无法使用原因不明)


u8 Key1;            //档位变量
u8 PWM6_MOD;      //PWM6初始占空比
bit PWM6_KG = 0;    //PWM6开关状态
bit PWM6_UP = 0;    //PWM6更新标识位
bit EEPROM_UP = 0;//EEPROM更新标识位


void main()
{
    INT0and1_Init();                //外部中断初始化,一定要加在main主程序前
    STC8H_PWM_Init();               //初始化硬件PWM
    P3M0 &= ~0x0c; P3M1 &= ~0x0c;   //P32/33设为准双向口

//    测试   
//    IapEraseSector(IAP_ADDRESS1);   //擦除第1扇区(写入地址所在扇区)
//    IapProgramByte(0x0000,5);          //在地址写入5
//    switch(IapReadByte(0x0000))       //读取EEPROM数据
    switch(IapReadByte(0x0001))   //读取EEPROM数据
    {
      case 2:Key1 = 2;PWM6_MOD = 40;break;
      case 3:Key1 = 3;PWM6_MOD = 50;break;
      case 4:Key1 = 4;PWM6_MOD = 60;break;
      case 5:Key1 = 5;PWM6_MOD = 70;break;
      case 6:Key1 = 6;PWM6_MOD = 80;break;
      case 7:Key1 = 7;PWM6_MOD = 90;break;
      case 8:Key1 = 8;PWM6_MOD = 100;break;
      default:Key1 = 1;PWM6_MOD = 30;break;
    }
      
    while (1)
    {
      if(PWM6_UP)
      {
            PWM6_UP = 0;//清除更新标识位
            
            if(PWM6_KG)//判断开关状态
            {
                PWM_Set(6,PWM6_MOD);
            }else
            {
                PWM_Set(6,0);
            }
      }
      if(EEPROM_UP)
      {
            EEPROM_UP = 0;                  //清除更新标识位
            IapEraseSector(IAP_ADDRESS1);   //擦除第1扇区(写入地址所在扇区)
            IapProgramByte(0x0001,Key1);    //在地址0x00F1写入Key1的值
      }
    }
}


void INT_0(void) interrupt 0                              //外部中断P32接口
{
    Delay(50);//延时消抖
    if(P32 == 0)
    {
      while(P32==0);      //松手检测
      PWM6_KG = ~PWM6_KG; //翻转开关状态
      PWM6_UP = 1;      //开启PWM6更新
    }
}

void INT_1(void) interrupt 2                              //外部中断P33接口
{
    Delay(50);//延时消抖
    if(P33==0)
    {
      while(P33 == 0);//松手检测
      Key1++;
      EEPROM_UP = 1;//开启EEPROM更新
      switch(Key1)//判断档位
      {
            case 2:PWM6_MOD = 40;break;
            case 3:PWM6_MOD = 50;break;
            case 4:PWM6_MOD = 60;break;
            case 5:PWM6_MOD = 70;break;
            case 6:PWM6_MOD = 80;break;
            case 7:PWM6_MOD = 90;break;
            case 8:PWM6_MOD = 100;break;
            default:Key1 = 1;PWM6_MOD = 30;break;
      }
      if(PWM6_KG) //如果PWM6开启,则开启PWM6更新
      {
            PWM6_UP = 1;
      }
    }
}


EEPROM封装函数.c:





#include <AI8H.H>
#include "STC8_EEPROM.h"

/*----------------------------
关闭ISP/IAP/EEPROM功能
使单片机处于安全状态
----------------------------*/
void IapIdle(void)
{
    IAP_CONTR = 0;                  //关闭ISP/IAP/EEPROM功能
    IAP_CMD = 0;                  //待机模式无ISP操作
    IAP_TRIG = 0;                   //ISP/IAP操作时的命令触发寄存器
    IAP_ADDRH = 0x80;               //操作时的地址寄存器高八位
    IAP_ADDRL = 0;                  //操作时的地址寄存器低八位
}

/*----------------------------
从ISP/IAP/EEPROM区域读取一个字节
输入:addr (ISP/IAP/EEPROM地址)
输出:Flash数据
----------------------------*/
u8 IapReadByte(u16 addr)
{
    u8 dat;                        

    IAP_CONTR = 0x80;               //打开IAP功能
    IAP_TPS = ENABLE_IAP;         //设置等待时间,根据系统时钟频率
    IAP_CMD = CMD_READ;             //设为读字节操作
    IAP_ADDRL = addr;               //地址低8位
    IAP_ADDRH = addr >> 8;          //地址高8位
    IAP_TRIG = 0x5a;                //发送触发命令1-必须
    IAP_TRIG = 0xa5;                //发送触发命令2-必须
    _nop_();                        //MCU将保持在这里,直到ISP/IAP/EEPROM操作完成
    dat = IAP_DATA;               //读取数据
    IapIdle();                      //关闭ISP/IAP/EEPROM功能

    return dat;                     //返回读取的数据
}

/*----------------------------
写一个字节到ISP/IAP/EEPROM区域
addr:ISP/IAP/EEPROM地址
dat :数据
----------------------------*/
void IapProgramByte(u16 addr, u8 dat)
{
    IAP_CONTR = 0x80;               //打开IAP功能
    IAP_TPS = ENABLE_IAP;         //设置等待时间,根据系统时钟频率
    IAP_CMD = CMD_PROGRAM;          //设为写字节操作
    IAP_ADDRL = addr;               //地址低8位
    IAP_ADDRH = addr >> 8;          //地址高8位
    IAP_DATA = dat;               //写ISP/IAP/EEPROM数据
    IAP_TRIG = 0x5a;                //发送触发命令1-必须
    IAP_TRIG = 0xa5;                //发送触发命令2-必须
    _nop_();                        //MCU将保持在这里,直到ISP/IAP/EEPROM操作完成
    IapIdle();                      //关闭ISP/IAP/EEPROM功能
}

/*----------------------------
擦除一个扇区
addr:ISP/IAP/EEPROM地址(起始地址)
----------------------------*/
void IapEraseSector(u16 addr)
{
    IAP_CONTR = 0x80;               //打开IAP功能
    IAP_TPS = ENABLE_IAP;         //设置等待时间,根据系统时钟频率
    IAP_CMD = CMD_ERASE;            //设为扇区擦除操作
    IAP_ADDRL = addr;               //地址低8位
    IAP_ADDRH = addr >> 8;          //地址高8位
    IAP_TRIG = 0x5a;                //发送触发命令1-必须
    IAP_TRIG = 0xa5;                //发送触发命令2-必须
    _nop_();                        //MCU将保持在这里,直到ISP/IAP/EEPROM操作完成
    IapIdle();                      //关闭ISP/IAP/EEPROM功能
}


EEPROM封装函数.h:


#ifndef __STC8_EEPROM_H__
#define __STC8_EEPROM_H__

#include <AI8H.H>
#include "intrins.h"

/*定义操作命令*/
#define CMD_READ    1               //读字节
#define CMD_PROGRAM 2               //写字节
#define CMD_ERASE   3               //扇区擦除


/*根据系统时钟选择等待时间*/
#define ENABLE_IAP 11               //11.0592MHZ    等待时间=系统工作频率/1000000(小数部分四舍五入取整)


//擦除EEPROM的起始地址,以扇区起始地址来擦除,EEPROM大小请在ISP下载工具中进行配置
#define IAP_ADDRESS1 0x0000 //第1扇区结束地址:0x01FF注意0x0000无法使用原因不明
#define IAP_ADDRESS2 0x0200 //第2扇区结束地址:0x03FF
#define IAP_ADDRESS3 0x0400 //第3扇区结束地址:0x05FF
#define IAP_ADDRESS4 0x0600 //第4扇区结束地址:0x07FF


//外部可调用的函数声明

u8 IapReadByte(u16 addr);               //读取一个字节
void IapProgramByte(u16 addr, u8 dat);//写一个字节
void IapEraseSector(u16 addr);          //擦除扇区

#endif



小飞侠 发表于 2025-9-22 12:21:05

先用官方例程试试,看看能不能成功

15270454439 发表于 2025-9-23 00:24:26

小飞侠 发表于 2025-9-22 12:21
先用官方例程试试,看看能不能成功

还是自己封装函数的问题,使用官方的库函数调用没问题,感谢{:4_197:}
页: [1]
查看完整版本: AI8H2K12U的EEPROM地址0x0000无法使用问题|已解决