[原创]
STC官方EEPROM程序运行报错原因分析
如下为STC官方给的EEPROM测试读写程序,写的比较不错的,可以借用,但要遵循STC的要求:
/*------------------------------------------------------------------*/
/* --- STC MCU Limited ---------------------------------------------*/
/* --- STC89-90xx Series MCU ISP/IAP/EEPROM Demo -------------------*/
/* --- Mobile: (86)13922805190 -------------------------------------*/
/* --- Fax: 86-755-82905966 ----------------------------------------*/
/* --- Tel: 86-755-82948412 ----------------------------------------*/
/* --- Web: www.STCMCU.com -----------------------------------------*/
/* If you want to use the program or the program referenced in the */
/* article, please specify in which data and procedures from STC */
/*------------------------------------------------------------------*/
#include <\STC\STC89C5xRC.H>
#include
typedef unsigned char BYTE;
typedef unsigned int WORD;
/*Declare SFR associated with the IAP */
sfr IAP_DATA = 0xE2; //Flash data register
sfr IAP_ADDRH = 0xE3; //Flash address HIGH
sfr IAP_ADDRL = 0xE4; //Flash address LOW
sfr IAP_CMD = 0xE5; //Flash command register
sfr IAP_TRIG = 0xE6; //Flash command trigger
sfr IAP_CONTR = 0xE7; //Flash control register
/*Define ISP/IAP/EEPROM command*/
#define CMD_IDLE 0 //Stand-By
#define CMD_READ 1 //Byte-Read
#define CMD_PROGRAM 2 //Byte-Program
#define CMD_ERASE 3 //Sector-Erase
/*Define ISP/IAP/EEPROM operation const for IAP_CONTR*/
//#define ENABLE_IAP 0x80 //if SYSCLK<40MHz
#define ENABLE_IAP 0x81 //if SYSCLK<20MHz
//#define ENABLE_IAP x82 //if SYSCLK<10MHz
//#define ENABLE_IAP 0x83 //if SYSCLK<5MHz
//Start address for STC89C58xx EEPROM
#define IAP_ADDRESS 0x08000
void Delay(BYTE n);
void IapIdle();
BYTE IapReadByte(WORD addr); //字节读取函数
void IapProgramByte(WORD addr, BYTE dat);
void IapEraseSector(WORD addr); //扇区擦除函数
void main()
{
WORD i;
P1 = 0xfe; //1111,1110 System Reset OK
Delay(10); //Delay
IapEraseSector(IAP_ADDRESS); //Erase current sector
for (i=0; i<512; i++) //Check whether all sector data is FF
{
if (IapReadByte(IAP_ADDRESS+i) != 0xff)
goto Error; //If error, break
}
P1 = 0xfc; //1111,1100 Erase successful
Delay(10); //Delay
for (i=0; i<512; i++) //Program 512 bytes data into data flash
{
IapProgramByte(IAP_ADDRESS+i, (BYTE)i);
}
P1 = 0xf8; //1111,1000 Program successful
Delay(10); //Delay
for (i=0; i<512; i++) //Verify 512 bytes data
{
if (IapReadByte(IAP_ADDRESS+i) != (BYTE)i)
goto Error; //If error, break
}
P1 = 0xf0; //1111,0000 Verify successful
while (1);
Error:
P1 &= 0x7f; //0xxx,xxxx IAP operation fail
while (1);
}
/*----------------------------
Software delay function
----------------------------*/
void Delay(BYTE n)
{
WORD x;
while (n--)
{
x = 0;
while (++x);
}
}
/*----------------------------
Disable ISP/IAP/EEPROM function
Make MCU in a safe state
----------------------------*/
void IapIdle()
{
IAP_CONTR = 0; //Close IAP function
IAP_CMD = 0; //Clear command to standby
IAP_TRIG = 0; //Clear trigger register
IAP_ADDRH = 0x80; //Data ptr point to non-EEPROM area
IAP_ADDRL = 0; //Clear IAP address to prevent misuse
}
/*----------------------------
Read one byte from ISP/IAP/EEPROM area
Input: addr (ISP/IAP/EEPROM address)
Output:Flash data
----------------------------*/
BYTE IapReadByte(WORD addr)
{
BYTE dat; //Data buffer
IAP_CONTR = ENABLE_IAP; //Open IAP function, and set wait time
IAP_CMD = CMD_READ; //Set ISP/IAP/EEPROM READ command
IAP_ADDRL = addr; //Set ISP/IAP/EEPROM address low
IAP_ADDRH = addr >> 8; //Set ISP/IAP/EEPROM address high
IAP_TRIG = 0x46; //Send trigger command1 (0x46)
IAP_TRIG = 0xb9; //Send trigger command2 (0xb9)
_nop_(); //MCU will hold here until ISP/IAP/EEPROM operation complete
dat = IAP_DATA; //Read ISP/IAP/EEPROM data
IapIdle(); //Close ISP/IAP/EEPROM function
return dat; //Return Flash data
}
/*----------------------------
Program one byte to ISP/IAP/EEPROM area
Input: addr (ISP/IAP/EEPROM address)
dat (ISP/IAP/EEPROM data)
Output:-
----------------------------*/
void IapProgramByte(WORD addr, BYTE dat)
{
IAP_CONTR = ENABLE_IAP; //Open IAP function, and set wait time
IAP_CMD = CMD_PROGRAM; //Set ISP/IAP/EEPROM PROGRAM command
IAP_ADDRL = addr; //Set ISP/IAP/EEPROM address low
IAP_ADDRH = addr >> 8; //Set ISP/IAP/EEPROM address high
IAP_DATA = dat; //Write ISP/IAP/EEPROM data
IAP_TRIG = 0x46; //Send trigger command1 (0x46)
IAP_TRIG = 0xb9; //Send trigger command2 (0xb9)
_nop_(); //MCU will hold here until ISP/IAP/EEPROM operation complete
IapIdle();
}
/*----------------------------
Erase one sector area
Input: addr (ISP/IAP/EEPROM address)
Output:-
----------------------------*/
void IapEraseSector(WORD addr)
{
IAP_CONTR = ENABLE_IAP; //Open IAP function, and set wait time
IAP_CMD = CMD_ERASE; //Set ISP/IAP/EEPROM ERASE command
IAP_ADDRL = addr; //Set ISP/IAP/EEPROM address low
IAP_ADDRH = addr >> 8; //Set ISP/IAP/EEPROM address high
IAP_TRIG = 0x46; //Send trigger command1 (0x46)
IAP_TRIG = 0xb9; //Send trigger command2 (0xb9)
_nop_(); //MCU will hold here until ISP/IAP/EEPROM operation complete
IapIdle();
}
下载后刚开始程序运行正常,但是耐心点等到最后时刻,就会发现当灯按1111,1110>1111,1100>1111,1000>0111,1000的顺序亮,可是出现0111,1000就是说明出错了,这里错误怎么产生的呢?
原来是因为51MCU内部按一个存储单元 8 位数据进行存储的,而一个扇区512字节,2^8=256,2^9=512,最初定义的WORD型变量 i 为16位,完全可以自增到512来,但是计算机存储器这么的马虎性格,当 i = 255 的时候一个基本存储单元正好全 1 ,当 i = 256 时溢出了,而我们没有做任何处理,于是它还在存储,当然它又从 0 开始存储,而此时 i = 256 与存储单元的值 (就是0)已经不等了,于是当我们最后检验时便会报错出来,至于灯为什么这么亮是报错,请自己看程序吧!
暂无评论,赶紧抢沙发吧