当前位置: 首页 > news >正文

【STC库函数】使用芯片自带的EEPROM来保存掉电不丢失的数据

之前开源过集成俩STC芯片的核心板,可以往回翻翻。

用的芯片是STC32G12K128和STC8G1K08。

那我来考你一考,它们为什么叫这个名字。

图片

其实很简单,我们直接看它的手册。

STC是它的公司名,32表示这个32位单片机,G是系列。

图片

12K是因为内部的SRAM和扩展RAM一共12K字节。

128则是Flash存储器是128K字节的。

我们烧录的程序就在这个Flash里,但是我们烧录的程序大小是多少呢?

图片

以官方库函数里的综合示例程序为例,它可是把能包含的都包含进去了,编译出来才31K。

就算你程序更复杂我再给你翻个倍,那也才60+K的大小,而我板子用的这个芯片可是有128K的Flash,这不是很浪费嘛?

这时候我们对这块空间可以有别的用法🤓👆。

比如说我们对单片机有一些配置不是一开始写在程序里的,而是后续用户自己配置的,那么这些配置参数是需要单独保存起来的,是要掉电不丢失的,那么我们可以把这些数据放到Flash里,反正程序用不了这么大的空间,和尚摸得我摸不得?

图片

问题在于我们应该如何使用,这时候又要翻一翻手册了。

图片

EEPROM是使用是需要先擦除再写入的,因为我们写操作只能把1变成0,但是没法把0变成1(0和1表示的是二进制的bit值,请不要有端联想)。

如果要让0变成1,那么就需要一次性把512个Byte的每个bit都变成1,也就是擦除一整个扇区。

这个是EEPROM的物理结构决定的,反正我们在写数据之前先擦除就对了。

图片

接着是EEPROM的操作时间,读取一个字节是4个系统时钟,我们用的时钟频率是24MHz,那么4个系统时间就是差不多167ns。

写入一个字节是30~40us。

擦除一个扇区比较花时间,因为是对512个字节进行操作,要4~6ms。

所以我们操作EEPROM的时候要注意一下时间。

那么说了一大堆,我们到底要怎么操作EEPROM呢?

使用库函数的话是非常简单的,因为都给我们封装好了。

图片

把.c文件包含进编译里。

把.h文件包含进文件里。

一共是三个函数,我们直接一起看,因为非常简单。

图片

首先是它们都需要的参数是EEPROM的地址,这一点后面再说。

读写函数的参数要多两个,是要写入(读出)的数据缓冲区地址,还有要写入(读出)的数据长度。

虽然文档里写的是一次性只能写入或读出一个字节的数据,但是库函数都封装好了,我们可以“一次性”写入或读出一堆字节。

我们使用EEPROM的流程就是如果要写入数据,那么写之前先擦除。

如果要读的话可以直接读。

最后剩下一个问题就是EEPROM的地址了。

图片

参考手册里的说法,使用IAP方式的时候地址从0000开始,使用MOV指令则是FE0000。

而我们库函数里妥妥是IAP方式,所以我们操作EEPROM的地址从0000开始。

可以参考一下下表。

虽然上面说从0000开始,但结束可不是在FFFF结束,是从下表可知,128K大小最极端的结束地址是1FFFF。

图片

关于我们使用多大的空间用于EEPROM,我们可以在烧录程序的时候设置,在官方烧录软件里。

图片

根据自己的需求来改哈,一般存储几个数据的话有个几K就很够用了。

接下来我们实操一下。

先是从000000这个地址开始擦除一个扇区的数据(512Byte),接着在000000这个地址写入一个字节0,我用它来记录芯片启动的次数。

先将上述步骤的程序烧录进去初始化一下。

接着就可以进入正题了,首先读出000000这个地址的一个byte的数据,取出来后加一再写进去,写之前先擦除。

#include "STC32G_GPIO.h"
#include "STC32G_Delay.h"
#include "STC32G_NVIC.h"
#include "STC32G_UART.h"
#include "STC32G_EEPROM.h"
#include "STC32G_Switch.h"void GPIO_Init(void){P0_MODE_IN_HIZ(GPIO_Pin_0);P0_MODE_OUT_PP(GPIO_Pin_1);
}void UART_Init(void){COMx_InitDefine initer;initer.BaudRateDouble = DISABLE;initer.Morecommunicate = DISABLE;initer.UART_BaudRate = 115200;initer.UART_BRT_Use = BRT_Timer3;initer.UART_Mode = UART_8bit_BRTx;initer.UART_RxEnable = DISABLE;UART_Configuration(UART3, &initer);NVIC_UART3_Init(ENABLE, Priority_3);UART3_SW(UART3_SW_P00_P01);
}void main(void){uint8 count = 0;WTST = 0;    //设置程序指令延时参数,赋值为0可将CPU执行指令的速度设置为最快EAXSFR();    //扩展SFR(XFR)访问使能 CKCON = 0;      //提高访问XRAM速度GPIO_Init();    UART_Init();EA = 1;// 第一次先把地址为0的字节修改为0// EEPROM_SectorErase(0x000000);// EEPROM_write_n(0x000000, &count, 1);// 后续就先读出数据,加一后写回去EEPROM_read_n(0x000000, &count, 1);printf("read count is %d, ", count);EEPROM_SectorErase(0x000000);count++;printf("write count is %d\r\n", count);EEPROM_write_n(0x000000, &count, 1);while(1){delay_ms(1000);}
}

​​​​​​​没问题,可以正常读写数据。

图片

最后需要提醒的还是写数据之前要先擦除扇区数据。

如果你有十个字节的数据放在了一起,但是你需要修改其中一个字节的数据,那么你要做的是把十个数据都取出来,把要修改的数据修改完之后,擦除这个扇区,最后把十个数据再次写进去。

因此建议把同一批次修改的数据放在同一个扇区。

http://www.dtcms.com/a/360221.html

相关文章:

  • 开发常用工具专栏
  • 赵玉平《梁山政治》读书笔记(下部)
  • wifi控制舵机
  • WinExec
  • Nginx反向代理及配置
  • c++ 线程局部存储(Thread-Local Storage,TLS)
  • Langflow Memory 技术深度分析
  • java--浅拷贝深拷贝
  • Introduction to GIS —— Chapter 3(Vector Data Model)
  • 雪花算法生成分布式ID
  • AI 智能体汇总,自动执行任务的“真 Agent”
  • 动态规划入门(三):一些经典动态规划模型
  • 赵玉平《刘备谋略》读书笔记(下部)
  • 小迪自用web笔记22
  • 01背包day35
  • 设计模式 | 常见的设计模式(单例、工厂、代理、适配器、责任链等等)
  • VisionProC#联合编程火花塞距离检测与VisionPro操作
  • libmodbus库,c++配置方法
  • 【CUDA入门·Lesson 1】Ubuntu实战:CUDA 概念、nvidia-smi 工具与 GPU 参数详解
  • 在Unity中,让子物体不随父物体移动或转动的方法!
  • 下一代防火墙(NGFW):从定义到功能
  • 试试 Xget 加速 GitHub 克隆仓库
  • 【WEB】[BUUCTF] <GXYCTF2019禁止套娃>《php函数的运用》
  • 大模型RAG项目实战:向量数据库Faiss
  • 【初始web3】什么是web3
  • 大模型时代:用Redis构建百亿级向量数据库方
  • 【自记】 Python 中函数参数前加 *(单星号)的解包可迭代对象写法说明
  • OpenCL C 内存对象
  • 第2.5节:中文大模型(文心一言、通义千问、讯飞星火)
  • 在线图片特效工具,600种创意模板