1301 字
7 分钟
STC EEPROM基础操作
2022-08-23

前言#

MCU:STC8G1K08-16Pin(DIP-16)

STC8G 系列单片机内部都集成了大容量的 EEPROM。利用 ISP/IAP 技术可将内部 Data Flash 当 EEPROM,擦写次数在 10 万次以上。EEPROM 可分为若干个扇区,每个扇区包含 512 字节。

以 STC8G1K08 为例,芯片集成了 4K(即 4096 Byte) 的 EEPROM (0000h ~ 0FFFh)。

详见 STC8G 芯片手册:15 IAP/EEPROM/DATA-FLASH


擦除操作#

在了解擦除操作前,需要了解:EEPROM 的写操作只能将 1 写为 0,如果需要将 0 写为 1,就必须先擦除整个扇区

IAP_CONTR,EEPROM 控制寄存器。

IAP_TRIG,EEPROM 触发寄存器,每次对 EEPROM 操作后都需要按顺序写入 0x5a 和 0xa5,才能生效。

IAP_ADDRHIAP_ADDRL,分别是 EEPROM 地址的高8位和低8位。

  • 以 STC8G1K08 为例,IAP_ADDR 的范围在 0000h ~ 0FFFh

IAP_TPS = SYSCLK / 1000000,EEPROM 等待时间空间寄存器。

  • 如果芯片工作频率是 11.0592MHz,IAP_TPS 就设置为 11
  • 如果芯片工作频率是 12MHz,IAP_TPS 就设置为 12
  • 小数部分四舍五入取整
/*
* void IapIdle()
* @brief 关闭 IAP 功能
*/
void IapIdle()
{
IAP_CONTR = 0; // 15.2.5 禁止 EEPROM 操作
IAP_CMD = 0; // 15.2.3 空操作 清除命令寄存器
IAP_TRIG = 0; // 15.2.4 清除触发寄存器
IAP_ADDRH = 0x80; // 15.2.2 将地址设置到非IAP区域
IAP_ADDRL = 0;
}
/*
* void IapErase(int addr)
* @brief 擦除 addr 所在扇区
*/
void IapErase(int addr)
{
IAP_CONTR = 0x80; // 15.2.5 使能 EEPROM 操作
IAP_TPS = 11; // 15.2.6 设置等待参数11.0592MHz
IAP_CMD = 0x03; // 15.2.3 设置IAP擦除命令
IAP_ADDRL = addr; //设置IAP低地址
IAP_ADDRH = addr >> 8; //设置IAP高地址
IAP_TRIG = 0x5a; //写触发命令(0x5a)
IAP_TRIG = 0xa5; //写触发命令(0xa5)
_nop_();
IapIdle(); //关闭IAP功能
}

写操作#

写操作前先擦除目标地址所在区块,以保证目标地址的原始数据是 0xFF!

IAP_DATA,EEPROM 数据寄存器(8 bit)。

/*
* void IapProgram(int addr, char dat)
* @brief 在 addr 处写入 dat 字节
*/
void IapProgram(int addr, char dat)
{
IAP_CONTR = 0x80; //使能IAP
IAP_TPS = 11; //设置等待参数11.0592MHz
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功能
}

读操作#

/*
* char IapRead(int addr)
* @brief 读取在 addr 处的字节数据
*/
char IapRead(int addr)
{
char dat;
IAP_CONTR = 0x80; //使能IAP
IAP_TPS = 11; //设置等待参数11.0592MHz
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;
}

完整代码#

代码 - 点击查看详情
#include <STC8G.h>
#include <intrins.h>
/*
* void IapIdle()
* @brief 关闭 IAP 功能
*/
void IapIdle()
{
IAP_CONTR = 0; // 15.2.5 禁止 EEPROM 操作
IAP_CMD = 0; // 15.2.3 空操作 清除命令寄存器
IAP_TRIG = 0; // 15.2.4 清除触发寄存器
IAP_ADDRH = 0x80; // 15.2.2 将地址设置到非IAP区域
IAP_ADDRL = 0;
}
/*
* char IapRead(int addr)
* @brief 读取在 addr 处的字节数据
*/
char IapRead(int addr)
{
char dat;
IAP_CONTR = 0x80; //使能IAP
IAP_TPS = 11; //设置等待参数11.0592MHz
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, char dat)
* @brief 在 addr 处写入 dat 字节
*/
void IapProgram(int addr, char dat)
{
IAP_CONTR = 0x80; //使能IAP
IAP_TPS = 11; //设置等待参数11.0592MHz
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)
* @brief 擦除 addr 所在扇区
*/
void IapErase(int addr)
{
IAP_CONTR = 0x80; // 15.2.5 使能 EEPROM 操作
IAP_TPS = 11; // 15.2.6 设置等待参数11.0592MHz
IAP_CMD = 0x03; // 15.2.3 设置IAP擦除命令
IAP_ADDRL = addr; //设置IAP低地址
IAP_ADDRH = addr >> 8; //设置IAP高地址
IAP_TRIG = 0x5a; //写触发命令(0x5a)
IAP_TRIG = 0xa5; //写触发命令(0xa5)
_nop_();
IapIdle(); //关闭IAP功能
}
bit busy = 0;
void UartIsr() interrupt 4
{
if (TI)
{
TI = 0;
busy = 0;
}
if (RI)
{
RI = 0;
}
}
void UartSend(char dat)
{
while (busy);
busy = 1;
SBUF = dat;
}
void UartSendStr(char *p)
{
while (*p)
{
UartSend(*p++);
}
}
void TimeInit(void)
{
AUXR = 0x40;
TMOD = 0x00;
SCON = 0x50;
TL1 = 0xE8;
TH1 = 0xFF;
ET1 = 0;
TR1 = 1;
ES = 1;
EA = 1;
}
void Delay1000ms() //@11.0592MHz
{
unsigned char i, j, k;
i = 57;
j = 27;
k = 112;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
char EEPROM_Dat;
void main()
{
P1M0 = 0x00;
P1M1 = 0x00;
P3M0 = 0x00;
P3M1 = 0x00;
P5M0 = 0x00;
P5M1 = 0x00;
TimeInit();
Delay1000ms();
Delay1000ms();
UartSendStr("0000");
Delay1000ms();
Delay1000ms();
/* STC8G1K08
* EEPROM 0000h ~ 0FFFh 4K
*/
//擦除 0x0400 所在扇区
IapErase(0x0400);
EEPROM_Dat = IapRead(0x0400);
UartSend(EEPROM_Dat);
Delay1000ms();
//在 0x0400 和 0x0401 处写入字节 0x12 和 0x0c
IapProgram(0x0400, 0x12);
IapProgram(0x0401, 0x0c);
//读取在 0x0400 和 0x0401 处的数据,并通过串口发送
EEPROM_Dat = IapRead(0x0400);
UartSend(EEPROM_Dat);
Delay1000ms();
EEPROM_Dat = IapRead(0x0401);
UartSend(EEPROM_Dat);
Delay1000ms();
while (1);
}
STC EEPROM基础操作
https://fuwari.vercel.app/posts/嵌入式/stc/stc-eeprom基础操作/
作者
Asuwee
发布于
2022-08-23
许可协议
CC BY-NC-SA 4.0