本帖最后由 dj狂人 于 2014-12-18 17:23 编辑
聊聊数据存储 之前学51的时候,对数据存储没什么概念,主要是做过的东西对这方面没这个需求自己也没往这方面考虑过。而对于STM32来说,当程序写大特别是跑OS之后数据存储就变成了不得不考虑的事情,那么我们现在就来聊聊数据存储。 假如我们在程序中定义了这么五个变量: int Frequency = 8; int Speed = 5; int Power = 60; int Voltage = 12; int Temperature = 25; 这五个变量在程序运行的时候是可以通过按键或者其它方式人为的改变它们的值的,现在要求在人为改变它们之后对它们进行保存,那么这个时候我们该怎么去编写程序呢。 如果是51单片机的的话,在单片机不支持IAP技术的条件下,我们一般会考虑外扩,但是在STM32上,我们可以把这五个变量保存到Flash ROM里面,在有数据变动的时候再进行重新擦写就可以了,但保存到FlashROM中会有一定的限制,那就是它不允许我们进行字节擦除,如果我们想要对其中的某个数据进行修改的话只能先把里面的数据都取出来,修改好之后把Flash ROM整页擦除再把数据写进去。这是因为Flash ROM在没有写入任何数据之前里面都是‘1’,我们写入数据只需要把相应的‘1’写成‘0’就可以了,但是它是不允许也不能把‘0’再写成‘1’的,这就是为什么Flash ROM不支持字节擦写的原因。 那么好,确定用Flash ROM来存储数据之后,我们下面开始数据改以什么样的形式进行存储。对于上面五个变量可不可以直接这样存放进去呢 这样是可以的,但我们要考虑到虽然我们知道里面哪个地址存的是什么变量的数据,但单片机是不知道它现在取的是什么数据的,这样就要求我们为每个变量都赋一个标志,比如用0x00代表Frequency变量,0x01代表Speed变量...以此类推,那么单片机取出数据的时候先找到标志,如先找到0x00,那么它就知道这次取的是Frequency变量的数据了,如果找到0x01,它就知道这次取出的是Speed变量的数据了。 解决好这个问题之后,我们再来看看有数据变动需要修改的情况。 如上图,现在我们的五个变量和相应的标志已经存放到FlashROM里面去了,假如程序在运行的时候,使用者通过按键修改了Speed变量的值,修改成了 Speed = 2;那么我们要更新保存在Flash ROM里的Speed的值的时候,需要在RAM里面定义一个数组,把Flash ROM里面这五个变量的值和标志取出来放到数组里面,然后通过标志找到Speed变量的数据,对它的数据进行更新,也就是把‘5’擦写成‘2’,之后对Flash ROM进行整页擦除,最后把数组里面的数据再重新写进去就完成了数据的更新。 上面介绍的方法是初学者比较常用的方法,这种方法简单,容易理解。但是有点致命的缺陷,我们都知道Flash 是有寿命的,虽然现在普遍上的Flash 可达10万次擦写,但如果在运行的时候使用者经常通过按键修改变量,频繁的对Flash进行整页擦除,会导致Flash的使用寿命大大减少。那么要解决这个问题就需要我们合理科学的使用Flash。那么对Flash又该怎么进行合理科学的使用呢。 在我们STM32的中小容量型号芯片中,一般一页有1K的内存空间,而上面我们存储五个变量加五个标志之后还剩下一大片的空间没用到,不得不说这是种浪费,如果把剩下的空间利用起来,那么有数据变动的时候我们可以先不对原数据进行更改,而是采用追加的方式保存到后面去: 这样的话我们只要在这页空间快存满或者合理的时候对这些数据进行整理,把无效旧的数据清理掉再重新写入Flash就可以了。 这样合理的使用Flash之后,我们再来看看怎么对无效数据进行清理。 如上图,当我们的一页空间里快存满或者我们想要进行清理的时候,我们可以在RAM里面先定义一个数组,把Flash中的数据取出来放到数组里面,在这个取出来的过程中,我们进行初步处理,就是判断哪些是无效数据。后面追加的数据肯定是要留下,而前面一点的数据则是要清理的,那么要清理的数据我们把它们的标志位置零,接着对Flash进行整页擦除,然后把数组里面标志不为零的数据再写入Flash里面。这样就完成了数据的清理。 上面这种清理无效数据的方法算是比较常用的,但也有缺陷,因为我们的Flash采用追加的方式之后,里面的数据还是比较多的,这就要求我们在RAM里面定义一个相当大的数组,如果我们的程序把RAM已经使用的很大,那么剩下的空间不足够我们定义这么大的数组,就会造成数据溢出或者是把其他数据给覆盖掉,这是很致命的。那我们又该怎样解决这个问题呢。方法很简单,只要我们在要往Flash里追加数据的时候先通过标志寻到旧的数据,然后把它的标志清零再追加新数据,这样我们在整理数据的时候只需要定义一个很小的数组把Flash中标志不为零的数据取出来,对Flash进行整页擦除之后再把数据写进去就可以了。那这种方法又是否完美了?肯定不是。 我们刚那种方法最大的缺陷就是寻找无效数据的时候太花时间,如果每改动一个数据都要遍历一页Flash一次或几次的话,在某些场合往往是无法忍受的,就像RTOS拒绝delay一样。如果不用这种方法又该怎样做才能更好的满足实时的需求又很好的避免在RAM中定义一个大数组的尴尬呢。相信也有很多程序编写者在思考这个问题,他们也肯定会有自己的处理方法。我在msOS里面就看到了一种比较新颖的处理方式。那么他是怎么处理的呢? 在msOS这个系统中,他充分利用了变量在RAM中原有的存储空间。我们都知道程序中的指令都是存储在程序存储空间也就是Flash里面,变量是存放在数据存储空间(RAM)里面的,那么我们整理数据的时候定义的数组只用来存放标志(注意,这个标志直接就是变量在RAM中的地址),数据放回它在RAM中原有的数据存储空间去(虽然这样做会把初始化时的初始值覆盖掉,这个有好处也有坏处,看情况而定)。这样我们定义的数组就只是之前的一半就够了。 好,数据存储就聊到这。以上都是个人在学习msOS时接触到的东西,如果有说的不对的或者不透彻的还请各位指正
|