找回密码
 立即注册
查看: 73|回复: 1

【15系列】SYK-0806-A2S1 工业自动化控制之【17-EEPROM实现数据掉电保存】

[复制链接]
  • 打卡等级:偶尔看看I
  • 打卡总天数:15
  • 最近打卡:2025-04-21 13:00:02

19

主题

9

回帖

215

积分

中级会员

积分
215
发表于 2025-4-17 15:31:28 | 显示全部楼层 |阅读模式
大家好,我是『芯知识学堂』的SingleYork,前一篇文章给大家介绍了“【STC15系列】SYK-0806-A2S1 工业自动化控制之【16-自定义协议通信】”,

这一篇中,笔者将会给大家介绍“EEPROM的基本操作”。

在实际应用中,很多时候我们需要对一些设置参数实现掉电保持,以免每次上电都需要重新设置参数,

或者产品在运行过程中,需要实时保存一些数据,下次开机后还能查询到。

像这种应用场合,就需要用到单片机的EEPROM功能了,当然,也可以用到外部FLASH、EEPROM等芯片,

只是,单片机本身自带EEPROM,又何必去另外花钱呢,对吧?

那么,本例笔者就来跟大家介绍一下这款IAP15W413AS控制板的掉电存储功能吧。

首先,什么是EEPROM相信大家都应该知道了,不知道的也可以自行百度,

毕竟这不是笔者要讲的重点,还是直接切入正题吧,

从芯片手册上我们可以知道,IAP15W413AS这款单片机是没有专门的EEPROM的,纳尼?

01.png

刚才不是说有EEPROM的么?怎么现在又说没有了呢,你是在逗我玩么?

哈哈,别急,IAP15W413AS虽然没有专门的EEPROM,但是我们可以将用户程序区的FLASH当EEPROM来使用,

也就是说,芯片的存储空间有多大,EEPROM就可以有多大,

当然咯,这是比较理想的状况,实际上,我们的程序大小不可能为零!

从上面表格中,我们可以知道,IAP15W413AS单片机的EEPROM最多可以分为26个扇区,每个扇区的大小为512个字节,

如果我们需要同时操作的数据不大的话,一般只用一个扇区应该就够了,

关于这部分详细的知识点,大家可以看芯片手册,笔者在此就不再赘述。

本例中,笔者以一个电子钟的程序为例来进行讲解,需要保存的数据就是时、分、秒,很显然只有三个数,一个扇区足矣!

那么我们就用使用最后一个扇区吧。

首先,我们定义用于EEPROM功能的扇区的起始地址:

  1. #define IAP_ADDRESS 0x3200        //0x3200-0x33FF   512BYTE
复制代码

然后,我们定义几个变量,用于电子钟的时、分、秒、毫秒:

  1. u16 time_hour      = 0;//时间-时
  2. u16 time_min       = 0;//时间-分
  3. u16 time_sec       = 0;//时间-秒
  4. u16 time_msec      = 0;//时间-毫秒
复制代码

另外定义两个数组,用于EEPROM数据读写的缓存:

  1. u8  EEPROM_ReadTable[7] = {0};
  2. u8  EEPROM_WriteTable[7]= {0};
复制代码

电子钟的计时,还是用定时器0来实现,我们将定时器0的中断频率设置在1k Hz:

  1. #define Timer0_Fre  500UL   //timer0中断频率 500*2Hz
复制代码
  1. Timer0_config(Timer0_Fre);  //定时器0配置
复制代码
  1. /************************ 定时器配置 ****************************/
  2. void        Timer0_config(u32 TIM0_Fre)
  3. {
  4.         TIM_InitTypeDef                TIM_InitStructure;                                                //结构定义
  5.    
  6.         TIM_InitStructure.TIM_Mode      = TIM_16BitAutoReload;            //指定工作模式,   TIM_16BitAutoReload,TIM_16Bit,TIM_8BitAutoReload,TIM_16BitAutoReloadNoMask
  7.         TIM_InitStructure.TIM_Polity    = PolityHigh;                            //指定中断优先级(低到高) Polity_0,Polity_1,Polity_2,Polity_3
  8.         TIM_InitStructure.TIM_Interrupt = ENABLE;                                        //中断是否允许,   ENABLE或DISABLE
  9.         TIM_InitStructure.TIM_ClkSource = TIM_CLOCK_1T;                        //指定时钟源,     TIM_CLOCK_1T,TIM_CLOCK_12T,TIM_CLOCK_Ext
  10.         TIM_InitStructure.TIM_ClkOut    = DISABLE;                                    //是否输出高速脉冲, ENABLE或DISABLE
  11.         TIM_InitStructure.TIM_Value     = 65536UL - (MAIN_Fosc / TIM0_Fre/2);                //初值,
  12.         TIM_InitStructure.TIM_Run       = ENABLE;                                        //是否初始化后启动定时器, ENABLE或DISABLE
  13.         Timer_Inilize(Timer0,&TIM_InitStructure);                                        //初始化Timer0          Timer0,Timer1,Timer2,Timer3,Timer4
  14. }
复制代码

app初始化程序中,在芯片上电后,除了对定时器、串口、GPIO做一些初始化之后,我们从EEPROM中读取7个数据,分别为:电子钟-时(2byte)、电子钟-分(2byte)、电子钟-秒(2byte)、时间更新标志,具体代码如下:

  1. /*********************    APP初始化   ***********************/
  2. void app_init(void)
  3. {
  4.         Timer0_config(Timer0_Fre);     //定时器0配置
  5.    
  6.     UART_config();                 //UART初始化
  7.     GPIO_Config();                 //GPIO初始化
  8.    
  9.     TI         = 1;
  10.     EA         = 1;//开启总中断
  11.    
  12.     EEPROM_read_n(IAP_ADDRESS,EEPROM_ReadTable,7);//从EEPROM中一次性读取7个数据
  13.     time_hour = EEPROM_ReadTable[0]*256 + EEPROM_ReadTable[1];
  14.     time_min  = EEPROM_ReadTable[2]*256 + EEPROM_ReadTable[3];
  15.     time_sec  = EEPROM_ReadTable[4]*256 + EEPROM_ReadTable[5];
  16.     if(EEPROM_ReadTable[6] != 0x01)//如果是第一次上电,初始化变量
  17.     {
  18.         time_hour  = 0;//时间-时
  19.         time_min   = 0;//时间-分
  20.         time_sec   = 0;//时间-秒
  21.         time_msec  = 0;//时间-毫秒
  22.         
  23.         printf("This is First Power On!\r\n");//串口打印结果
  24.     }
  25.     else
  26.     {
  27.         printf("EEPROM Test Start!\r\n");//串口打印
  28.     }
  29. }
复制代码

电子钟的基础定时,是由timer0来实现:

  1. /********************* Timer0中断函数************************/
  2. void timer0_int (void) interrupt TIMER0_VECTOR //频率可变
  3. {
  4.     time_msec ++;
  5. }
复制代码

电子钟功能的主要代码在app_run()中实现,每秒会通过printf()函数打印一次当前时间:

  1. /*********************     APP运行    ***********************/
  2. void app_run(void)
  3. {
  4.     //计时:时、分、秒、毫秒
  5.     if(time_msec>=1000)
  6.     {
  7.         time_msec = 0;
  8.         
  9.         printf("Time = %02d:%02d:%02d\r\n",time_hour,time_min,time_sec);//串口打印输出时间
  10.         
  11.         EEPROM_SectorErase(IAP_ADDRESS);//扇区擦除,为写EEPROM做准备
  12.         EEPROM_WriteTable[0] = time_hour/256;
  13.         EEPROM_WriteTable[1] = time_hour%256;
  14.         EEPROM_WriteTable[2] = time_min /256;
  15.         EEPROM_WriteTable[3] = time_min %256;
  16.         EEPROM_WriteTable[4] = time_sec /256;
  17.         EEPROM_WriteTable[5] = time_sec %256;
  18.         EEPROM_WriteTable[6] = 0x01;        //参数更新标志
  19.         EEPROM_write_n(IAP_ADDRESS,EEPROM_WriteTable,7);//将数据写到EEPROM
  20.         
  21.         if(++time_sec>=60)
  22.         {
  23.             time_sec = 0;
  24.             if(++time_min>=60)
  25.             {
  26.                 time_min  = 0;
  27.                 time_hour ++ ;
  28.             }
  29.         }
  30.     }
  31. }
复制代码

关于printf()函数的用法,网上一查一大把,笔者就不在这赘述了,这里需要提醒大家的是,在使用printf()函数时一定要注意一下两点:

必须包含stdio.h文件,即:

  1. #include  <stdio.h>
复制代码

在调用printf()函数之前需要先将TI置“1”,即:

  1. TI         = 1;
复制代码

程序下载到板子中,第一次上电时回打印如下信息:

This is First Power On!

Time = 00:00:00

Time = 00:00:01

Time = 00:00:02

Time = 00:00:03

断电后再重新上电,会打印如下信息:

EEPROM Test!

Time = 00:00:03

Time = 00:00:04

Time = 00:00:05

Time = 00:00:06

说明我们的时间是按照我们设定的“每秒”自动写到的EEPROM中了,EEPROM读写都是OK的。

01.png

另外有一点笔者需要提醒大家,我们都知道,芯片的擦写次数是有上限的,一般都是在10万次或者100万次,

不管是多少次,都意味着他是有寿命的,而我们进行EEPROM写操作的时候,每次都会需要先进行擦除操作,才能成功写入数据,

既然这样,如果我们每秒来操作一次EEPROM的话,一天就需要擦写86400次,即使EEPROM的寿命有100万次,也就不到12天可能就要挂逼了。

因此,在实际应用中,我们对EEPROM的擦写操作,不能这么频繁。

因此,如果我们要实时存储运行过程中的一些数据,比较理想的方式是,我们搭建专门的掉件检测电路来检测外部电源是否掉电,

如果掉电这个时候才保存参数即可。

关于这个掉电检测电路,实际上STC芯片手册也给出了一种比较容易实现的方案,如下图所示:

02.png

当然咯,由于笔者这个板子上没有做这块的电路,所以我们暂时就没办法演示了,

但是笔者也有在别的板子上用到这个电路,效果还不错,感兴趣的小伙伴们可以自己搭建电路去试下。

另外,在一些不太方便搭建外部掉电检测电路的情况下,我们也可以通过操作不同的扇区来延长实现,

比如,当某个扇区擦写次数达到某一数值后,我们可以切换另外的扇区来存储数据。

好了,关于本讲的内容就简单介绍到这里了,有疑问的小伙伴们可以给笔者留言或者直接参与评论,

下一节笔者将给大家介绍“单片机ADC的应用”,详见“SYK-0806-A2S1 工业自动化控制之【18-内部AD采集外部电压】”,感谢大家的支持!

本章附件:

【STC15系列】SYK-0806-A2S1- 17-EEPROM实现数据掉电保存.rar (81.56 KB, 下载次数: 6)




1 喜欢他/她就送朵鲜花吧,赠人玫瑰,手有余香!

本帖被以下淘专辑推荐:

回复

使用道具 举报 送花

3

主题

1160

回帖

1031

积分

等待验证会员

积分
1031
发表于 2025-4-17 15:33:00 | 显示全部楼层
【15系列】SYK-0806-A2S1 工业自动化控制之【17-EEPROM实现数据掉电保存】技术解析

大家好,我是『芯知识学堂』的SingleYork。在上一篇文章中,我们探讨了“【STC15系列】SYK-0806-A2S1 工业自动化控制之【16-自定义协议通信】”,今天我们将深入探讨“EEPROM的基本操作”及其在工业自动化控制中的应用。

一、EEPROM在工业自动化中的重要性

在实际的工业自动化应用中,系统参数的掉电保持是一个关键需求。例如,设备在运行过程中需要实时保存一些关键数据,以便在下次开机时能够继续使用这些数据,而不需要重新设置。这种情况下,EEPROM(电可擦可编程只读存储器)就显得尤为重要。

二、IAP15W413AS单片机的EEPROM特性

虽然IAP15W413AS单片机没有专门的EEPROM,但我们可以利用其用户程序区的FLASH来模拟EEPROM的功能。这种方法不仅节省了成本,还充分利用了芯片的存储资源。

1. FLASH模拟EEPROM的原理

FLASH存储器通常用于存储程序代码,但其特性与EEPROM相似,都可以进行多次擦写操作。通过特定的编程方法,我们可以将FLASH的一部分空间用作EEPROM,实现数据的掉电保存。

2. EEPROM的分区与使用

根据芯片手册,IAP15W413AS单片机的EEPROM最多可以分为26个扇区,每个扇区的大小为512字节。在实际应用中,如果数据量不大,通常只需要使用一个扇区即可满足需求。

三、EEPROM的基本操作

1. 数据写入

在将数据写入EEPROM之前,需要先擦除目标扇区。擦除操作会将整个扇区的数据清零,因此在进行写入操作时,需要确保数据已经备份或不再需要。

2. 数据读取

读取EEPROM中的数据相对简单,只需通过特定的地址访问即可。需要注意的是,读取操作不会影响存储的数据。

3. 数据更新

当需要更新EEPROM中的数据时,通常需要先擦除目标扇区,然后再写入新的数据。这一过程需要谨慎操作,以避免数据丢失。

四、实际应用案例

以SYK-0806-A2S1工业自动化控制板为例,我们可以通过以下步骤实现数据的掉电保存:

1. 初始化EEPROM:在系统启动时,初始化EEPROM相关寄存器,确保其处于可操作状态。
2. 数据存储:在设备运行过程中,将需要保存的数据写入指定的EEPROM扇区。
3. 数据读取:在设备重新启动时,从EEPROM中读取之前保存的数据,恢复系统状态。

五、注意事项

1. 擦写次数限制:FLASH存储器的擦写次数有限,通常为10万次左右。因此,在设计时应尽量减少不必要的擦写操作,以延长芯片寿命。
2. 数据备份:在进行擦写操作前,建议先备份重要数据,以防止意外丢失。
3. 电源管理:在掉电保存过程中,确保系统有足够的电源供应,以避免数据写入不完整。

六、总结

通过利用IAP15W413AS单片机的FLASH模拟EEPROM功能,我们可以有效地实现数据的掉电保存,满足工业自动化控制中的实际需求。这种方法不仅节省了成本,还提高了系统的可靠性和稳定性。希望本文能为大家在实际应用中提供有价值的参考。

感谢大家的阅读,我们下期再见!

——SingleYork,『芯知识学堂』

[本文内容由国芯人工智能辅助生成,仅供参考]
回复 支持 反对

使用道具 举报 送花

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

本版积分规则

QQ|手机版|小黑屋|深圳国芯人工智能有限公司 ( 粤ICP备2022108929号-2 )

GMT+8, 2025-5-2 02:22 , Processed in 0.131720 second(s), 59 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

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