Come utilizzare la libreria SD per scrivere e leggere dalla micro SD
La nuova board Arduino Ethernet ha in dotazione uno slot per scheda micro SD (Secure Digital) utile per dare la possibilità ai nostri programmi di memorizzare varie informazioni. La libreria permette di lavorare su schede formattate con file system FAT16 e FAT32, i nomi dei file devono essere composti da massimo 8 caratteri più 3 per l’estensione (formato 8.3 stile MS-DOS).
Come molte libreria dobbiamo inserire un riferimento nello sketch che la utilizza:
//inserisco riferimento alla libreria SD #include <SD.h>
successivamente, nel blocco setup, bisogna inizializzare la classe utilizzando il metodo begin(). A questo metodo dobbiamo passare il pin relativo alla funzione Card Select (CS) che per la Arduino Ethernet è uguale a 4, come visibile nello schema elettrico
//inizializza la classe e specifica //il pin Card Select SD.begin(4);
Il metodo restituisce false se si verificano problemi durante l’inizializzazione. Quindi prima di continuare è fondamentale verificare chequesta si concluda senza errori
if (SD.begin(4) == true) //inizializzazione ok //continua con il codice else //problemi nell'inizializzazione!
Per poter scrivere e leggere file dalla micro SD abbiamo bisogno di utilizzare la classe File che espone metodi che svolgono questo compito.
Creiamo un oggetto dalla classe File subito dopo la dichiarazione della libreria SD:
//inserisco riferimento alla libreria SD #include <SD.h> //creo un oggetto dalla classe File File MioFile;
Utilizziamo il metodo open() della classe SD per aprire un file esistente; il metodo restituisce un riferimento che viene associato all’oggetto MioFile:
//dopo l'inizializzazione posso lavorare sulla micro SD //Apro un file di testo MioFile = SD.open("filetest.txt", FILE_WRITE);
Da notare che se il file non esiste nella micro SD il metodo open() ne crea uno automaticamente.
il metodo open() della classe file accetta come argomenti due parametri, il primo è il nome del file, il secondo è un flag che indica se aprire il file in lettura o in scrittura, le opzioni sono:
FILE_READ | Apre il file per la lettura partendo dall’inizio |
FILE_WRITE | Apre il file per la scrittura |
Se non si verificano errori il metodo open() restituisce il riferimento al file, in caso di errore invece restituisce false; è buona norma controllare tramite un blocco if se si sono verificati errori:
//dopo l'inizializzazione posso lavorare sulla micro SD //Creao un file di testo MioFile = SD.open("filetest.txt", FILE_WRITE); if (MioFile == false) //problemi nell'accesso al file
Utilizziamo il metodo println() dell’oggetto MioFile per scrivere dati sul file appena aperto
//se non ci sono problemi nell'apertura dei file scrivi //qualcosa al suo interno if (MioFile != false) MioFile.println("Ciao Mondo");
Una volta ultimate le fasi di scrittura, se non intendiamo scrivere altro è consigliabile rilasciare le risorse chiudendo il file con il metodo close()
//chiudo il file MioFile.close()
La fase di lettura è analoga a quella di scrittura, si procede aprendo il file con il metodo open() ed eseguendo il metodo read() dell’oggetto MioFile
//Apro il file per la lettuta MioFile = SD.open("filetest.txt", FILE_READ); //Se non si sono verificati errori //leggo il file if (MioFile == true) { //Leggi fino alla fine del file while (MioFile.available()) { //read esegue la lettura di un byte alla volta Serial.write(MioFile.read()); } // close the file: MioFile.close(); }
Il metodo available() restituisce il numero di byte disponibili tra il puntatore e la fine del file. Il puntatore rappresenta un indice, o per rendere meglio l’idea, un cursore all’interno del file aperto.
Quando apriamo il file il puntatore viene posizionato sul primo byte quindi il metodo available() restituisce il numero di byte compresi tra il puntatore e la fine del file stesso. La read() legge il primo byte (dato che il puntatore si trova all’inizio del file) e fa avanzare il cursore di una posizione.
L’illustrazione seguente spiega meglio il concetto, (viene preso in considerazione un file di 100 byte)
Quando il file viene aperto il cursore punta sul primo byte e available() restituisce 100
Dopo la read() il cursore avanza di un byte spostandosi al secondo byte del file. Il metodo available() restituisce 99
Il ciclo while() esegue la read() ciclicamente fino a quando il valore di available() restituisce zero.
Una volta eseguita la lettura, se non intendiamo fare altro con il file, è consigliabile eseguire il metodo close() per rilasciare risorse e chiudere il file correttamente.
//chiudo il file MioFile.close()
Verificare l’esistenza di un file o di una directory
La classe SD espone alcuni metodi utili per gestire la nostra micro SD, uno di questi permette di verificare l’esistenza di un file all’interno di un percorso, il metodo è exists() e viene utilizzato in questo modo
//verifico l'esistenza di un file if (SD.exists("filetest.txt")) //true -> il file esiste else //false-> il file non esiste
possiamo includere anche un percorso di cartelle
//verifico l'esistenza di un file in un percorso if (SD.exists("arduino/arduino0022/filetest.txt")) //true -> il file esiste else //false-> il file non esiste
con lo stesso metodo verifichiamo l’esistenza di una directory
//verifico l'esistenza di un file in un percorso if (SD.exists("arduino/arduino0022")) //true -> la directory arduino0022 esiste else //false-> la directory arduino0022 NON esiste
Come cancellare un file dalla micro SD
Dopo aver eseguito diverse prove creando diversi file sulla micro SD possiamo liberare un po di spazio cancellandone qualcuno. Il metodo remove() della classe SD esegue questo compito, il suo utilizzo è molto semplice e l’unico parametro da passargli è il nome del file da cancellare:
//Cancella il file di test SD.remove("filetest.txt");
Se la cancellazione avviene con successo la funzione restituisce true altrimenti false.
//Cancella il file di test if (SD.remove("filetest.txt")) Serial.println("File eliminato!"); else Serial.println("Problemi nell'eliminazione");
Creare ed eliminare directory
Anche per la creazione ed eliminazione di directory è sufficiente utilizzare i metodi della classe SD, per la creazione utilizziamo il metodo mkdir mentre per l’eliminazione utilizziamo il metodo rmdir
//Creo una directory if(SD.mkdir("arduino")) Serial.println("Directory creata"); else Serial.println("Problemi nella creazione della directory");
con mkdir è possibile creare anche le sottodirectory in un colpo solo
//Creo directory e sottodirectory if(SD.mkdir("arduino/arduino1/arduino2")) Serial.println("Directory create"); else Serial.println("Problemi nella creazione della directory");
il codice precedente crea tre cartelle nidificate (arduino, arduino1 e arduino2) utilizzando solamente una singola istruzione.
Per eliminare le directory utilizziamo il metodo rmdir() in questo modo
//Elimina la directory if(SD.rmdir("arduino")) Serial.println("Directory Eliminata"); else Serial.println("Problemi nell'eliminazione della directory");
rmdir() non può eliminare una directory se all’interno sono presenti altre sottodirectory oppure file, bisogna quindi svuotale e poi eliminarle singolarmente
//Elimina le directory vuote SD.rmdir("arduino2"); SD.rmdir("arduino1"); SD.rmdir("arduino");
La gestione della micro SD risulta essere molto semplice e comoda per le diverse applicazioni che hanno bisogno di memorizzare dati piuttosto che recuperarne per eseguire calcoli o comparazioni. Nel prossimo articolo vedremo come utilizzare queste funzioni per creare un data logger.