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; //总中断允许
}
贴上工程 您好,针对您在使用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的物理状态,确保其正常工作。希望这些建议对您有所帮助!
[本文内容由国芯人工智能辅助生成,仅供参考] jrh200310 发表于 2025-4-18 17:03
贴上工程
你好,我这里测试EEPROM功能正常,使用的是stcisp自带的串口工具
具体测试步骤是,选择不擦除EEPROM,然后下载一次带有擦除和写入EEPROM的程序
然后屏蔽擦除和写入程序,只保留读取函数,测试可以正常读取刚才写入的程序
王昱顺 发表于 2025-4-18 18:30
你好,我这里测试EEPROM功能正常,使用的是stcisp自带的串口工具
直接测试楼主的原工程呢?看着好像没啥问题啊 _奶咖君_ 发表于 2025-4-19 17:56
直接测试楼主的原工程呢?看着好像没啥问题啊
我就是用的楼主原程序,确实是没问题的 在擦除的函数后面跟上一个打印信息,起到延时的作用就正常了,不知道是不是芯片批次不一样的原因。在我的板子上不加延时确实不行。
/********************** 主函数 ************************/
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
}
}
//============================================================== jrh200310 发表于 2025-4-21 09:02
在擦除的函数后面跟上一个打印信息,起到延时的作用就正常了,不知道是不是芯片批次不一样的原因。在我的板 ...
我看程序里面IAP_TPS 也设置了,,感觉应该不会因为时间不足导致EEPROM操作失败? 王昱顺 发表于 2025-4-19 20:12
我就是用的楼主原程序,确实是没问题的
王哥哥,,看看楼主最新的回复,,
我看你这里测试的是先 只写入,,,后只读取,,和楼主这里的操作不太一样,,,我的意思是直接使用楼主提供的原程序试一试,,可能就是这点儿差距 _奶咖君_ 发表于 2025-4-21 09:18
王哥哥,,看看楼主最新的回复,,
我看你这里测试的是先 只写入,,,后只读取,,和楼主这里的操作不 ...
我当时直接测试源程序也没问题,直接就出来正常信息了。可能是芯片体质不同?
我用的是11.0592mhz主频
页:
[1]
2