Arduino: ottimizzare la EEPROM

La memoria arduino ha un numero limitato di celle, 1024 su arduino uno, per cui è necessario ottimizzare la EEPROM per cercare ridurne al minimo il suo utilizzo e poter memorizzare un maggior numero di informazioni.

ottimizzare la eeprom

Il tuo progetto potrebbe dover memorizzare dati sulla EEPROM di arduino.

In questo articolo apprenderai come memorizzare un intero arbitrariamente grande e ottimizzare la EEPROM e lo spazio.

Un po’ di teoria sugli interi con arduino

Esistono diversi tipi di interi che potrai utilizzare con arduino.

Tutti i tipi hanno diverse dimensioni in BYTE, gruppi di 8 bit che ne contengono il valore in base 2, detto comunemente valore binario, per esempio 241 in base 10 equivale a 11110001 binario.

Un breve elenco di alcuni tipi disponibili chiarisce meglio le idee:

int Numeri interi a 16bit(2 BYTE)
(in alcuni modelli di arduino a 32bit)
Variano da -32.768 a +32.767.
(nei modelli a 32 bit da -2.147.483.648 a +2.147.483.647)
long Numeri interi a 32bit(4 BYTE)
Variano da -2.147.483.648 a +2.147.483.647
long long Numeri interi a 64bit(8 BYTE)
Variano da −9.223.372.036.854.775.808 a +9.223.372.036.854.775.807
unsigned int Numeri interi a 16bit(2 BYTE) o in alcuni modelli di arduino a 32bit(4 BYTE)
Variano da 0 a +65.535 oppure, nei casi in cui siano a 32 bit da 0 a +4.294.967.295
unsigned long Numeri interi a 32bit(4 BYTE)
Variano da 0 a +4.294.967.295
unsigned long long Numeri interi a 64bit(8 BYTE)
Variano da 0 a +18.446.744.073.709.551.615

come puoi osservare, hai a disposizione per gestire quasi tutto ciò che ti si presenterà nei tuoi progetti per ottimizzare la EEPROM.

Dovrai prestare attenzione ai tipi a 64bit per due motivi:

  1. anche se gestiti correttamente, possono fare esplodere le dimensioni dello sketch compilato.
  2. Non sono supportati direttamente da metodi come print() e println() dell’oggetto serial.

Potrai comunque gestirli con alcuni trucchi che ti spiegherò in un prossimo articolo.

Tornando al tema principale, come visto nell’articolo sulle EEPROM, ogni cella ha le dimensioni di 1 BYTE, ti serviranno quindi 2 celle per un intero a 16bit, 4 per quelli a 32bit ed 8 per quelli a 64bit.

Definizione del dominio e dei limiti per ottimizzare la EEPROM

Definisci il dominio come il range che contiene il numero massimo che vorrai memorizzare.

Vediamo come puoi definire i limiti del dominio di una determinata applicazione partendo con un esempio pratico un esempio:

ottimizzare la eeprom
Supponi di voler misurare la rotazione con un encoder ad impulsi, se l’albero di rotazione è fissato in modo che ad ogni giro del albero rotore l’encoder emetta 3000 impulsi e la velocità massima del motore è di 1500 giri al minuto potresti voler memorizzare 2 giorni consecutivi.

Definiti tutti i dati per definire il limite massimo del dominio usa la seguente moltiplicazione ed otterrai il valore limite del tuo dominio:

3000 impulsi * 1500 giri/minuto * 60 minuti * 24 ore * 2 giorni = 12.960.000.000

Questo numero equivale alla massima quantità di impulsi che dovrai memorizzare se la macchina mantenesse il suo massimo regime per tutti e due i giorni, inoltre gli impulsi daranno origine a un conteggio sempre positivo.

Nello sketch avrai bisogno di una variabile a 64bit, in quanto tutte quelle più piccole non saranno sufficienti, sarà indifferente la scelta di una variabile unsigned piuttosto che signed, in quanto i numeri saranno solo positivi e sufficientemente grandi.

Con variabili signed potresti incappare in problemi legati al bit di segno ti consiglio di usare variabili unsigned.

Per memorizzare i dati invece potrai ottimizzare ulteriormente, in quanto avrai a disposizione quante celle da 8bit vorrai.

Nella seguente tabella è indicato il valore massimo solo positivo per diversi multipli di celle (BYTE):

1 CELLA o 1 BYTE 255
2 CELLE o 2 BYTES 65.535
3 CELLE o 3 BYTES 16.777.215
4 CELLE o 4 BYTES 4.294.967.295
5 CELLE o 5 BYTES 1.099.511.627.775
6 CELLE o 6 BYTES 281.474.976.710.655

come puoi osservare è necessario usare almeno 5 celle, in quanto 4 sarebbero poche e 6 sarebbero insufficienti.

L’algoritmo per ottimizzare la EEPROM con gli operatori booleani

A questo punto hai a disposizione una variabile a 64 bit e le 5 celle per memorizzare la lettura in essa contenuta.

Il problema consiste nel trasferire il contenuto di un grosso contenitore (variabile) in 5 contenitori più piccoli (celle).

La soluzione è più semplice di quanto pensi !

Devi spezzare il numero in pezzi più piccoli e memorizzarlo per ottimizzare la EEPROM.

Puoi spezzare il numero grazie agli operatori booleani ereditati dal linguaggio C.

Il primo operatore di cui avrai bisogno è il prodotto booleano ( AND ) indicato negli sketch con il simbolo & (come in wiring, C++ e C).

Il secondo operatore che ti servirà è lo scorrimento a destra indicato negli sketch con il simbolo >> (come in wiring, C++ e C).
Anche in questo caso non dovrai confonderlo con l’operatore per lo streaming di dati, in quanto assolve tutt’altro compito.

Cosa fanno gli operatori booleani

Ti mostro cosa fanno questi operatori con degli esempi partendo dal prodotto logico:

167.665 & 255 = 241

Scritto così ha poco significato. La stessa operazione fatta in colonna, con i numeri tradotti in base2 ti sarà molto più chiara:

ottimizzare la eeprom

Puoi intuire l’analogia con l’applicazione di una maschera, infatti tutto ciò che è sopra gli 1 rimane tutto ciò che è sopra agli zero vene azzerato (mascherato). In questo caso preservi solo i primi 8 bit del numero di partenza.

Passa all’operatore di scorrimento:

167.655 >> 8 = 654

Analizzando in colonna questo esempio, capirai cosa succede:

ottimizzare la eeprom shift

Gli 8 bit meno significativi sono usciti a destra, 8 nuovi bit posti a 0 ed indicati in neretto sono entrati. In giallo puoi osservare i bit spostati a destra.

Riapplica la maschera AND ed otterrai il secondo pezzo del numero di partenza e così via per quanti pezzi ti serviranno.

Lo sketch per ottimizzare la EEPROM

Ora hai a disposizione un metodo risolutivo, dovrai solo tradurlo in uno scketch. Ecco come si fa con il seguente esempio:

#include <EEPROM.h>

#define ENCODER_PIN 2 // Sul pin 2 è collegato l'encoder
#define PUSH_BUTTON_STORE 4 // Il pulsante al pin 2 indica quando memorizzare il valore conteggiato
#define COUNTER_INDEX 200 // Un valore a caso di esempio che indica l'indirizzo in cui memorizzare il dato
#define DEBOUNCE_TIME_US 5 // Tempo antirimbalzo per evitare doppie letture tenendo conto che tra due impulsi passano minimo 13 microSecondi

unsigned long long value=0; // Variabile che terrà il conto

void setup() {
     pinMode(PUSH_BUTTON_STORE, INPUT);
     pinMode(ENCODER_PIN, INPUT);
}

void loop() {
  if(digitalRead(PUSH_BUTTON_STORE)==HIGH) {
    for(int indice = 0;indice < 5;indice ++) {
       EEPROM.write(COUNTER_INDEX + indice, byte(value & 255));
       delay(5);
       value=value >> 8;
    }
    value=0;
  }
  if(digitalRead(ENCODER_PIN)==HIGH) {
    value ++;
    delayMicroseconds(DEBOUNCE_TIME_US);
  }
}

Leggendo lo sketch riga per riga:

linea 1: includi la libreria EEPROM;

linee 2-6: definisci delle costanti per rendere più leggibile il codice;

linea 8: definisci la variabile che conterrà un valore sufficientemente grande e azzerala allo stesso tempo;

linee 11-12: indica che i due piedini saranno input, al primo sarà collegato un pulsante di memorizzazione ed azzeramento, al secondo l’encoder;

linea 16: rileva la pressione del tasto o non perdere tempo;

linea 17: sei qua se il tasto è stato premuto, inizia quindi un ciclo che si ripeterà per i 5 BYTE(Celle) che devi memorizzare;

linea 18: memorizza a partire da COUTER_INDEX i 5 byte, uno per ogni ripetizione del ciclo for(). Prendi gli ultimi 8 bit a destra (Il BYTE meno significativo);

linea 19: assicurati che la EEPROM abbia il tempo di memorizzare il dato;

linea 20: sposta a destra di 8 bit value, ora gli 8 bit meno significativi sono quelli che precedevano gli 8 memorizzati;

linea 21: chiudi il ciclo for() iniziato alla linea 16;

linea 22: azzera il conteggio e preparati a ricominciare tutto;

linee 25-26: se ricevi un impulso incrementa il contatore value, attendi qualche microSecondo per evitare rimbalzi del conteggio e procedi;

Con questo articolo abbiamo visto come procedere alla memorizzazione. Prossimamente spiegheremo come rileggere i dati memorizzati e ricostruire un intero, vedremo anche alcuni trucchi inviare numeri a 64 bit sulla seriale.

Cortesemente, prima di inserire i commenti leggi il regolamento

Permanent link to this article: http://www.mauroalfieri.it/informatica/arduino-ottimizzare-la-eeprom.html

13 comments

Skip to comment form

    • Alberto on 3 settembre 2013 at 13:52
    • Reply

    Complimenti Mauro, bell’articolo.

    Sei il Luciano de Crescenzo del 21° secolo, che sa rendere semplice e comprensibile l’informatica e l’elettronica.

    1. Ciao Alberto,
      grazie per il complimento, ma questo articolo è di Marco .. un appassionato molto in gamba che ha voluto condividere le sue conoscenza sul mio blog con tutti noi 🙂

      Mauro

        • Alberto on 4 settembre 2013 at 13:05
        • Reply

        Il complimento per te é sempre valido perché nei tuoi articoli non sei da meno peró in questo caso specifico mi devo complimentare con Marco. Ottimo lavoro!

          • Mondin Marco on 4 settembre 2013 at 15:06
          • Reply

          Grazie mille… 🙂 Spero ancora di poter contribuire con altri articoli…

    • robi on 1 marzo 2016 at 16:51
    • Reply

    Caro Mauro mi é piaciuto molto questo tuo articolo sulle EEPROM pero,x poterlo usare dovresti dirmi dove trovo
    l”esempio x poterle leggere che tu dici, pubblicherai piu avanti. grazie

    distinti saluti robi

    1. Ciao Robi,
      cercando nel blog non hai trovato nulla?
      Sai che mi viene il dubbio di non aver mai scritto la seconda parte ?

        • Andrea on 11 marzo 2016 at 10:45
        • Reply

        Ciao Mauro ,

        non hai più scritto l’articolo per la lettura dei dati memorizzati in modo ottimizzato?

        1. No Andrea,
          hai ragione, sono stato preso da altri progetti ed ho tantissime cose che vorrei approfondire, se ti va scrivilo tu e me lo invii io lo pubblicherò a tuo nome.

    • Giacomo on 10 maggio 2016 at 18:57
    • Reply

    ciao Mauro,
    intanto volevo farti i complimenti per il sito e per le tue spiegazioni chiare e dirette.
    E’ da poco tempo che sono entrato nel mondo di arduino, quindi non ho molta dimestichezza … comunque volevo chiederti un’informazione riguardante la memoria della EEPROM: cosa succede nel momento in cui la memoria è satura di dati ? blocca il funzionamento della scheda o non salva più nessun altro dato ?

    Grazie

    1. Ciao Giacomo,
      il funzionamento della EEPROM è simile ad uno spazio di archiviazione dati.
      Per cui quando avrai riempito tutte le aree disponibili potrai leggerle, o sovrascrivere quelle già utilizzate con dati nuovi, il tuo arduino/genuino continuerà a funzionare senza difficoltà.

        • Giacomo on 13 maggio 2016 at 16:59
        • Reply

        grazie mauro … gentile come sempre

        • Giacomo on 13 maggio 2016 at 18:45
        • Reply

        mauro volevo farti un’altra domanda…
        io sto usando un encoder (di una stampante) per un progetto scolastico e voglio salvare l’ultimo valore del mio encoder.. sto usando la libreria EEPROMex.h perchè ho la necessità di usare valori superiori a 255 e sto usando le funzioni EEPROM.readLong ed EEPROM.updateLong perchè ho anche numeri negativi..
        tuttavia dopo pochi cicli mi compare la scritta :” EXCEEDED MAXIMUM NUMBERS OF WRITES”.

        come faccio a risolvere questo problema?

        grazie

        1. Ciao Giacomo,
          non sono un esperto di calcoli in numeri binari, tuttavia ricordo di aver pubblicato un articolo di un appassionato arduino che ha scritto e condiviso sul mio blog dei ragionamenti molto interessanti sull’argomento.

Lascia un commento

Your email address will not be published.

Questo sito usa Akismet per ridurre lo spam. Scopri come i tuoi dati vengono elaborati.