Skip to content

EEPROM

一.EEPROM简介

EEPROM(Electrically Erasable Programmable Read-Only Memory,电子可擦可编程只读存储器)是一种非易失性存储器,它可以在断电后保留数据。EEPROM通常用于存储需要长期保存的数据,如系统配置、用户设置等。

STC8G系列单片机内置了EEPROM,其容量为4K字节。EEPROM的读写操作需要通过特定的指令来完成。

EEPROM

二.示例代码

以下程序的代码的作用是,将EEPROM中的数据读取出来,并打印到串口上. 如果串口发送了数据,则将数据写入EEPROM中.
系统主系统时钟为11.0592MHz,波特率为9600.

关于串口的接收数据的方法,请参考: 串口通信

1.扇区删除函数

c
// EEPROM操作函数实现
void EEPROM_SectorErase(unsigned int addr) {
    IAP_CONTR = 0x80;   // 使能IAP
    IAP_CMD = 0x03;     // 扇区擦除命令
    IAP_ADDRH = addr >> 8;
    IAP_ADDRL = addr & 0xFF;
    IAP_TRIG = 0x5A;
    IAP_TRIG = 0xA5;
    _nop_();
    _nop_();
    IAP_CONTR = 0x00;   // 关闭IAP
}

2.字节写入函数

c
// EEPROM字节写入
void EEPROM_ByteWrite(unsigned int addr, unsigned char dat) {
    IAP_CONTR = 0x80;   // 使能IAP
    IAP_CMD = 0x02;     // 字节编程命令
    IAP_ADDRH = addr >> 8;
    IAP_ADDRL = addr & 0xFF;
    IAP_DATA = dat;
    IAP_TRIG = 0x5A;
    IAP_TRIG = 0xA5;
    _nop_();
    _nop_();
    IAP_CONTR = 0x00;   // 关闭IAP
}

3.字节读取函数

c
// EEPROM字节读取
unsigned char EEPROM_ByteRead(unsigned int addr) {
    unsigned char dat;
    IAP_CONTR = 0x80;   // 使能IAP
    IAP_CMD = 0x01;     // 字节读取命令
    IAP_ADDRH = addr >> 8;
    IAP_ADDRL = addr & 0xFF;
    IAP_TRIG = 0x5A;
    IAP_TRIG = 0xA5;
    _nop_();
    dat = IAP_DATA;
    IAP_CONTR = 0x00;   // 关闭IAP
    return dat;
}

三.完整代码

c
#include "stc8g.h"
#include "intrins.h"
#include <string.h>

// EEPROM操作函数声明
void EEPROM_SectorErase(unsigned int addr);
void EEPROM_ByteWrite(unsigned int addr, unsigned char dat);
unsigned char EEPROM_ByteRead(unsigned int addr);

bit uartReceived = 0;
unsigned char receivedData = 0;

// 用户参数结构体
typedef struct {
    unsigned int param1;
    float param2;
    char param3[16];
} UserParams;

// 串口中断服务函数
void UART_ISR() interrupt 4 {
    if(RI) {
        RI = 0;  // 清除接收中断标志
        receivedData = SBUF;  // 读取接收到的数据
        uartReceived = 1;     // 设置接收标志
    }
    if(TI) {
        TI = 0;  // 清除发送中断标志
    }
}

// 添加串口初始化函数
void UART_Init() {
    SCON = 0x50;        // 8位数据,可变波特率
    AUXR |= 0x40;       // 定时器1时钟为Fosc,即1T
    AUXR &= 0xFE;       // 串口1选择定时器1为波特率发生器
    TMOD &= 0x0F;       // 设定定时器1为16位自动重装方式
    TL1 = 0xE0;         // 设定定时初值
    TH1 = 0xFE;         // 设定定时初值
    ET1 = 0;            // 禁止定时器1中断
    TR1 = 1;            // 启动定时器1
}



// 串口发送一个字符
void UART_SendChar(char c) {
    SBUF = c;
    while(!TI);
    TI = 0;
}

// 串口发送字符串
void UART_SendString(char *s) {
    while(*s) {
        UART_SendChar(*s++);
    }
}


// EEPROM操作函数实现
void EEPROM_SectorErase(unsigned int addr) {
    IAP_CONTR = 0x80;   // 使能IAP
    IAP_CMD = 0x03;     // 扇区擦除命令
    IAP_ADDRH = addr >> 8;
    IAP_ADDRL = addr & 0xFF;
    IAP_TRIG = 0x5A;
    IAP_TRIG = 0xA5;
    _nop_();
    _nop_();
    IAP_CONTR = 0x00;   // 关闭IAP
}

// EEPROM字节写入
void EEPROM_ByteWrite(unsigned int addr, unsigned char dat) {
    IAP_CONTR = 0x80;   // 使能IAP
    IAP_CMD = 0x02;     // 字节编程命令
    IAP_ADDRH = addr >> 8;
    IAP_ADDRL = addr & 0xFF;
    IAP_DATA = dat;
    IAP_TRIG = 0x5A;
    IAP_TRIG = 0xA5;
    _nop_();
    _nop_();
    IAP_CONTR = 0x00;   // 关闭IAP
}

// EEPROM字节读取
unsigned char EEPROM_ByteRead(unsigned int addr) {
    unsigned char dat;
    IAP_CONTR = 0x80;   // 使能IAP
    IAP_CMD = 0x01;     // 字节读取命令
    IAP_ADDRH = addr >> 8;
    IAP_ADDRL = addr & 0xFF;
    IAP_TRIG = 0x5A;
    IAP_TRIG = 0xA5;
    _nop_();
    dat = IAP_DATA;
    IAP_CONTR = 0x00;   // 关闭IAP
    return dat;
}

// 保存用户参数到EEPROM
void SaveUserParams(UserParams *params, unsigned int baseAddr) {
    unsigned char *p = (unsigned char *)params;
    unsigned int i;
    
    // 先擦除整个扇区
    EEPROM_SectorErase(baseAddr);
    
    // 写入数据
    for(i = 0; i < sizeof(UserParams); i++) {
        EEPROM_ByteWrite(baseAddr + i, p[i]);
    }
}

// 从EEPROM读取用户参数
void LoadUserParams(UserParams *params, unsigned int baseAddr) {
    unsigned char *p = (unsigned char *)params;
    unsigned int i;
    
    for(i = 0; i < sizeof(UserParams); i++) {
        p[i] = EEPROM_ByteRead(baseAddr + i);
    }
}

void Delay1s() {
    unsigned int i, j;
    for(i = 0; i < 5000; i++) {
        for(j = 0; j < 1000; j++) {
            _nop_();
        }
    }
}

// 示例主函数
void main() {
    UserParams params;
    UserParams params2;
    char str[10];  // 用于存储转换后的字符串
    unsigned int eepromBaseAddr = 0x0000; // EEPROM起始地址
	
	UART_Init();

    // 添加这两行启用中断
    ES = 1;      // 使能串口中断
    EA = 1;      // 开启全局中断
    
    // 初始化IAP等待时间
    IAP_TPS = 12; // 根据系统时钟设置
    
    // 修改参数
    params.param1 = 1234;
    params.param2 = 3.14f;
    strcpy(params.param3, "STC8G1K08A");
    
    // 保存修改后的参数
    SaveUserParams(&params, eepromBaseAddr);

    while(1) {
    // 主循环
    if(uartReceived){ // 检查是否有数据接收
        uartReceived = 0;  // 清除标志
        params.param1 = receivedData;
        // 保存修改后的参数
        SaveUserParams(&params, eepromBaseAddr);
        UART_SendString("Save Sucess\r\n");
    }
	// 从EEPROM加载参数
    LoadUserParams(&params2, eepromBaseAddr);
    // 打印参数
    UART_SendString("Loaded User Params:\r\n");
    UART_SendString("param1: ");
    // 将param1转换为字符串并发送
    
    sprintf(str, "%d", params2.param1);  // 将param1转换为字符串
    UART_SendString(str);  // 发送转换后的字符串
    UART_SendString("\r\n");

    UART_SendString("param2: ");
    // 将param2转换为字符串并发送
    sprintf(str, "%.2f", params2.param2);  // 将param2转换为字符串,保留两位小数
    UART_SendString(str);  // 发送转换后的字符串
    UART_SendString("\r\n");


    UART_SendString("param3: ");
    UART_SendString(params2.param3);
    UART_SendString("\r\n");  
    Delay1s();  // 添加1秒延时
    }
}