找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 4105|回复: 31
收起左侧

EEPROM掉电存储功能放MCU程序哪里比较好?

[复制链接]
ID:956872 发表于 2021-8-31 16:13 | 显示全部楼层 |阅读模式
我现在按键控制灯的状态及亮度,想要存储状态变量及PWM变量,EEPROM的擦写放在程序哪部分比较好?是放在按键中断里面好呢还是放在主程序里面好。还有怎么做延时存储,比如按键完后10S才自动存储,还不影响主程序的运行。而不是每次按键都要是擦写EEPROM。
回复

使用道具 举报

ID:161164 发表于 2021-8-31 16:48 | 显示全部楼层
开机时
Your_Data = IapReadByte(0x2000);//详细可参考STC_ISP

在while(1)内
if(!Key_In)
{
if(Key_Down_Count>1200000)//时间随你改
{
IapEraseSector(0x2000);//详细可参考STC_ISP
IapProgramByte(0x2000, Your_Data);//详细可参考STC_ISP
}else{
++Key_Down_Count;
}
}else{
Key_Down_Count = 0;
}
回复

使用道具 举报

ID:887371 发表于 2021-8-31 16:49 | 显示全部楼层
变化比较频繁的在断电瞬间保存。
变化很少的在每次更改时保存。
回复

使用道具 举报

ID:956872 发表于 2021-8-31 17:04 | 显示全部楼层
datouyuan 发表于 2021-8-31 16:49
变化比较频繁的在断电瞬间保存。
变化很少的在每次更改时保存。

断电瞬间保存的话,那还得做硬件电路加电容吧。
感觉没必要,考虑的就是要不更改后就擦写,要不就操作完后延时擦写
回复

使用道具 举报

ID:956872 发表于 2021-8-31 17:20 | 显示全部楼层
lkc8210 发表于 2021-8-31 16:48
开机时
Your_Data = IapReadByte(0x2000);//详细可参考STC_ISP

我放在主程序里,这样只要修改变量参数后要等执行完该分支才进行擦写,感觉也可以。不知道怎么去判断EEPROM里的值是否为分支对应的num值。如果IAP_ADDRESS里的值等于num就不再重复擦写了,只有在不等于的时候才进行擦写
void main()
{
        init();
        num=IapReadByte(IAP_ADDRESS);
        while(1)
        {
                 
               
                        switch(num)
                        {
                         case(0):lsd0();
                                       P1=0xfe;
                                     
               IapEraseSector(IAP_ADDRESS);             // 擦除扇区
               IapProgramByte(IAP_ADDRESS,0);                               
                                      break;
                         case(1):lsd1();
               P1=0xfd;
               IapEraseSector(IAP_ADDRESS);             // 擦除扇区
               IapProgramByte(IAP_ADDRESS,1);                                       
                                      break;
                         case(2):lsd2();
                                       P1=0xfb;
                                       IapEraseSector(IAP_ADDRESS);             // 擦除扇区
               IapProgramByte(IAP_ADDRESS,2);       
                                       break;//num++;
                         case(3):lsd3();
                                       P1=0xf7;
                                       IapEraseSector(IAP_ADDRESS);             // 擦除扇区
               IapProgramByte(IAP_ADDRESS,3);       
                                        break;
                         
                        }
回复

使用道具 举报

ID:624769 发表于 2021-8-31 18:35 | 显示全部楼层
掉电存储功能,放在掉电中断里。
掉电检测点定的高一点,比如,3.7V,  这样你能用15毫秒左右的时间,储存东西,足够了。
回复

使用道具 举报

ID:956872 发表于 2021-8-31 19:17 | 显示全部楼层
188610329 发表于 2021-8-31 18:35
掉电存储功能,放在掉电中断里。
掉电检测点定的高一点,比如,3.7V,  这样你能用15毫秒左右的时间,储存 ...

这样纯软件能搞定吗,是得需要硬件电路支持吧
回复

使用道具 举报

ID:624769 发表于 2021-8-31 19:41 | 显示全部楼层
PEB188 发表于 2021-8-31 19:17
这样纯软件能搞定吗,是得需要硬件电路支持吧

不需要,我实测过,当外部电容为47uf时,3.7V低压检测的情况下,发现掉电后有大约15毫秒处理时间,其中10毫秒左右,是Eeprom安全操作时间,足够了,你Eeprom 写一个字节最多7微妙,你可以写将近1000个字节,时间足够了,要是还觉得时间不够,可以适当调大单片机的外部电容,而如果用比较器检测掉电,大约能比掉电检测早发现3毫秒,意义不大。

最后,最关键一点,掉电检测中断一触发进去后,第一件事情是,先关闭所有的输出,不然如果你有强推挽输出点一个LED的话,剩下的电撑不了多久。
回复

使用道具 举报

ID:161164 发表于 2021-8-31 19:44 来自触屏版 | 显示全部楼层
PEB188 发表于 2021-8-31 17:20
我放在主程序里,这样只要修改变量参数后要等执行完该分支才进行擦写,感觉也可以。不知道怎么去判断EEPR ...

正常不会这样写的吧?
不知道lsd()里写的是什么
如果num是0
不就不断在Case 0擦写同一地址吗?
还没有延时!  EEProm很快坏吧~

先比较再写入可以这样
if(!Key_In)
{
if(Key_Down_Count>1200000)//时间随你改
{Key_Down_Count = 0;
if(num !=IapReadByte(EEProm_Addr))
{
IapEraseSector(EEProm_Addr);//详细可参考STC_ISP
IapProgramByte(EEProm_Addr, num);//详细可参考STC_ISP
}
}else{
++Key_Down_Count;
}
}else{
Key_Down_Count = 0;
}
回复

使用道具 举报

ID:956872 发表于 2021-8-31 19:48 | 显示全部楼层
188610329 发表于 2021-8-31 19:41
不需要,我实测过,当外部电容为47uf时,3.7V低压检测的情况下,发现掉电后有大约15毫秒处理时间,其中10 ...

这个还是需要硬件电容支持啊。我现在这只是改变灯的状态,这不是频繁操作的数据,还是纯软件直接擦写好了
回复

使用道具 举报

ID:624769 发表于 2021-8-31 19:57 | 显示全部楼层
PEB188 发表于 2021-8-31 19:48
这个还是需要硬件电容支持啊。我现在这只是改变灯的状态,这不是频繁操作的数据,还是纯软件直接擦写好了

你可别跟我说你搭建单片机电路的时候没有用47uf电解电容,+ 0.1 uf 滤波电容,就跑起来了哈?这算需要额外硬件支持么?不是标配么?
最后,你的问题是“掉电存储功能”,那么自然是放到掉电中断里面罗。
你要是状态改变后存储,就放在改变状态的函数里,或者函数后面。
另外,建议你,Eeprom不要盯着一个地方写,容易坏,每次移动一个地址写,写满后格式化,再从头写。
回复

使用道具 举报

ID:883242 发表于 2021-8-31 20:07 | 显示全部楼层
IAP什么的函数是操作flash的吧?不像是操作eeprom的代码。
回复

使用道具 举报

ID:624769 发表于 2021-8-31 20:13 | 显示全部楼层
Hephaestus 发表于 2021-8-31 20:07
IAP什么的函数是操作flash的吧?不像是操作eeprom的代码。

STC, 就是把 Flash 当 Eeprom 用,对外号称Eeprom, 所以一擦一个扇区,贼不方便。
回复

使用道具 举报

ID:956872 发表于 2021-8-31 20:24 | 显示全部楼层
188610329 发表于 2021-8-31 19:57
你可别跟我说你搭建单片机电路的时候没有用47uf电解电容,+ 0.1 uf 滤波电容,就跑起来了哈?这算需要额 ...

我就一个STC芯片跑的,啥电容晶振复位电路都没有,供电用稳压管。也不会搭建多余的电路,还刚开始学
要是多个变量参数非同时变更的话还是要分页存储到EEPROM吧(EPROM有5K,差不多10页吧),这样擦除只擦一页也不会擦掉其它页的数据,对吧
回复

使用道具 举报

ID:956872 发表于 2021-8-31 20:25 | 显示全部楼层
188610329 发表于 2021-8-31 20:13
STC, 就是把 Flash 当 Eeprom 用,对外号称Eeprom, 所以一擦一个扇区,贼不方便。

不是挺方便的吗,哪个什么IIC的,学的糊里糊涂,感觉这个简单就放弃学那个了
回复

使用道具 举报

ID:624769 发表于 2021-8-31 20:57 | 显示全部楼层
PEB188 发表于 2021-8-31 20:24
我就一个STC芯片跑的,啥电容晶振复位电路都没有,供电用稳压管。也不会搭建多余的电路,还刚开始学[em01 ...

不分页高地址不变,低地址每次存储 +1 ,加到255以后 擦除扇区从0开始写
回复

使用道具 举报

ID:401564 发表于 2021-8-31 21:00 | 显示全部楼层
看实际情况,如果条件允许,加硬件电路执行断电写入,这样的话就是关机每次都会保存
不想搞的话,那就按键长按或者是多个按键按下保存,反正,保存设置是非常规操作就可以了
没什么好纠结的
回复

使用道具 举报

ID:624769 发表于 2021-8-31 21:04 | 显示全部楼层
PEB188 发表于 2021-8-31 20:25
不是挺方便的吗,哪个什么IIC的,学的糊里糊涂,感觉这个简单就放弃学那个了

写码而言是简单了,但在架构方面来讲,是麻烦。因为实际应用中,不会像你那样就一个数据盯着一个地方写,必须考虑均匀使用,写满以后,擦除一个扇区需要将近21毫秒,对系统影响还是比较大的。所以经常改的数据,比如闹钟数据,我宁可往DS1302,和DS1307里面存,也不往IAP里面存。只有一年都改不了几次的才存IAP

评分

参与人数 1黑币 +60 收起 理由
admin + 60 共享资料的黑币奖励!

查看全部评分

回复

使用道具 举报

ID:956872 发表于 2021-9-1 06:49 | 显示全部楼层
188610329 发表于 2021-8-31 20:57
不分页高地址不变,低地址每次存储 +1 ,加到255以后 擦除扇区从0开始写

从0开始写,但我好像写不进1啊,写1的话掉电后上电无法保存掉电前的状态,写2.3.4都没问题
回复

使用道具 举报

ID:398219 发表于 2021-9-1 08:06 | 显示全部楼层
我常用的方式是计数,一般我是计10次后写入EEPROM,然后清空计数。掉电还要写AD检测电压,感觉有点麻烦就没做。
回复

使用道具 举报

ID:390416 发表于 2021-9-1 08:28 | 显示全部楼层
简单  开机时  读取EEPROM

然后计数 设定时间 比如100ms  

100ms 判断一次  如果某数据的值 发生了改变 那么执行EEPROM擦除整个扇区+写入该字节保存
如果数据保持不变 不执行EEPROM擦写
回复

使用道具 举报

ID:624769 发表于 2021-9-1 20:18 | 显示全部楼层
herui2128 发表于 2021-9-1 08:06
我常用的方式是计数,一般我是计10次后写入EEPROM,然后清空计数。掉电还要写AD检测电压,感觉有点麻烦就没 ...

掉电压根不用写什么检测电压,直接 ELVD = 1; 然后写中断
void Power_Lost(void)        interrupt  6;
{
    ;//此处存储Eeprom 代码
     PCON  &= 0xDF; // 清掉电标志
     delay50ms();    //如 50ms 还没有关机,说明是误判,返回主程序。
}
就那么简单一件事。
回复

使用道具 举报

ID:956872 发表于 2021-9-2 11:45 | 显示全部楼层
人人学会单片机 发表于 2021-9-1 08:28
简单  开机时  读取EEPROM

然后计数 设定时间 比如100ms  

这样怎么跟主程序同时运行啊
回复

使用道具 举报

ID:161164 发表于 2021-9-2 11:59 | 显示全部楼层
PEB188 发表于 2021-9-2 11:45
这样怎么跟主程序同时运行啊

不用你那套while循环嵌套法就可以了
while(1){
  while(1){
    while(1){
      while(1){
        if(xxx)break;  ​
     ​}
   ​}
​}
}
回复

使用道具 举报

ID:956872 发表于 2021-9-2 17:15 | 显示全部楼层
lkc8210 发表于 2021-8-31 19:44
正常不会这样写的吧?
不知道lsd()里写的是什么
如果num是0

lsd()里就是简单的流水灯测试,case我从2开始写,加入了判断读取的值与当前值是否一致。不过这样还有问题,就是在按键连续按下调光的时候,这里就有问题了,会连续擦写,因为擦写需要较长的时间,对PWM调光也产生干扰了
回复

使用道具 举报

ID:956872 发表于 2021-9-2 17:24 | 显示全部楼层
lkc8210 发表于 2021-9-2 11:59
不用你那套while循环嵌套法就可以了
while(1){
  while(1){

我没这样写过。虽然小白一个,但也不至于白成这样。同时运行程序51单片机好像做不到,那应该是用定时器了,这样就得长期占用一个定时器。本来定时器就不多
回复

使用道具 举报

ID:161164 发表于 2021-9-2 17:27 | 显示全部楼层
PEB188 发表于 2021-9-2 17:15
lsd()里就是简单的流水灯测试,case我从2开始写,加入了判断读取的值与当前值是否一致。不过这样还有问题 ...

你不是要按着10秒才去擦写吗?
怎么又变成了连续按下会连续擦写?
回复

使用道具 举报

ID:956872 发表于 2021-9-2 19:48 | 显示全部楼层
lkc8210 发表于 2021-9-2 17:27
你不是要按着10秒才去擦写吗?
怎么又变成了连续按下会连续擦写?

之前是执行完分支程序的最后才判断变量与EEPROM存储的值是否一致,不一致才去擦写。后来加了PWM调光就有问题了,按键按下变量从一直加到100,相当擦写一百次,还对PWM产生干扰。主要这款型号定时器才两个,太少了,现在只能用PCA当定时器,按键按下打开PCA定时器,设一个变量计数,每次按键按下计数清0,一定时间内没有按键操作了再判断参数变量,最后决定是否擦写。这样应该能解决之前的问题吧
回复

使用道具 举报

ID:956872 发表于 2021-9-2 21:20 | 显示全部楼层
188610329 发表于 2021-9-1 20:18
掉电压根不用写什么检测电压,直接 ELVD = 1; 然后写中断
void Power_Lost(void)        interrupt  6;
...

这样是每次进入掉电模式前保存一次数据吗。那要是刚修改了数据,断电一次不就没来得及保存了。还要电路上加大的电容跟电压检测判断吧
回复

使用道具 举报

ID:161164 发表于 2021-9-2 22:26 | 显示全部楼层
PEB188 发表于 2021-9-2 17:24
我没这样写过。虽然小白一个,但也不至于白成这样。同时运行程序51单片机好像做不到,那应该是用定 ...

这不是你写的吗? 2021-09-02_222102.png
2021-09-02_222050.png


其实只用一个定时器
分时工作
已经等同于同时运行了
因为人跟本分不出几毫秒的差别

回复

使用道具 举报

ID:161164 发表于 2021-9-2 22:40 | 显示全部楼层
PEB188 发表于 2021-9-2 19:48
之前是执行完分支程序的最后才判断变量与EEPROM存储的值是否一致,不一致才去擦写。后来加了PWM调光就有 ...

那是你的写法有基本上的问题
所以每加一个新功能时就会与旧逻辑有冲突
然后又用一些另辟蹊径的逻辑来解决
结果越写越乱

12T的单片机只用一个定时器已足够协调五个工作模块+一个慢速PWM
回复

使用道具 举报

ID:624769 发表于 2021-9-3 22:08 | 显示全部楼层
PEB188 发表于 2021-9-2 21:20
这样是每次进入掉电模式前保存一次数据吗。那要是刚修改了数据,断电一次不就没来得及保存了。还要电路上 ...

你还是看一下手册吧……
interrupt 6 不是什么掉电模式, 是给单片机断电了,单片机在发现你掐了电源,简单点说,打比方说:发现你给他拔管子后,他在短期前利用还剩下的最后一口气,写下死亡讯息。 噢不是,把变量存Eeprom。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表