RYMCU

NO18.内部EEPROM读写实验-NEBULA-VSCODE

devcui 1 年前
# nebula-vscode

所属作品集

EEPROM

EEPROM 简单来说就是存储数据的元器件,断电后数据依然可以被保存。

STC89C51/52 内部自带 2K 字节的 E2PROM

ISP/IAP

点我了解更多

  • 1.ISP: In system programable 在系统编程
  • 2.IAP: In application programable 在应用编程

STC89C52 存储空间有

  • a.8KB flash 地址 0-1FFFH
  • b.512B RAM 地址 0-0200H
  • c.2KB EEPROM 地址 2000H-27FFH

ISP 操作对象为 8KB flash
IAP 操作对象为 2KB EEPROM

EEPROM 分为 4 个扇区每个 512B

image.png

操作步骤

扇区

  • a. 将想保留的数据存到 RAM
  • b. 对扇区进行擦除操作,擦除后扇区数据为 FFH
  • c. 写字节到扇区
  • d. 将暂存数据写回扇区

寄存器

image.png

  • a. 配置 ISP_CONTR 寄存器,配置 ISPEN 生效,配置 WT2,WT1,WT0 三位等待时间
  • b. 写指令: 读/写/擦三种命令
  • c. 赋值 ISP_ADDRH 和 ISP_ADDRL 地址值,分别为操作地址的高低位
  • d. 关闭总中断 EA
  • e. 执行 ISP_IAP 触发指令,触发后才能进行读写
  • f. 打开总中断 EA,关闭 ISP_IAP 功能,清除相关寄存器

image.png

    1. ISP_DATA: ISP/IAP 数据寄存器
    1. ISP_ADDRH/ISP_ADDRL: ISP/IAP 地址寄存器
    1. ISP_CMD: ISP/IAP 命令寄存器
      • 3.1: MS1 MS0 = 00 待机模式,无法进行读写
      • 3.2: MS1 MS0 = 01 从应用程序区对 DATA FLASH/E2PROM 进行读字节命令
      • 3.3: MS1 MS0 = 10 从应用程序区对 DATA FLASH/E2PROM 进行写字节命令
      • 3.4: MS1 MS0 = 11 从应用程序区对 DATA FLASH/E2PROM 进行擦除命令
    1. ISP_TRIG: ISP/IAP 命令触发器
    1. ISP_CONTR: ISP/IAP 控制寄存器
      • 5.1: ISPEN ISP/IAP 功能允许位,ISPEN=0 禁止读写擦除,ISPEN=1 允许读写擦除
      • 5.2: SWBS=0 软件从应用程序区启动,SWBS=1 从系统 ISP 监控程序区启动,需与 SWRST 配合使用
      • 5.3: SWRST: 0 不操作,1 表示产生软件系统复位,硬件自动复位
      • 5.4: SWBS SWRST = 1 1 表示应用程序区软件复位并从系统 ISP 监控程序区开始执行程序
      • 5.5: SWBS SWRST = 0 1 表示应用程序区软件复位并从应用程序区开始处执行程序
      • 5.6: WT2 WT1 WT0 表示读写擦操作 CPU 插入的等待时间如下图表示
      • 5.7 image.png

EEPROM 驱动函数编写

/*
 * @Author: cuihaonan
 * @Email: devcui@outlook.com
 * @Date: 2021-04-08 22:19:28
 * @LastEditTime: 2021-04-08 22:34:36
 * @LastEditors: cuihaonan
 * @Description: Basic description
 * @FilePath: /sdcc-include/src/eeprom/include/eeprom.h
 * @LICENSE: NONE
 */
#ifndef __EEPROM_H__
#define __EEPROM_H__
// 关闭ISP_IAP
extern void ISP_IAP_disable(void);
// 触发
extern void ISP_IAP_trigger(void);
// 读取数据
extern void ISP_IAP_readData(unsigned int beginAddr, unsigned char *pBuf, unsigned int dataSize);
// 写数据
extern void ISP_IAP_writeData(unsigned int beignAddr, unsigned char *pDat, unsigned int dataSize);
// 扇区擦除
extern void ISP_IAP_sectorErase(unsigned int sectorAddr);
#endif
/*
 * @Author: cuihaonan
 * @Email: devcui@outlook.com
 * @Date: 2021-04-08 22:25:23
 * @LastEditTime: 2021-04-08 22:34:26
 * @LastEditors: cuihaonan
 * @Description: Basic description
 * @FilePath: /sdcc-include/src/eeprom/include/eeprom.c
 * @LICENSE: NONE
 */
#include "../../../include/STC89xx.h"
#include "./eeprom.h"
// 读
#define read_cmd 0x01
// 写
#define wirte_cmd 0x02
// 擦
#define erase_cmd 0x03
// 等待计时
#define enable_waitTime 0x82

// 关闭ISP_IAP
void ISP_IAP_disable(void)
{
    EA = 1;
    ISP_CONTR = 0x00;
    ISP_CMD = 0x00;
    ISP_TRIG = 0x00;
}

// 触发
void ISP_API_trigger(void)
{
    EA = 0;
    ISP_TRIG = 0x46;
    ISP_TRIG = 0xB9;
}

// 读取数据
void ISP_API_readData(unsigned int beginAddr, unsigned char *pBuf, unsigned int dataSize)
{
    ISP_DATA = 0;
    ISP_CMD = read_cmd;
    ISP_CONTR = enable_waitTime;
    while (dataSize--)
    {
        ISP_ADDRH = (unsigned char)(beginAddr >> 8);
        ISP_ADDRL = (unsigned char)(beginAddr & 0x00FF);
        ISP_IAP_trigger();
        beginAddr++;
        *pBuf++ = ISP_DATA;
    }
    ISP_IAP_dsiable();
}

// 写数据
void ISP_IAP_writeData(unsigned int beignAddr, unsigned char *pDat, unsigned int dataSize)
{
    ISP_CONTR = enable_waitTime;
    ISP_CMD = wirte_cmd;
    while (dataSize--)
    {
        ISP_ADDRH = (unsigned char)(beignAddr >> 8);
        ISP_ADDRL = (unsigned char)(beignAddr & 0x00FF);
        ISP_DATA = *pDat++;
        beignAddr++;
        ISP_IAP_trigger();
    }
    ISP_IAP_dsiable();
}

// 扇区擦除
void ISP_IAP_sectorErase(unsigned int sectorAddr)
{
    ISP_CONTR = enable_waitTime;
    ISP_CMD = erase_cmd;
    ISP_ADDRH = (unsigned char)(sectorAddr >> 8);
    ISP_ADDRH = (unsigned char)(sectorAddr & 0x00FF);
    ISP_IAP_trigger();
    ISP_IAP_disable();
}

EEPROM 应用

下面我们下一个小的应用程序来验证我们驱动函数,函数实现的功能为记录
开发板上电的次数。并把上电的次数,显示到 1602 液晶显示器上

/*
 * @Author: cuihaonan
 * @Email: devcui@outlook.com
 * @Date: 2021-04-08 21:44:53
 * @LastEditTime: 2021-04-08 22:39:33
 * @LastEditors: cuihaonan
 * @Description: Basic description
 * @FilePath: /sdcc-include/src/eeprom/main.c
 * @LICENSE: NONE
 */
#include "../../include/STC89xx.h"
#include "./include/eeprom.h"
#include "./include/1602.h"

unsigned char pbuf[5] = {0};
unsigned char str[8] = {0};
unsigned char disp[] = "times of PowerOn";

void main()
{
    Init_1602();
    ISP_IAP_readData(0x21F0, pbuf, sizeof(pbuf));
    pbuf[0]++;
    str[0] = pbuf[0] / 100 + '0';
    str[1] = (pbuf[0] % 100) / 10 + '0';
    str[2] = (pbuf[0] % 10) + '0';
    str[4] = '\0';
    Disp_1602_str(1, 1, disp);
    Disp_1602_str(2, 6, str);
    ISP_IAP_sectorErase(0x2000);
    ISP_IAP_writeData(0x21F0, pbuf, sizeof(pbuf));
    while(1);
}

所属作品集

后发布评论