Mémoire pour arduino
avec un CMOS CD4021
Electronique
Root » Serveurs » ElectroNique » Arduino » Mémoire

L'arduino a une mémoire permanente, mais comme toutes les mémoires flash, le nombre de fois qu'elle peut être écrite est limitée (100.000 fois au maximum)
-

-

Stockage dans l'EEPROM

Supposez que vous voulez mémoriser l'état de 8 sorties pour que l'arduino produise directement les même valeurs après une coupure de courant. La solution la plus simple, c'est de stocker l'état des sorties dans l'EEPROM. L'EEPROM est de la mémoire flash accessible un octet à la fois. La capacité de l'EEPROM est limitée, elle est de 1k pour un Arduino Uno.

L'écriture se fait avec les instructions: (l'adresse va de 0 à 1023 pour un Uno)

  • #include <EEPROM.h>
    Pour définir les routines pour accéder à la mémoire EEPROM

  • EEPROM.write(address, value);
    Pour écrire un octet

  • EEPROM.read(address);
    Pour lire un octet.

Si une sortie change une fois par seconde et qu'il faut à chaque fois stocker la valeur, cela nous fait 86400 écritures par jour: notre mémoire EEPROM est usée au bout d'un peu plus d'un jour. Même si l'état des sorties ne change qu'une fois par minute, la mémoire sera épuisée au bout de 3 mois. Ce n'est pas l'idéal pour un système qui travaille en permanence. On peut éventuellement stocker chaque sortie dans un octet si toutes les sorties ne changent pas simultanément, mais cela ne fait que retarder l'échéance.

Stockage dans un CMOS statique

Mais pour le stockage de valeurs momentanés (pendant la durée d'une coupure électrique) on peut utiliser un circuit CMOS, j'ai choisi le CD4021 qui a 8 entrées (parallèle) et une sortie série. Le circuit a également une entrée série que nous n'utiliserons pas. On peut effectuer autant d'opérations d'écriture que l'on veut, le CMOS est une mémoire statique qui ne s'use pas.

A chaque modification d'une sortie, on envoie un ordre de mémorisation au 4021 qui a ainsi en mémoire l'état le plus récent des sorties.
Le port à utiliser est parallel/serial control. Cette entrée est connectée au port appellé latchPin dans le logiciel de l'arduino.
L'ordre de mémorisation est simple:

void setup() {
   pinMode(latchPin, OUTPUT);
   pinMode(0, OUTPUT); // 0, 1, 2,... sorties 0/1
   pinMode(clockPin, OUTPUT); // voir plus bas
   pinMode(dataPin, INPUT); // voir plus bas
   ...
   }
...
void loop() {
   ...
   digitalWrite(latchPin, HIGH);
   digitalWrite(latchPin, LOW);
   ...
   }

Quand la ligne est haute, les valeurs sur les entrées parallèles (PI = Parallel Input) sont transférées dans le CMOS, qui les conserve grâce à une petite alimentation de secours. On remet la ligne basse pour garder les valeur et éviter qu'elles ne se perdent lors de la coupure de courant. En effet, tant que la ligne est haute le CMOS est constamment remis à jour. En cas de coupure de courant les lignes peuvent tomber à zéro avant que P/S CONTROL ne passe à zéro.

Pour garder la configuration des sorties en cas de coupure de courant, il faut évidemment alimenter le CMOS avec un petit accu. La tension minimale est de 3V, donc trois petits éléments NiMH de 1.2V sont suffisants. La consommation de la puce au repos est de moins de 100µA: un petit accu de sauvegarde de 3.6V 100mA permet de garder les données pendant plus d'un mois. Avec la résistance de 1kΩ le courant de charge est d'environ 1.5mA (accu vide) à 300µA (accu chargé). Les diodes sont des schottky basse puissance.

Quand le courant revient, il suffit de lire séquentiellement les valeurs stockées dans le CMOS et de configurer les sorties. Cette opération se fait dans le setup. Il y a une instruction spécifique pour lire tous les bits à la fois:

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

incoming est un octet qui reçoit les données, dataPin est l'entrée des données et clockPin le signal d'horloge qui est envoyé au CD4021. bitOrder est soit MSBFIRST ou LSBFIRST selon le cablage de la mémoire.

Pour lire les bits individuels, on peut soit utiliser un masque, soit une opération de shift. J'utilise pour cela la fonction "modulo" (reste de la division).

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

tab est un tableau d'octets recevant les bits successifs. Ensuite la valeur est utilisée pour configurer les sorties. S'il n'est pas nécessaire de stocker la valeur de chaque bit, on peut se passer du tableau et directement commander le port à partir du reste de la division: digitalWrite(i, incoming % 2);. Toutes ces opérations doivent se faire dans le setup.

Publicités - Reklame

-