找回密码
 立即注册
查看: 125|回复: 10

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

[复制链接]
  • 打卡等级:初来乍到
  • 打卡总天数:5
  • 最近打卡:2025-04-28 15:28:39
已绑定手机

3

主题

6

回帖

59

积分

注册会员

积分
59
发表于 2025-4-18 17:00:56 | 显示全部楼层 |阅读模式
在程序开始设置两个字符串数组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[20] = {"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;                 //总中断允许
}


截图202504181700046836.jpg
截图202504181700463222.jpg
回复

使用道具 举报 送花

  • 打卡等级:初来乍到
  • 打卡总天数:5
  • 最近打卡:2025-04-28 15:28:39
已绑定手机

3

主题

6

回帖

59

积分

注册会员

积分
59
发表于 2025-4-18 17:03:25 | 显示全部楼层
贴上工程

AI8051U Bit8 EEPROM.rar

74.98 KB, 下载次数: 1

点评

你好,我这里测试EEPROM功能正常,使用的是stcisp自带的串口工具 [attachimg]94471[/attachimg] 具体测试步骤是,选择不擦除EEPROM,然后下载一次带有擦除和写入EEPROM的程序 然后屏蔽擦除和写入程序,只保留读取函  详情 回复 发表于 2025-4-18 18:30
回复

使用道具 举报 送花

3

主题

1160

回帖

1031

积分

等待验证会员

积分
1031
发表于 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数组的长度一致,避免数据截断或溢出。
在写入和读取操作前后,添加调试信息,以便更好地跟踪数据的变化。

示例代码
以下是一个可能的代码优化示例,供您参考:
  1. c
  2. include "AI8051Uh"
  3. include "intrinsh"
  4. include
  5. typedef unsigned char u8;
  6. typedef unsigned int u16;
  7. typedef unsigned long u32;
  8. define MAINFosc 11059200L
  9. define EEADDRESS 0x000000
  10. define Timer0Reload (65536UL - (MAINFosc / 1000))
  11. define TipDelay (MAINFosc / 1000000)
  12. unsigned char zhifu0[] = {"1234567890"};
  13. unsigned char zhifu1[20] = {"ABCD"};
  14. void DisableEEPROM(void);
  15. void EEPROMreadn(u32 EEaddress, u8 DataAddress, u16 number);
  16. void EEPROMwriten(u32 EEaddress, u8 DataAddress, u16 number);
  17. void main() {
  18.     // 初始化
  19.     DisableEEPROM();
  20.     // 打印初始数据
  21.     printf("Initial zhifu1: %s\n", zhifu1);
  22.     // 将zhifu0的数据写入EEPROM
  23.     EEPROMwriten(EEADDRESS, zhifu0, sizeof(zhifu0));
  24.     // 从EEPROM读取数据到zhifu1
  25.     EEPROMreadn(EEADDRESS, zhifu1, sizeof(zhifu0));
  26.     // 打印读取后的数据
  27.     printf("After EEPROM read, zhifu1: %s\n", zhifu1);
  28.     while (1) {
  29.         // 主循环
  30.     }
  31. }
  32. void DisableEEPROM(void) {
  33.     // 禁用EEPROM操作
  34. }
  35. void EEPROMreadn(u32 EEaddress, u8 DataAddress, u16 number) {
  36.     // 从EEPROM读取数据
  37. }
  38. void EEPROMwriten(u32 EEaddress, u8 DataAddress, u16 number) {
  39.     // 将数据写入EEPROM
  40. }
复制代码

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

[本文内容由国芯人工智能辅助生成,仅供参考]
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:458
  • 最近打卡:2025-05-01 07:48:22
已绑定手机
已实名认证

110

主题

2218

回帖

5450

积分

版主

积分
5450
发表于 2025-4-18 18:30:13 | 显示全部楼层

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

截图202504181828564484.jpg
具体测试步骤是,选择不擦除EEPROM,然后下载一次带有擦除和写入EEPROM的程序
然后屏蔽擦除和写入程序,只保留读取函数,测试可以正常读取刚才写入的程序
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:435
  • 最近打卡:2025-04-30 08:43:23

33

主题

2351

回帖

4860

积分

论坛元老

积分
4860
发表于 2025-4-19 17:56:54 | 显示全部楼层
王*** 发表于 2025-4-18 18:30
你好,我这里测试EEPROM功能正常,使用的是stcisp自带的串口工具

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

点评

我就是用的楼主原程序,确实是没问题的  详情 回复 发表于 2025-4-19 20:12
参考例程并不是对技术参 考手册的补充,而是对技术参 考手册的解释。
技术参 考手册不应该需要参考例程作为补充,而是解释成了参考例程的样子
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:458
  • 最近打卡:2025-05-01 07:48:22
已绑定手机
已实名认证

110

主题

2218

回帖

5450

积分

版主

积分
5450
发表于 2025-4-19 20:12:05 | 显示全部楼层
_奶*** 发表于 2025-4-19 17:56
直接测试楼主的原工程呢?看着好像没啥问题啊

我就是用的楼主原程序,确实是没问题的
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:初来乍到
  • 打卡总天数:5
  • 最近打卡:2025-04-28 15:28:39
已绑定手机

3

主题

6

回帖

59

积分

注册会员

积分
59
发表于 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                                       
    }
}
//==============================================================
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:435
  • 最近打卡:2025-04-30 08:43:23

33

主题

2351

回帖

4860

积分

论坛元老

积分
4860
发表于 2025-4-21 09:17:13 | 显示全部楼层
jrh20*** 发表于 2025-4-21 09:02
在擦除的函数后面跟上一个打印信息,起到延时的作用就正常了,不知道是不是芯片批次不一样的原因。在我的板 ...

我看程序里面IAP_TPS 也设置了,,感觉应该不会因为时间不足导致EEPROM操作失败?
参考例程并不是对技术参 考手册的补充,而是对技术参 考手册的解释。
技术参 考手册不应该需要参考例程作为补充,而是解释成了参考例程的样子
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:435
  • 最近打卡:2025-04-30 08:43:23

33

主题

2351

回帖

4860

积分

论坛元老

积分
4860
发表于 2025-4-21 09:18:52 | 显示全部楼层
王*** 发表于 2025-4-19 20:12
我就是用的楼主原程序,确实是没问题的

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

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

点评

我当时直接测试源程序也没问题,直接就出来正常信息了。可能是芯片体质不同? 我用的是11.0592mhz主频  详情 回复 发表于 2025-4-21 09:30
参考例程并不是对技术参 考手册的补充,而是对技术参 考手册的解释。
技术参 考手册不应该需要参考例程作为补充,而是解释成了参考例程的样子
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:458
  • 最近打卡:2025-05-01 07:48:22
已绑定手机
已实名认证

110

主题

2218

回帖

5450

积分

版主

积分
5450
发表于 2025-4-21 09:30:03 | 显示全部楼层
_奶*** 发表于 2025-4-21 09:18
王哥哥,,看看楼主最新的回复,,

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

我当时直接测试源程序也没问题,直接就出来正常信息了。可能是芯片体质不同?
我用的是11.0592mhz主频
回复 支持 反对

使用道具 举报 送花

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

本版积分规则

QQ|手机版|小黑屋|深圳国芯人工智能有限公司 ( 粤ICP备2022108929号-2 )

GMT+8, 2025-5-1 19:36 , Processed in 0.216360 second(s), 116 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

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