stm32掉电存储方案

  • Post author:
  • Post category:其他


一.问题引入

在实际设备中,经常有一些数据需要掉电存储,存储的方式一般会用内部flash或者外部扩展的存储芯片。不管哪种方式,在存储的时候,都有擦除与写入的过程,而这一过程是比较耗时间的(程序烧录过程类似)。以下为常见存储芯片AT24c16写入时间间隔 。

常规的写入程序如下,使用了delay();函数

//在AT24C16指定地址写入一个数据
void AT24C16_WriteOneByte(u16 writeaddr,u8 data)
{				   	  	    																 
    I2C_Start();  
    I2C_Send_Byte(0xA0+((writeaddr/256)<<1));   
    I2C_Wait_Ack();	   
    I2C_Send_Byte(writeaddr%256);  
    I2C_Wait_Ack(); 	 										  		   
    I2C_Send_Byte(data);    				   
    I2C_Wait_Ack();  		    	   
    I2C_Stop();
    
    Delay_ms(5);	 
}

当系统中有大量的需要掉电保存的的数据,且硬件又不支持断电时自检,维持一定时间供电以保存数据时,使用delay();函数会大大降低系统的实时性。因此本文最终的目的是消除此延时的5ms。

二.延时实现方法

从上面的写函数可以看出,需要保存一个变量时,得输入存放地址以及数据,当数据为16位时还需要分别保存数据的高8位和低8位。以保存变量count为例

u16 count;

int main()
{
       count = AT24C16_ReadOneByte(1)<<8 | AT24C16_ReadOneByte(2);   //变量开机初始化
       while(1)
       {
               1.获取count值(由外部传感器)

               2.保存count至AT24c16
                   if(last_count != count)  //判断当前值是否改变
                   {
                       AT24C16_WriteOneByte(1 , count>>8);
                       AT24C16_WriteOneByte(2 , count & 0xff);
                   }

               3.使用到count这个变量,比如做一些判断,做出一些处理
                 
               4.保存当前的count, last_count = count;
       }
}

可以看出write函数在主循环中,这样导致主循环周期不确定,且当要存入的变量比较多时,主循环实时性大大降低。且write函数在各处交叉调用,每引入一个新变量,都要做以上重复的事:开机赋值,写入保存。

三.定时器实现方法

1.   实现思路

绿色块为存储需要保存变量的地址的数组,其中数组的最末端为定义的常量地址,用于判断数组中当前需要存储变量的个数。当获取到需要存储的个数后,便会进行判同处理,只有当变量改变后才会进行写操作,当某个变量改变时会在定时器产生的第一个5ms使能写入数据高位至第一页,在第二个使能信号到达时写入低位至第二页。

2.代码实现:

step1 . 定义一个变量地址存储数组,用户将需要保存的变量地址存入即可。

u16 a,b,c,d,e;      //示例
u16 tail=0xfefe;    //用于获取数组当前存储长度

u8 data_len;        //用于存放当前存储变量个数

/*************需要存储的变量定义****************/
u16* data_address[256]
={
/*------------------用户区----------------------------*/	
         &a,           //   1
	 &b,           //   2   
	 &c,           //   3
	 &d,           //   4
/*----------------------------------------------*/	
	 &tail,
};

step2 .写入函数实现

/***********************写入改变的变量****************************/
void DATA_write(void)
{
	u8 j;	
	static u8 i=1;
	static u8 cnt;
	static u32  run_out_oftime;
	static u32  last_time;
        static u8 write_en;

/*-------------------------写使能-----------------------------------*/	
        if(!write_en)
        {
             if(*data_address[i-1]!=(u16)(AT24C16_Read(i)<<8 | AT24C16_Read(i+256))) 
               write_en=1; 
             else
             {
                i++; 
                if(i>=data_len)
	          i=1;
             }                          //值改变则允许写
        }

/*---------------------写入E2PROM-----------------------------------*/	
       else 
       {
            /*---------产生5ms运行间隔-----*/	
	    if(!last_time)
	       last_time=sys_time();   //系统1ms定时时间
	       run_out_oftime= sys_time()-last_time;

	    if(run_out_oftime> 5)
	    {
	       last_time=0;
	       run_out_oftime=0;
               cnt++;               //间隔5ms加一次
	    }
          /*-------------写入高位----------*/
	   if(cnt==1)
	   {
	       AT24C16_WriteByte(*data_address[i-1]>>8,i);               //数据高位第一页
           }
          /*-------------写入低位----------*/
           else if(cnt>=2)
	   {
	       AT24C16_WriteByte((u8)(*data_address[i-1]&0xff),i+256);  //数据低位第二页
               write_en=0;
	       cnt=0;
               i++; 
               if(i>=data_len)
	         i=1;

	   }
       }
  }

step3 .开机初始化函数

void DATA_init(void)
{
      u8 i,j;
      /*---------------获取当前需要存储数的个数--------------------------*/	
      if(!data_len)
      {
             for(j=0;j<255;j++)
	    {
	         if(*data_address[j]==0xfefe)
                 {
	            data_len=j+1;
		    break;
	         }
	     }
      }
      for(i=0;i< data_len;i++)
      {
	  *data_address[i]=(u16)(AT24C16_Read(i)<<8 | AT24C16_Read(i+256));
      }
}

step4. 主函数

/*主函数*/
int main ()
{
   data_init();  //开机初始化

   while(1)
   {
      data_write();
     
      other_deal();
   }
}

四。优缺点以及后续改进方向

优点:可以看到,去掉了写函数的延时函数。当用户需要增加新的存储变量时,只需要在step1中添加,开机初始化函数以及写   函数都不需要做调整,这样方便对掉电保存模块进行封装。

缺点:当变量值改变,便会进行一次保存,会影响存储器件的寿命,为加入写保护等。主循环的周期要小于最小写入周期5ms。

改进方向:

1.掉电存储的数据一般对整个系统至关重要,因此在写入时因该检测是否写入成功

2.当写入失败(某处地址存储损坏),系统自检,自动更换写入地址

3.在干扰比较严重的环境下,写入有可能受到干扰,导致存进去的数值与实际不符,在开机初始化时可能导致不可预   料的错误,因此写入时可以在多页存储相同变量,开机初始化时全部读出做比较,取概率较大的值。

4.引入时间片轮转或者操作系统,将模块设成一个任务,写函数可更加简化



版权声明:本文为qq_36969440原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。