Electronica
Permanent geheugen met een arduino
TechTalk
Root server » TechTalk » Electronica » Permanent geheugen
De arduino heeft permanent flash geheugen aan boord, maar het aantal schrijfcycli is beperkt. Is er een andere mogelijkheid om data op te slaan?
-

-

Opslag in de EEPROM

Veronderstel dat je de toestand van 8 uitgangslijnen wilt opslaan, zodat de arduino automatisch dezelfde toestand zou aannemen bij het terug opstarten. De meest eenvoudige oplossing zou zijn de toestand op te slaan in de EEPROM. De EEPROM is flash geheugen dat per byte adresseerbaar is. De capaciteit is beperkt, 1k voor een arduino uno.

Het schrijven gebeurt met de volgende instructies (het adresbereik gaat van 0 tot 1023 voor een uno):

  • #include <EEPROM.h>
    Om de routines te laden om toegang te krijgen tot de EEPROM

  • EEPROM.write(address, value);
    Om een byte te schrijven

  • EEPROM.read(address);
    Om een byte te lezen

Indien een uitgang om de seconde kan veranderen en men moet iedere keer de nieuwe waarde opslaan, dan hebben we 86400 schrijfoperaties per dag. Onze EEPROM is versleten in minder dan twee dagen. Zelfs als de toestand slechts om de minuut verandert, is het geheugen versleten na 3 maanden. Dit is onvoldoende voor een processor die constant moet werken. Men kan eventueel één byte gebruiken voor iedere uitgang als de uitgangen niet samen veranderen, maar je zal daar waarschijnlijk weinig tijdswinst mee boeken. We moeten een andere oplossing vinden.

Opslag in een statische CMOS

Om waarden op te slaan gedurende een stroomonderbreking kan men een CMOS IC gebruiken. Ik heb daarvoor de CD4021 gekozen, die 8 parallele ingangen en een seriële uitgang heeft. Het IC heeft ook een seriële ingang die hier niet gebruikt wordt. Men mag zoveel schrijfoperaties uitvoeren, het IC zal daardoor niet verslijten, des te meer dat we hem op een lage spanning van 5V laten werken.

Bij iedere verandering van een uitgang sturen we een schrijfopdracht naar de 4021, die zo altijd de laatste toestand bewaart.
We gebruiken de pin parallel/serial control, verbonden met de arduino uitgang die we latchPin in de software noemen. Een schrijfopdracht is eenvoudig:

void setup() {
   pinMode(latchPin, OUTPUT);
   pinMode(0, OUTPUT); // 0, 1, 2,... binaire uitgangen
   pinMode(clockPin, OUTPUT); // zie lager
   pinMode(dataPin, INPUT); // zie lager
   ...
   }
...
void loop() {
   ...
   digitalWrite(latchPin, HIGH);
   digitalWrite(latchPin, LOW);
   ...
   }

Als de lijn hoog is worden de waarden op de parallele ingangen (PI = Parallel Input) in de CMOS opgeslagen. De waarden blijven behouden door een kleine noodvoeding. De lijn wordt direct nadien weer laag gemaakt zodat de waarden niet verloren gaan bij een stroomonderbreking. Immers als de lijn hoog is worden de gegevens constant bijgewerkt. Bij een stroomonderbreking kan een (data)lijn laag worden voordat de P/S CONTROL laag wordt.

Om de toestand van de digitale lijnen te bewaren tijdens een stroomonderbreking moet de CMOS natuurlijk gevoed worden door een kleine accu. De minimale spanning bedraagt 3V, waardoor 3 NiMH elementen van 1.2V gebruikt kunnen worden. Het verbruik van het IC is minder dan 100µA zodat een accu van 3.6V 100mA voldoende is voor een maand. Met een weerstand van 1kΩ is de laadstroom 1.5mA bij een lege accu en 300µA bij een volle accu. De diodes zijn laagvermogen schottky's.

Als de stroom terugkeert volstaat het de gegevens sekwentieel terug in te lezen en de uitgangen van de arduino te sturen. Dit gebeurt in de setup. Er bestaat een instructie om alle bits in één keer te lezen:

void setup() {
   ...
   incoming = shiftIn(dataPin, clockPin, bitOrder);
   ...
   }

incoming is een byte die de data ontvangt, dataPin wordt gebruikt om de seriële data in te lezen en clockPin geeft het kloksignaal naar de CD4021. bitOrder is MSBFIRST of LSBFIRST naargelang de manier van aansluiten.

Om de individuele bits in incoming te lezen kan men ofwel een masker gebruiken, ofwel een shift opdracht. Ik gebruik daarvoor de "modulo"funktie (rest van de deling).

   for (i = 0; i < 8; i++) {
      tab[i] = incoming % 2;
      incoming = incoming / 2;
      digitalWrite(i, tab[i]); // outputports 0..7
   }

tab is een byte array die de opeenvolgende bits ontvangt. De waarde wordt dan gebruikt om de uitgangen aan te passen. Indien het niet nodig is om de toestand van iedere uitgang te bewaren, dan is een tabel niet nodig en kan men direct de poort sturen via de modulofunctie digitalWrite(i, incoming % 2);.

Het inlezen moet in de setup gebeuren, we hoeven immers onze statische geheugen slechts éénmaal in te lezen.

Publicités - Reklame

-