jrh200310 发表于 2025-4-18 17:00:56

AI8051 8位模式 内部EEPROM按例程函数无法保存数据,求助!

在程序开始设置两个字符串数组zhifu0,zhifu1,开机先打印zhifu1数据,正常。然后把zhifu0的数据保存到EEPROM中,再读到zhifu1打印。发现打印的都是0.EEPROM操作函数从官方例子中复制。求助!

#include "AI8051U.h"
#include "intrins.h"
#include <stdio.h>
typedef   unsigned char   u8;
typedef   unsigned int    u16;
typedef   unsigned long   u32;
/****************************** 用户定义宏 ***********************************/
#define   MAIN_Fosc       11059200L   //定义主时钟
#define   EE_ADDRESS      0x000000//保存的EEPROM起始地址
#define   Timer0_Reload   (65536UL -(MAIN_Fosc / 1000))       //Timer 0 中断频率, 1000次/秒
#define   Tip_Delay       (MAIN_Fosc / 1000000)
/*****************************************************************************/
unsigned char zhifu0[] = {"1234567890"};
unsigned char zhifu1 = {"ABCD"};

void DisableEEPROM(void);
void EEPROM_read_n(u32 EE_address,u8 *DataAddress,u16 number);
void EEPROM_write_n(u32 EE_address,u8 *DataAddress,u16 number);
void EEPROM_SectorErase(u32 EE_address);
void Uart1_init(void)      ;////115200bps@11.0592MHz
void Delay100ms(void)      //@11.0592MHz
{
      unsigned char data i, j, k;
      _nop_();
      _nop_();
      i = 5;
      j = 52;
      k = 195;
      do
      {
                do
                {
                        while (--k);
                } while (--j);
      } while (--i);
}

//==========================
      void UartPutc(unsigned char dat)
{
      SBUF = dat;
      while(TI == 0);
      TI = 0;
}
char putchar(char c)
{
      UartPutc(c);
      return c;
}      
/********************** 主函数 ************************/
void main(void)
{   
          Delay100ms();      //@11.0592MHz
    WTST = 0;//设置程序指令延时参数,赋值为0可将CPU执行指令的速度设置为最快
    P_SW2 |= 0x80; //扩展寄存器(XFR)访问使能
    CKCON = 0; //提高访问XRAM速度

    P0M1 = 0x00;   P0M0 = 0x00;   //设置为准双向口
    P1M1 = 0x00;   P1M0 = 0x00;   //设置为准双向口
    P2M1 = 0x00;   P2M0 = 0x00;   //设置为准双向口
    P3M1 = 0x00;   P3M0 = 0x00;   //设置为准双向口
    P4M1 = 0x00;   P4M0 = 0x00;   //设置为准双向口
    P5M1 = 0x00;   P5M0 = 0x00;   //设置为准双向口
    P6M1 = 0x00;   P6M0 = 0x00;   //设置为准双向口
    P7M1 = 0x00;   P7M0 = 0x00;   //设置为准双向口

    EA = 1;   //打开总中断
    Uart1_init()      ;////115200bps@11.0592MHz
   
          printf("\n%s",zhifu1) ; //开机打印数据1原始数据
          EEPROM_SectorErase(0x000000); //擦除
          EEPROM_write_n(0x000000,zhifu0,10); // 把数组0的数据写入
          EEPROM_read_n(0x000000,zhifu1,10); // 读到数据1
    while(1)
    {   
                  printf("\n%s",zhifu1) ; //打印
                        Delay100ms();      //@11.0592MHz                                       
    }
}
//=======================================================================

/***************串口1中断服务程序************************/
void Uartl_ISR() interrupt 4
{
//    uchar i;
         if (RI)          // 串口中断接收数
    {
         RI = 0 ;
         
    }
}




//========================================================================
// 函数: void   ISP_Disable(void)
// 描述: 禁止访问ISP/IAP.
// 参数: non.
// 返回: non.
// 版本: V1.0, 2012-10-22
//========================================================================
void DisableEEPROM(void)
{
    IAP_CONTR = 0;          //关闭 IAP 功能
    IAP_CMD = 0;            //清除命令寄存器
    IAP_TRIG = 0;         //清除触发寄存器
    IAP_ADDRE = 0xff;       //将地址设置到非 IAP 区域
    IAP_ADDRH = 0xff;       //将地址设置到非 IAP 区域
    IAP_ADDRL = 0xff;
}

//========================================================================
// 函数: void EEPROM_read_n(u32 EE_address,u8 *DataAddress,u16 number)
// 描述: 从指定EEPROM首地址读出n个字节放指定的缓冲.
// 参数: EE_address:读出EEPROM的首地址.
//       DataAddress: 读出数据放缓冲的首地址.
//       number:      读出的字节长度.
// 返回: non.
// 版本: V1.0, 2012-10-22
//========================================================================
void EEPROM_read_n(u32 EE_address,u8 *DataAddress,u16 number)
{
    EA = 0;   //禁止中断

    IAP_CONTR = 0x80; //使能 IAP
    IAP_TPS = Tip_Delay; //设置擦除等待参数 24MHz
    IAP_CMD = 1;//设置 IAP 读命令
    do
    {
      IAP_ADDRE = (u8)(EE_address >> 16); //送地址高字节(地址需要改变时才需重新送地址)
      IAP_ADDRH = (u8)(EE_address >> 8);//送地址中字节(地址需要改变时才需重新送地址)
      IAP_ADDRL = (u8)EE_address;         //送地址低字节(地址需要改变时才需重新送地址)
      IAP_TRIG = 0x5a; //写触发命令(0x5a)
      IAP_TRIG = 0xa5; //写触发命令(0xa5)
      _nop_();   //多级流水线的指令系统,触发命令后建议加4个NOP,保证IAP_DATA的数据完成准备
      _nop_();
      _nop_();
      _nop_();
      *DataAddress = IAP_DATA; //读 IAP 数据
      EE_address++;
      DataAddress++;
    }while(--number);
    DisableEEPROM();
    EA = 1;   //重新允许中断
}

//========================================================================
// 函数: void EEPROM_SectorErase(u32 EE_address)
// 描述: 把指定地址的EEPROM扇区擦除.
// 参数: EE_address:要擦除的扇区EEPROM的地址.
// 返回: non.
// 版本: V1.0, 2013-5-10
//========================================================================
void EEPROM_SectorErase(u32 EE_address)
{
    EA = 0;   //禁止中断

    IAP_CONTR = 0x80; //使能 IAP
    IAP_TPS = Tip_Delay; //设置擦除等待参数 24MHz
    IAP_CMD = 3;      //设置 IAP 擦除命令
    IAP_ADDRE = (u8)(EE_address >> 16); //送扇区地址高字节(地址需要改变时才需重新送地址)
    IAP_ADDRH = (u8)(EE_address >> 8);//送扇区地址中字节(地址需要改变时才需重新送地址)
    IAP_ADDRL = (u8)EE_address;         //送扇区地址低字节(地址需要改变时才需重新送地址)
    IAP_TRIG = 0x5a; //写触发命令(0x5a)
    IAP_TRIG = 0xa5; //写触发命令(0xa5)
    _nop_();   //多级流水线的指令系统,触发命令后建议加4个NOP,保证IAP_DATA的数据完成准备
    _nop_();
    _nop_();
    _nop_();
    DisableEEPROM();
    EA = 1;   //重新允许中断
}

//========================================================================
// 函数: void EEPROM_write_n(u32 EE_address,u8 *DataAddress,u16 number)
// 描述: 把缓冲的n个字节写入指定首地址的EEPROM.
// 参数: EE_address:写入EEPROM的首地址.
//       DataAddress: 写入源数据的缓冲的首地址.
//       number:      写入的字节长度.
// 返回: non.
// 版本: V1.0, 2012-10-22
//========================================================================
void EEPROM_write_n(u32 EE_address,u8 *DataAddress,u16 number)
{
    EA = 0;   //禁止中断

    IAP_CONTR = 0x80; //使能 IAP
    IAP_TPS = Tip_Delay; //设置擦除等待参数 24MHz
    IAP_CMD = 2;//设置 IAP 写命令
    do
    {
      IAP_ADDRE = (u8)(EE_address >> 16); //送地址高字节(地址需要改变时才需重新送地址)
      IAP_ADDRH = (u8)(EE_address >> 8);//送地址中字节(地址需要改变时才需重新送地址)
      IAP_ADDRL = (u8)EE_address;         //送地址低字节(地址需要改变时才需重新送地址)
      IAP_DATA = *DataAddress; //写 IAP 数据
      IAP_TRIG = 0x5a; //写触发命令(0x5a)
      IAP_TRIG = 0xa5; //写触发命令(0xa5)
      _nop_();   //多级流水线的指令系统,触发命令后建议加4个NOP,保证IAP_DATA的数据完成准备
      _nop_();
      _nop_();
      _nop_();
      EE_address++;
      DataAddress++;
    }while(--number);

    DisableEEPROM();
    EA = 1;   //重新允许中断
}

//==========================================================================

void Uart1_init(void)      ////115200bps@11.0592MHz
{
      P3M0&=~ 0X01;
      P3M1&=~ 0X02;

SCON = 0x50;                //8位数据,可变波特率
      AUXR |= 0x01;                //串口1选择定时器2为波特率发生器
      AUXR |= 0x04;                //定时器时钟1T模式
      T2L = 0xE8;                //设置定时初始值
      T2H = 0xFF;                //设置定时初始值
      AUXR |= 0x10;                //定时器2开始计时
      ES = 1;               //串口中断允许
      //IP=0x10;//串口中断优先
      EA = 1;               //总中断允许
}


jrh200310 发表于 2025-4-18 17:03:25

贴上工程

国芯人工智能 发表于 2025-4-18 17:03:00

您好,针对您在使用AI8051 8位模式时遇到的EEPROM数据保存和读取问题,以下是一些可能的原因和解决方案。

问题分析
1. EEPROM操作函数问题:您提到EEPROM操作函数是从官方例子中复制的,但可能存在以下问题:
地址对齐:确保EEPROM的起始地址EEADDRESS是正确的,并且与EEPROM的物理地址对齐。
数据长度:在EEPROMwriten和EEPROMreadn函数中,确保number参数正确反映了要写入或读取的数据长度。

2. 数据初始化问题:在程序开始时,zhifu0和zhifu1数组的初始化是正确的,但在将zhifu0的数据保存到EEPROM并读取到zhifu1时,可能会出现数据丢失或错误。

3. EEPROM读写时序:EEPROM的读写操作需要遵循特定的时序,确保在写入和读取之间有足够的延迟,以避免数据冲突。

解决方案
1. 检查EEPROM操作函数:
确保EEPROMwriten和EEPROMreadn函数的实现正确,特别是地址和数据的传递。
在写入和读取操作之间添加适当的延迟,以确保数据稳定。

2. 调试和验证:
在写入EEPROM后,立即读取并打印数据,以验证写入操作是否成功。
使用调试工具(如仿真器或调试器)逐步检查程序的执行流程,确保每一步操作都按预期进行。

3. 代码优化:
确保zhifu0和zhifu1数组的长度一致,避免数据截断或溢出。
在写入和读取操作前后,添加调试信息,以便更好地跟踪数据的变化。

示例代码
以下是一个可能的代码优化示例,供您参考:

c
include "AI8051Uh"
include "intrinsh"
include

typedef unsigned char u8;
typedef unsigned int u16;
typedef unsigned long u32;

define MAINFosc 11059200L
define EEADDRESS 0x000000
define Timer0Reload (65536UL - (MAINFosc / 1000))
define TipDelay (MAINFosc / 1000000)

unsigned char zhifu0[] = {"1234567890"};
unsigned char zhifu1 = {"ABCD"};

void DisableEEPROM(void);
void EEPROMreadn(u32 EEaddress, u8 DataAddress, u16 number);
void EEPROMwriten(u32 EEaddress, u8 DataAddress, u16 number);

void main() {
    // 初始化
    DisableEEPROM();

    // 打印初始数据
    printf("Initial zhifu1: %s\n", zhifu1);

    // 将zhifu0的数据写入EEPROM
    EEPROMwriten(EEADDRESS, zhifu0, sizeof(zhifu0));

    // 从EEPROM读取数据到zhifu1
    EEPROMreadn(EEADDRESS, zhifu1, sizeof(zhifu0));

    // 打印读取后的数据
    printf("After EEPROM read, zhifu1: %s\n", zhifu1);

    while (1) {
      // 主循环
    }
}

void DisableEEPROM(void) {
    // 禁用EEPROM操作
}

void EEPROMreadn(u32 EEaddress, u8 DataAddress, u16 number) {
    // 从EEPROM读取数据
}

void EEPROMwriten(u32 EEaddress, u8 DataAddress, u16 number) {
    // 将数据写入EEPROM
}

总结
通过以上分析和优化,您应该能够解决EEPROM数据保存和读取的问题。如果问题仍然存在,建议进一步检查硬件连接和EEPROM的物理状态,确保其正常工作。希望这些建议对您有所帮助!

[本文内容由国芯人工智能辅助生成,仅供参考]

王昱顺 发表于 2025-4-18 18:30:13

jrh200310 发表于 2025-4-18 17:03
贴上工程

你好,我这里测试EEPROM功能正常,使用的是stcisp自带的串口工具


具体测试步骤是,选择不擦除EEPROM,然后下载一次带有擦除和写入EEPROM的程序
然后屏蔽擦除和写入程序,只保留读取函数,测试可以正常读取刚才写入的程序

_奶咖君_ 发表于 2025-4-19 17:56:54

王昱顺 发表于 2025-4-18 18:30
你好,我这里测试EEPROM功能正常,使用的是stcisp自带的串口工具




直接测试楼主的原工程呢?看着好像没啥问题啊

王昱顺 发表于 2025-4-19 20:12:05

_奶咖君_ 发表于 2025-4-19 17:56
直接测试楼主的原工程呢?看着好像没啥问题啊

我就是用的楼主原程序,确实是没问题的

jrh200310 发表于 2025-4-21 09:02:37

在擦除的函数后面跟上一个打印信息,起到延时的作用就正常了,不知道是不是芯片批次不一样的原因。在我的板子上不加延时确实不行。

/********************** 主函数 ************************/
void main(void)
{   
          Delay100ms();        //@11.0592MHz
    WTST = 0;//设置程序指令延时参数,赋值为0可将CPU执行指令的速度设置为最快
    P_SW2 |= 0x80; //扩展寄存器(XFR)访问使能
    CKCON = 0; //提高访问XRAM速度

    P0M1 = 0x00;   P0M0 = 0x00;   //设置为准双向口
    P1M1 = 0x00;   P1M0 = 0x00;   //设置为准双向口
    P2M1 = 0x00;   P2M0 = 0x00;   //设置为准双向口
    P3M1 = 0x00;   P3M0 = 0x00;   //设置为准双向口
    P4M1 = 0x00;   P4M0 = 0x00;   //设置为准双向口
    P5M1 = 0x00;   P5M0 = 0x00;   //设置为准双向口
    P6M1 = 0x00;   P6M0 = 0x00;   //设置为准双向口
    P7M1 = 0x00;   P7M0 = 0x00;   //设置为准双向口

    EA = 1;   //打开总中断
    Uart1_init()        ;////115200bps@11.0592MHz
   
          printf("\n%s",zhifu1) ; //开机打印数据1原始数据
          EEPROM_SectorErase(0x000000); //擦除
          printf("\nEERPOM_Erase") ; //开机打印数据1原始数据
          EEPROM_write_n(0x000000,zhifu0,10); // 把数组0的数据写入
          EEPROM_read_n(0x000000,zhifu1,10); // 读到数据1
    while(1)
    {   
                  printf("\n%s",zhifu1) ; //打印
                        Delay100ms();        //@11.0592MHz                                       
    }
}
//==============================================================

_奶咖君_ 发表于 2025-4-21 09:17:13

jrh200310 发表于 2025-4-21 09:02
在擦除的函数后面跟上一个打印信息,起到延时的作用就正常了,不知道是不是芯片批次不一样的原因。在我的板 ...

我看程序里面IAP_TPS 也设置了,,感觉应该不会因为时间不足导致EEPROM操作失败?

_奶咖君_ 发表于 2025-4-21 09:18:52

王昱顺 发表于 2025-4-19 20:12
我就是用的楼主原程序,确实是没问题的

王哥哥,,看看楼主最新的回复,,

我看你这里测试的是先 只写入,,,后只读取,,和楼主这里的操作不太一样,,,我的意思是直接使用楼主提供的原程序试一试,,可能就是这点儿差距

王昱顺 发表于 2025-4-21 09:30:03

_奶咖君_ 发表于 2025-4-21 09:18
王哥哥,,看看楼主最新的回复,,

我看你这里测试的是先 只写入,,,后只读取,,和楼主这里的操作不 ...

我当时直接测试源程序也没问题,直接就出来正常信息了。可能是芯片体质不同?
我用的是11.0592mhz主频
页: [1] 2
查看完整版本: AI8051 8位模式 内部EEPROM按例程函数无法保存数据,求助!