解决stc8h2k12u读EEPROM的一点小问题,求大神们验证
以前用STC8H8K64U读写EEPROM,使用官方例程,一向都正常,但近日换用STC8H2K12U-SOP16时,却出现了一点小问题。现象是当连续写入,再连续读出时,读出的第0字节是错误的,正确的数据跑到第1字节了,第1字节的正确数据跑到第2字节了----- 依此类推。
具体请参考:https://www.stcaimcu.com/thread-18985-1-1.html
源代码如下:
/*---------------------------------------------------------------------*/
/* --- Web: www.STCAI.com ---------------------------------------------*/
/*---------------------------------------------------------------------*/
#include "stc8h.h"
#include "intrins.h"
#include "stdio.h"
/*************本程序功能说明**************
对STC内部自带的EEPROM(FLASH)进行读写测试。
对FLASH做扇区擦除、写入、读出的操作。
通过串口打印读取EEPROM结果。
注意:下载时,下载界面"硬件选项"中设置用户EEPROM大小,
并确保擦除、写入、读出的地址在EEPROM设置的大小范围之内。
下载时, 选择时钟 11.0592MHz (用户可自行修改频率)。
******************************************/
#define MAIN_Fosc 11059200L //定义主时钟参数
#define BAUD 115200
#define TM (65536 -(MAIN_Fosc/BAUD/4))
#define OFFSET 12 //EEPROM起始地址
typedef unsigned char u8;
typedef unsigned int u16;
typedef unsigned long u32;
void PrintfInit(void)
{
SCON = (SCON & 0x3f) | 0x40;
AUXR |= 0x40; //定时器时钟1T模式
AUXR &= 0xFE; //串口1选择定时器1为波特率发生器
TL1= TM;
TH1= TM>>8;
TR1 = 1; //定时器1开始计时
// SCON = (SCON & 0x3f) | 0x40;
// T2L= TM;
// T2H= TM>>8;
// AUXR |= 0x15; //串口1选择定时器2为波特率发生器
}
void UartPutc(unsigned char dat)
{
SBUF = dat;
while(TI == 0);
TI = 0;
}
char putchar(char c)
{
UartPutc(c);
return c;
}
void IapIdle()
{
IAP_CONTR = 0; //关闭IAP功能
IAP_CMD = 0; //清除命令寄存器
IAP_TRIG = 0; //清除触发寄存器
IAP_ADDRH = 0x80; //将地址设置到非IAP区域
IAP_ADDRL = 0;
}
unsigned char IapRead(int addr)
{
char dat;
IAP_CONTR = 0x80; //使能IAP
IAP_CMD = 1; //设置IAP读命令
IAP_ADDRL = addr; //设置IAP低地址
IAP_ADDRH = addr >> 8; //设置IAP高地址
IAP_TRIG = 0x5a; //写触发命令(0x5a)
IAP_TRIG = 0xa5; //写触发命令(0xa5)
_nop_();
dat = IAP_DATA; //读IAP数据
IapIdle(); //关闭IAP功能
return dat;
}
void IapProgram(int addr, unsigned char dat)
{
IAP_CONTR = 0x80; //使能IAP
IAP_CMD = 2; //设置IAP写命令
IAP_ADDRL = addr; //设置IAP低地址
IAP_ADDRH = addr >> 8; //设置IAP高地址
IAP_DATA = dat; //写IAP数据
IAP_TRIG = 0x5a; //写触发命令(0x5a)
IAP_TRIG = 0xa5; //写触发命令(0xa5)
_nop_();
IapIdle(); //关闭IAP功能
}
void IapErase(int addr)
{
IAP_CONTR = 0x80; //使能IAP
IAP_CMD = 3; //设置IAP擦除命令
IAP_ADDRL = addr; //设置IAP低地址
IAP_ADDRH = addr >> 8; //设置IAP高地址
IAP_TRIG = 0x5a; //写触发命令(0x5a)
IAP_TRIG = 0xa5; //写触发命令(0xa5)
_nop_(); //
IapIdle(); //关闭IAP功能
}
void Delay1000ms(void) //@11.0592MHz
{
unsigned char data i, j, k;
i = 57;
j = 27;
k = 112;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
void main()
{
unsigned char i;
unsigned char a;
P0M1 = 0; P0M0 = 0; //设置为准双向口
P1M1 = 0; P1M0 = 0; //设置为准双向口
P2M1 = 0; P2M0 = 0; //设置为准双向口
P3M1 = 0; P3M0 = 0; //设置为准双向口
P4M1 = 0; P4M0 = 0; //设置为准双向口
P5M1 = 0; P5M0 = 0; //设置为准双向口
IAP_TPS = 11; //设置EEPROM操作等待参数(11.0592MHz),初始化设置一次即可
PrintfInit();
Delay1000ms(); //@11.0592MHz
Delay1000ms(); //@11.0592MHz
printf("Read1="); //读取EEPROM原先的内容
for(i=0;i<10;i++)
{
a = IapRead(OFFSET+i);
printf("0x%02bx ",a);
if(a == 0xff) a = i;//如果内容为空,则写入初始化数据
else a++; //如果内容非空,在原先基础上加1
}
printf("\r\n");
IapErase(OFFSET); //如果擦写范围跨扇区,需要擦除两个扇区的空间
for(i=0;i<10;i++)
{
IapProgram(OFFSET+i, a);
}
printf("Read2="); //擦除、重写后,读取EEPROM现在的内容
for(i=0;i<10;i++)
{
a = IapRead(OFFSET+i);
printf("0x%02bx ",a);
}
printf("\r\n");
while (1);
}
经过多次测试,发现加长读函数的延时,即可解决,
改后的读函数如下:
unsigned char IapRead(int addr)
{
char dat;
IAP_CONTR = 0x80; //使能IAP
IAP_CMD = 1; //设置IAP读命令
IAP_ADDRL = addr; //设置IAP低地址
IAP_ADDRH = addr >> 8; //设置IAP高地址
IAP_TRIG = 0x5a; //写触发命令(0x5a)
IAP_TRIG = 0xa5; //写触发命令(0xa5)
_nop_();_nop_();
dat = IAP_DATA; //读IAP数据
IapIdle(); //关闭IAP功能
return dat;
}
该问题请大家测试一下。谢谢!
在读函数中延时没有加长的情况下,测试时,可以将
#define OFFSET 12 //EEPROM起始地址
中的12改为0
刚才没有改成0,有一次是没有问题的,然后改为0,又出现了问题 看AiCube生成的和8H手册里都是四个NOP。
1L这个例程可能时间长了没维护吧。使用AiCube一键生成~
ercircle 发表于 2025-7-11 10:04
看AiCube生成的和8H手册里都是四个NOP。
1L这个例程可能时间长了没维护吧。使用AiCube一键生成~
难怪。
我是加长延时解决问题的。
估计STC8H2K12U在读取EEPROM时,要比STC8H8K64U稍微快了那么一点点
我一般直接读取地址。addr是eeprom多少字节,IAP_OFFSET是eeprom的基址
char IAP_Read_MOVC(int addr) //读取EEPROM
{
addr += IAP_OFFSET;
return *(char code *)(addr);
} _依如画 发表于 2025-7-11 15:45
我一般直接读取地址。addr是eeprom多少字节,IAP_OFFSET是eeprom的基址
char IAP_Read_MOVC(int addr) //读 ...
那么,写入又如何操作?用官方的函数void IapProgram(unsigned int addr, unsigned char dat)吗? _依如画 发表于 2025-7-11 15:45
我一般直接读取地址。addr是eeprom多少字节,IAP_OFFSET是eeprom的基址
char IAP_Read_MOVC(int addr) //读 ...
请问eeprom的基址怎样计算?
IAP 是从 0000H 开始
神农鼎 发表于 2025-7-11 22:20
IAP 是从 0000H 开始
好的,我试试
页:
[1]