Diferencia entre revisiones de «SD»

De ArduWiki
Saltar a: navegación, buscar
(Parametros)
(Descripción)
 
(No se muestran 26 ediciones intermedias de 2 usuarios)
Línea 4: Línea 4:
 
Debido a que usa [[SPI]], la conexión debe realizarse hacia los respectivos pines del Arduino; salvo SS/CS, este puede conectarse en cualquier pin digital libre.
 
Debido a que usa [[SPI]], la conexión debe realizarse hacia los respectivos pines del Arduino; salvo SS/CS, este puede conectarse en cualquier pin digital libre.
  
{{Nota|la librería soporta tarjetas SD del estándar '''SC''' y '''HC'''; por esta razón, la capacidad máxima soportada es de '''32 GB'''.}}{{Nota|la librería está preinstalada junto con la IDE de Arduino, no es necesario descargarla.}}{{Nota|debido a limitaciones de la librería y sistema de archivos compatibles, el tamaño máximo por archivo es de 4 GB o 4294967295 bytes.}}
+
{{Nota|La librería soporta tarjetas SD del estándar '''SC''' y '''HC'''; por esta razón, la capacidad máxima soportada es de '''32 GB'''.}}
  
 +
{{Tip|Librería oficial, es decir que está preinstalada junto con la [[IDE]] de Arduino, no es necesario descargarla.}}
 +
 +
{{Nota|debido a limitaciones de la librería y sistema de archivos compatibles, el tamaño máximo por archivo es de 4 GB o 4294967295 bytes.}}
 +
 +
Una mejor opción sera la libreria [https://github.com/greiman/SdFat SdFat] de Bill Greiman que soporta FAT16 y FAT32.
  
 
== La clase SD ==
 
== La clase SD ==
Línea 12: Línea 17:
 
=== Sintaxis ===
 
=== Sintaxis ===
 
<pre>
 
<pre>
 +
#include <SPI.h>
 +
#include <SD.h>
 
SD.begin(CS);
 
SD.begin(CS);
 
</pre>
 
</pre>
Línea 22: Línea 29:
 
|+Metodos de la clase SD
 
|+Metodos de la clase SD
 
|-
 
|-
! Métodos !! Descripción
+
! Método !! Descripción
 
|-
 
|-
| [[SD.begin()]] || Intenta inicializar la tarjeta SD al modo SPI, para así obtener de esta la información necesaria para empezar a usar.
+
| [[SD.begin()]] || Intenta inicializar la tarjeta SD al modo SPI, para así obtener de esta la información necesaria para empezar a usarla.
 
|-
 
|-
 
| [[SD.end()]] || Devuelve la librería al estado inicial; útil para remover, "en caliente" y de forma segura, la tarjeta.
 
| [[SD.end()]] || Devuelve la librería al estado inicial; útil para remover, "en caliente" y de forma segura, la tarjeta.
Línea 34: Línea 41:
 
| [[SD.remove()]] || Elimina un archivo.
 
| [[SD.remove()]] || Elimina un archivo.
 
|-
 
|-
| SD.mkdir() || Crea un directorio (carpeta).
+
| [[SD.mkdir()]] || Crea un directorio (carpeta).
|-
 
| SD.size() ||
 
 
|-
 
|-
| SD.seek() ||
+
| [[SD.rmdir()]] || Elimina un directorio (carpeta).
 
|}
 
|}
  
Línea 48: Línea 53:
 
=== Sintaxis ===
 
=== Sintaxis ===
 
<pre>
 
<pre>
File variable = SD.open(nombre, modo);
+
File variable1 = SD.open(nombre, modo);
 +
File variable2 = variable1.openNextFile();
 
</pre>
 
</pre>
  
Línea 58: Línea 64:
 
=== Metodos ===
 
=== Metodos ===
 
{| class="wikitable"
 
{| class="wikitable"
|+Metrodos libreria SD.h
+
|+Metrodos de la clase File
 
|-
 
|-
 
!Método!!Descripción
 
!Método!!Descripción
 
|-
 
|-
|[[File.read()]] || Lee un byte/caracter o varios del archivo.
+
| [[File.read()]] || Lee un byte/caracter o varios del archivo.
 
|-
 
|-
|[[File.peek()]] || Lee un byte/caracter del archivo sin avanzar al siguiente.
+
| [[File.peek()]] || Lee un byte/caracter del archivo sin avanzar al siguiente.
 
|-
 
|-
|[[File.available()]] || Retorna la cantidad de bytes/caracteres disponibles para leer (antes de llegar al final del archivo).
+
| [[File.available()]] || Retorna la cantidad de bytes/caracteres disponibles para leer (antes de llegar al final del archivo).
 
|-
 
|-
|[[File.write()]] || Escribe un byte/caracter o varios al archivo. Suele usarse para archivos binarios.
+
| [[File.write()]] || Escribe un byte/caracter o varios al archivo. Suele usarse para archivos binarios.
 
|-
 
|-
|[[File.print()]] || Escribe una representación textual de un dato (o una cadena de caracteres) al archivo. Suele usarse para archivos de texto plano.
+
| [[File.print()]] || Escribe una representación textual de un dato (o una cadena de caracteres) al archivo. Suele usarse para archivos de texto plano.
 
|-
 
|-
|[[File.println()]] || Igual al anterior, excepto que agrega una nueva línea de texto.
+
| [[File.println()]] || Igual al anterior, excepto que agrega una nueva línea de texto.
 
|-
 
|-
|[[File.flush()]] || Fuerza la actualización de los datos en la tarjeta SD.
+
| [[File.flush()]] || Fuerza la actualización de los datos en la tarjeta SD.
 
|-
 
|-
|[[File.close()]] || Cierra el archivo (o carpeta) para liberar correctamente cualquier recurso que esté siendo utilizado por esta instancia.
+
| [[File.seek()]] || Posiciona el "cursor" del archivo hacia una posición dada.
 
|-
 
|-
|[[File.seek()]] || Posiciona el "cursor" del archivo hacia una posición dada.
+
| [[File.position()]] || Retorna la posición actual del "cursor" del archivo.
 
|-
 
|-
|[[File.position()]] || Retorna la posición actual del "cursor" del archivo.
+
| [[File.size()]] || Retorna el tamaño del archivo (en bytes).
 
|-
 
|-
|[[File.size()]] || Retorna el tamaño del archivo (en bytes).
+
| [[File.name()]] || Retorna el nombre del archivo/carpeta.
 
|-
 
|-
|[[File.name()]] || Retorna el nombre del archivo/carpeta.
+
| [[File.isDirectory()]] || Verifica si esta instancia realmente representa un directorio (carpeta) y no un archivo regular.
 
|-
 
|-
|[[File.isDirectory()]] || Verifica si esta instancia realmente representa un directorio (carpeta) y no un archivo regular.
+
| [[File.openNextFile()]] || Abre el siguiente archivo de la lista (válido si esta instancia representa un directorio/carpeta).
 
|-
 
|-
|[[File.openNextFile()]] || Abre el siguiente archivo de la lista (válido si esta instancia representa un directorio/carpeta).
+
| [[File.rewindDirectory()]] || Devuelve la iteración de archivos al comienzo (válido si esta instancia representa un directorio/carpeta).
 
|-
 
|-
|[[File.rewindDirectory()]] || Devuelve la iteración de archivos al comienzo (válido si esta instancia representa un directorio/carpeta).
+
| [[File.close()]] || Cierra el archivo (o carpeta) para liberar correctamente cualquier recurso que esté siendo utilizado por esta instancia.
 
|}
 
|}
  
Línea 98: Línea 104:
 
Esta librería utiliza el formato de rutas de UNIX/Linux: el nombre de las carpetas involucradas se separa con '''/''' (barra inclinada o slash), siendo el destino final el último nombre de la secuencia. Por ejemplo:
 
Esta librería utiliza el formato de rutas de UNIX/Linux: el nombre de las carpetas involucradas se separa con '''/''' (barra inclinada o slash), siendo el destino final el último nombre de la secuencia. Por ejemplo:
  
<pre>ruta/hacia/el/archivo/que/buscamos.txt</pre>
+
<pre>
 +
datos.txt
 +
ruta/hacia/el/archivo/que/buscamos.txt
 +
</pre>
 +
 
 +
Esto hará que el archivo '''datos.txt''' sea creado o buscado en el directorio raíz; en otras palabras, fuera de toda carpeta.
 +
 
 +
{{Nota|Para efectos del sistema de archivos, los nombres '''NO SON''' sensibles a las mayúsculas; por lo tanto, '''datos.txt''', '''Datos.txt''' y '''DATOS.TXT''' hacen referencia al mismo archivo. Lo mismo aplica para directorios/carpetas.}}
  
 
Siendo '''ruta''', '''hacia''', '''el''', '''archivo''' y '''que''' las carpetas que nos llevan al archivo '''buscamos.txt'''
 
Siendo '''ruta''', '''hacia''', '''el''', '''archivo''' y '''que''' las carpetas que nos llevan al archivo '''buscamos.txt'''
Línea 106: Línea 119:
 
Si es algo que queremos colocar o ubicar en la "raíz", basta con simplemente colocar el nombre del elemento. Por ejemplo:
 
Si es algo que queremos colocar o ubicar en la "raíz", basta con simplemente colocar el nombre del elemento. Por ejemplo:
  
<pre>datos.txt</pre>
+
{{Nota|ya que el directorio de trabajo de la librería siempre es la raíz, da igual que la ruta sea absoluta (con '''/''' al comienzo) o relativa (sin '''/''' al comienzo).}}
 
 
Esto hará que el archivo '''datos.txt''' sea creado o buscado en el directorio raíz; en otras palabras, fuera de toda carpeta.
 
 
 
{{Nota|ya que el directorio de trabajo de la librería siempre es la raíz, da igual que la ruta sea absoluta (con '''/''' al comienzo) o relativa (sin '''/''' al comienzo).}}{{Nota|para efectos del sistema de archivos, los nombres no son sensibles a las mayúsculas; por lo tanto, '''datos.txt''', '''Datos.txt''' y '''DATOS.TXT''' hacen referencia al mismo archivo. Lo mismo aplica para directorios/carpetas.}}
 
  
 
=== Nombres SFN (8.3) ===
 
=== Nombres SFN (8.3) ===
Línea 142: Línea 151:
 
{{Nota|Este objeto se puede introducir directamente en un contexto booleano (ej.: como condición de un [[if... else]]); se evaluará como verdadero o '''true''' si el archivo/carpeta que representa está abierto/a en dicha instancia, falso o '''false''' en el caso contrario.}}
 
{{Nota|Este objeto se puede introducir directamente en un contexto booleano (ej.: como condición de un [[if... else]]); se evaluará como verdadero o '''true''' si el archivo/carpeta que representa está abierto/a en dicha instancia, falso o '''false''' en el caso contrario.}}
  
== Cómo agregar fecha y hora a los archivos ==
+
=== Cómo agregar fecha y hora a los archivos ===
Todo archivo/fichero y directorio/carpeta tiene por atributos, además del nombre, la fecha y hora de creación, último acceso y última modificación (datos que se pueden mirar en las "propiedades" o "detalles" del elemento, en el explorador de archivos de tu PC). La librería por defecto no tiene definido cómo obtener dicha información; pero cuando es requerido, por defecto coloca el '''01/01/2000 12:00:00 am''' aunque haya transcurrido un tiempo desde que el sistema ha arrancado.
+
Todo archivo/fichero y directorio/carpeta tiene por atributos, además del nombre, la fecha y hora de creación, último acceso y última modificación (datos que se pueden mirar en las "propiedades" o "detalles" del elemento, en el explorador de archivos de tu PC). La librería por defecto no tiene definido cómo obtener dicha información; pero cuando es requerido, por defecto coloca el '''01/01/2000 1:00:00 am''' aunque haya transcurrido un tiempo desde que el sistema ha arrancado.
  
 
Para definir la obtención de esos datos, primero debes crear una función con la siguiente "firma" (declaración):
 
Para definir la obtención de esos datos, primero debes crear una función con la siguiente "firma" (declaración):
 +
 
<pre>void nombreFuncion(uint16_t* fecha, uint16_t* hora)</pre>
 
<pre>void nombreFuncion(uint16_t* fecha, uint16_t* hora)</pre>
  
'''Quiere decir que dicha función DEBE retornar [[void]] y DEBE tener dos parámetros de tipo [[word|uint16_t]][[asterisco|*]]. El nombre no es importante.'''
+
'''Quiere decir que dicha función DEBE retornar [[void]] y DEBE tener dos parámetros de tipo [[word|word o uint16_t]][[asterisco|*]]. El nombre no es importante.'''
  
 
En dicha función, programarás la obtención de la fecha y hora actualizados; que pueden provenir de un reloj generado por software, un reloj NTP o un RTC.
 
En dicha función, programarás la obtención de la fecha y hora actualizados; que pueden provenir de un reloj generado por software, un reloj NTP o un RTC.
  
 
Luego, en el [[setup()]], colocas esta línea para así otorgarle dicha definición a la librería:
 
Luego, en el [[setup()]], colocas esta línea para así otorgarle dicha definición a la librería:
 +
 
<pre>SdFile::dateTimeCallback(nombreFuncion);</pre>
 
<pre>SdFile::dateTimeCallback(nombreFuncion);</pre>
  
 
== Advertencias ==
 
== Advertencias ==
 +
* Para efectos del sistema de archivos, los nombres '''NO SON''' sensibles a las mayúsculas; por lo tanto, '''datos.txt''', '''Datos.txt''' y '''DATOS.TXT''' hacen referencia al mismo archivo. Lo mismo aplica para directorios/carpetas.
 
* Atento al uso de la [[SRAM]], esta librería suele ser intensiva en ese recurso. Inicialmente consume alrededor de 700 bytes de este tipo de memoria.
 
* Atento al uso de la [[SRAM]], esta librería suele ser intensiva en ese recurso. Inicialmente consume alrededor de 700 bytes de este tipo de memoria.
 
* La tarjeta debe estar formateada en FAT16 o FAT32 con [https://www.sdcard.org/downloads/formatter_4/ SDFormatter] ('''NUNCA CON LOS UTILITARIOS DEL SISTEMA OPERATIVO'''), de lo contrario no funcionará con la librería o podría tener un bajo rendimiento.
 
* La tarjeta debe estar formateada en FAT16 o FAT32 con [https://www.sdcard.org/downloads/formatter_4/ SDFormatter] ('''NUNCA CON LOS UTILITARIOS DEL SISTEMA OPERATIVO'''), de lo contrario no funcionará con la librería o podría tener un bajo rendimiento.
Línea 187: Línea 199:
  
 
== Ejemplo 2 ==
 
== Ejemplo 2 ==
Este ejemplo muestra como conectar SD mediante [[SPI]], con MOSI, MISO, CLK, CS (11,12,13,4). CS puede variar segun si es Arduino Shield (4), Adafuit (19, Sparkfun(8) o MKRZero.
+
Este ejemplo muestra como conectar SD mediante [[SPI]], con MOSI, MISO, CLK, CS (11,12,13,4). CS puede variar segun si es Arduino Shield (4), Adafuit (19, Sparkfun(8) o MKRZero. Es el mismo ejemplo de '''CardInfo''', solo que los mensajes se han traducido al español.
  
 
<syntaxhighlight lang="c++">
 
<syntaxhighlight lang="c++">
Línea 197: Línea 209:
 
SdFile root;
 
SdFile root;
  
const int chipSelect = 4;  //Arduino Ethernet shield
+
const int chipSelect = 4;  //Arduino Ethernet shield, o cambiar según corresponda.
  
 
void setup() {
 
void setup() {
Línea 213: Línea 225:
  
 
   Serial.println();
 
   Serial.println();
   Serial.print("Card type:        ");
+
   Serial.print("Tipo de tarjeta:        ");
 
   switch (card.type()) {
 
   switch (card.type()) {
 
   case SD_CARD_TYPE_SD1:
 
   case SD_CARD_TYPE_SD1:
Línea 225: Línea 237:
 
       break;
 
       break;
 
   default:
 
   default:
       Serial.println("Unknown");
+
       Serial.println("Desconocido");
 
   }
 
   }
  
 
   if (!volume.init(card)) {
 
   if (!volume.init(card)) {
       Serial.println("No encuantro particion: FAT16/FAT32.\nSD esta formateada ?");
+
       Serial.println("No encuentro particion FAT16/FAT32. La tarjeta esta formateada ?");
 
       while (1);
 
       while (1);
 
   }
 
   }
  
   Serial.print("Clusters:          ");
+
   Serial.print("Clusteres:          ");
 
   Serial.println(volume.clusterCount());
 
   Serial.println(volume.clusterCount());
   Serial.print("Blocks x Cluster:  ");
+
   Serial.print("Sectores por Cluster:  ");
 
   Serial.println(volume.blocksPerCluster());
 
   Serial.println(volume.blocksPerCluster());
   Serial.print("Total Blocks:      ");
+
   Serial.print("Total de sectores:      ");
 
   Serial.println(volume.blocksPerCluster() * volume.clusterCount());
 
   Serial.println(volume.blocksPerCluster() * volume.clusterCount());
 
   Serial.println();
 
   Serial.println();
 
   uint32_t volumesize;
 
   uint32_t volumesize;
   Serial.print("Volume type is:    FAT");
+
   Serial.print("El tipo de volumen es:    FAT");
 
   Serial.println(volume.fatType(), DEC);
 
   Serial.println(volume.fatType(), DEC);
  
 
   volumesize = volume.blocksPerCluster();
 
   volumesize = volume.blocksPerCluster();
 
   volumesize *= volume.clusterCount();
 
   volumesize *= volume.clusterCount();
   volumesize /= 2;                      //Bloques SD son de 512 bytes (2 blocks are 1KB)
+
   volumesize /= 2;                      // Bloques (sectores) de una SD son de 512 bytes (2 bloques abarcan 1 KB o 1024 bytes)
   Serial.print("Volume size (Kb):  ");
+
   Serial.print("Tamanio del volumen (KB):  ");
 
   Serial.println(volumesize);
 
   Serial.println(volumesize);
   Serial.print("Volume size (Mb):  ");
+
   Serial.print("Tamanio del volumen (MB):  ");
 
   volumesize /= 1024;
 
   volumesize /= 1024;
 
   Serial.println(volumesize);
 
   Serial.println(volumesize);
   Serial.print("Volume size (Gb):  ");
+
   Serial.print("Tamanio del volumen (GB):  ");
 
   Serial.println((float)volumesize / 1024.0);
 
   Serial.println((float)volumesize / 1024.0);
  
   Serial.println("\nArchivos en SD (name, date and size in bytes): ");
+
   Serial.println("\r\nArchivos en SD (nombre, fecha y tamanio en bytes): ");
 
   root.openRoot(volume);
 
   root.openRoot(volume);
  
   //Mostrar contenido
+
   // Mostrar contenido
 
   root.ls(LS_R | LS_DATE | LS_SIZE);
 
   root.ls(LS_R | LS_DATE | LS_SIZE);
 
}
 
}
  
 
void loop(void) {
 
void loop(void) {
   //Nada
+
   // Nada
 
}
 
}
 
</syntaxhighlight>
 
</syntaxhighlight>
Línea 314: Línea 326:
  
 
== Referencias externas ==
 
== Referencias externas ==
* [https://www.arduinolibraries.info/libraries All Libraries]
+
* [https://www.arduinolibraries.info/libraries/sd SD] - All Libraries
 
* [http://www.arduino.cc/en/Reference/SD SD]
 
* [http://www.arduino.cc/en/Reference/SD SD]
 
* [https://en.wikipedia.org/wiki/8.3_filename Artículo de Wikipedia sobre los nombres SFN (en inglés)]
 
* [https://en.wikipedia.org/wiki/8.3_filename Artículo de Wikipedia sobre los nombres SFN (en inglés)]
 +
* [https://www.luisllamas.es/tarjeta-micro-sd-arduino/ Leer y escribir en tarjeta SD] - Luis Llamas
 +
* [https://naylampmechatronics.com/blog/38_Tutorial-Arduino-y-memoria-SD-y-micro-SD-.html Memorias SD y microSD] - Naylamp
 +
* [https://aprendiendoarduino.wordpress.com/category/sd/ SD] - Enrique Crespo
 +
* [http://manueldelgadocrespo.blogspot.com/p/biblioteca-sd.html Biblioteca SD] - Manuel Delgado
 +
* [https://www.prometec.net/sdcard/ SDcard] - Prometec
 +
* [https://eldesvandejose.com/2016/05/12/la-libreria-sd/ Libreria SD] - El desvan de José
  
 
[[Category:Librerias]]
 
[[Category:Librerias]]
 +
[[Category:Libreria SD]]

Revisión actual del 17:15 16 mar 2020

Descripción

La librería SD.h de SparkFun habilita un Arduino para la interacción con tarjetas SD (Secure Digital) mediante el protocolo Serial Peripheral Interface (SPI). A pesar de que existen tres tamaños distintos, todos operan exactamente de la misma manera (a determinada capacidad); por lo tanto, esta librería funciona con todos los tamaños.

Debido a que usa SPI, la conexión debe realizarse hacia los respectivos pines del Arduino; salvo SS/CS, este puede conectarse en cualquier pin digital libre.

Nota: La librería soporta tarjetas SD del estándar SC y HC; por esta razón, la capacidad máxima soportada es de 32 GB.


Tip: Librería oficial, es decir que está preinstalada junto con la IDE de Arduino, no es necesario descargarla.


Nota: debido a limitaciones de la librería y sistema de archivos compatibles, el tamaño máximo por archivo es de 4 GB o 4294967295 bytes.


Una mejor opción sera la libreria SdFat de Bill Greiman que soporta FAT16 y FAT32.

La clase SD

Es un objeto preinstanciado que se utiliza para iniciar la tarjeta y realizar operaciones generales sobre el sistema de archivos (FAT en sus versiones de 16 y 32 bits; exFAT no es compatible).

Sintaxis

#include <SPI.h>
#include <SD.h>
SD.begin(CS);

Parametros

CS
Puerto 4 si es Aduino Shield.

Metodos

Metodos de la clase SD
Método Descripción
SD.begin() Intenta inicializar la tarjeta SD al modo SPI, para así obtener de esta la información necesaria para empezar a usarla.
SD.end() Devuelve la librería al estado inicial; útil para remover, "en caliente" y de forma segura, la tarjeta.
SD.open() Abre un archivo o una carpeta.
SD.exists() Verifica si determinado archivo o carpeta realmente existe en la tarjeta.
SD.remove() Elimina un archivo.
SD.mkdir() Crea un directorio (carpeta).
SD.rmdir() Elimina un directorio (carpeta).

Nota: prácticamente ningún otro método funcionará si no se inicializa de antemano la tarjeta SD.


La clase File

Es un objeto que representa la instancia de un fichero (archivo) o directorio (carpeta) dentro de la tarjeta SD; con este se interactúa directamente sobre ellos. Se crea mediante las funciones SD.open() o File.openNextFile().

Sintaxis

File variable1 = SD.open(nombre, modo);
File variable2 = variable1.openNextFile();

Parámetros

variable
Nombre de variable a instanciar.
nombre
Nombre de archivo SFN (8.3). Ejemplo log12345.txt.
modo
Puede ser FILE_WRITE o FILE_READ

Metodos

Metrodos de la clase File
Método Descripción
File.read() Lee un byte/caracter o varios del archivo.
File.peek() Lee un byte/caracter del archivo sin avanzar al siguiente.
File.available() Retorna la cantidad de bytes/caracteres disponibles para leer (antes de llegar al final del archivo).
File.write() Escribe un byte/caracter o varios al archivo. Suele usarse para archivos binarios.
File.print() Escribe una representación textual de un dato (o una cadena de caracteres) al archivo. Suele usarse para archivos de texto plano.
File.println() Igual al anterior, excepto que agrega una nueva línea de texto.
File.flush() Fuerza la actualización de los datos en la tarjeta SD.
File.seek() Posiciona el "cursor" del archivo hacia una posición dada.
File.position() Retorna la posición actual del "cursor" del archivo.
File.size() Retorna el tamaño del archivo (en bytes).
File.name() Retorna el nombre del archivo/carpeta.
File.isDirectory() Verifica si esta instancia realmente representa un directorio (carpeta) y no un archivo regular.
File.openNextFile() Abre el siguiente archivo de la lista (válido si esta instancia representa un directorio/carpeta).
File.rewindDirectory() Devuelve la iteración de archivos al comienzo (válido si esta instancia representa un directorio/carpeta).
File.close() Cierra el archivo (o carpeta) para liberar correctamente cualquier recurso que esté siendo utilizado por esta instancia.

Nota: Prácticamente ningún método funcionará si la instancia es "vacía" o representa un archivo/carpeta sin abrir.


Formato de la ruta de acceso

Esta librería utiliza el formato de rutas de UNIX/Linux: el nombre de las carpetas involucradas se separa con / (barra inclinada o slash), siendo el destino final el último nombre de la secuencia. Por ejemplo:

datos.txt
ruta/hacia/el/archivo/que/buscamos.txt

Esto hará que el archivo datos.txt sea creado o buscado en el directorio raíz; en otras palabras, fuera de toda carpeta.

Nota: Para efectos del sistema de archivos, los nombres NO SON sensibles a las mayúsculas; por lo tanto, datos.txt, Datos.txt y DATOS.TXT hacen referencia al mismo archivo. Lo mismo aplica para directorios/carpetas.


Siendo ruta, hacia, el, archivo y que las carpetas que nos llevan al archivo buscamos.txt

Ese destino no tiene que ser solamente un archivo regular, también podría ser otra carpeta.

Si es algo que queremos colocar o ubicar en la "raíz", basta con simplemente colocar el nombre del elemento. Por ejemplo:

Nota: ya que el directorio de trabajo de la librería siempre es la raíz, da igual que la ruta sea absoluta (con / al comienzo) o relativa (sin / al comienzo).


Nombres SFN (8.3)

Parte de la escritura de rutas también involucra respetar el formato SFN (Short File Name o nombre corto de archivo), el cuál sigue estas reglas:

  • El nombre del elemento debe tener como mínimo 1 carácter, y como máximo 8 caracteres.
  • Si es un archivo regular, debe haber un único punto (.) justo después del nombre.
  • Si es un archivo regular, deben haber de 1 a 3 caracteres después del antes mencionado punto. Esto es lo que se conoce como la "extensión", una forma burda (pero muy usada en Windows) de etiquetar archivos por su contenido (ej.: txt para texto plano, jpg para imágenes codificadas en JPEG, mp3 para audio codificado en MPEG capa 3, etc.).

Nota: deduciendo de las reglas anteriores, los directorios/carpetas solo deben cumplir la primera; no debe haber punto (.) ni extensión en el nombre.


Caracteres permitidos

En el nombre puede venir cualquier carácter, excepto los siguientes:

  • " * + , / : ; < = > ? \ [ ] |
  • Los que tienen un valor decimal del 0 al 31
  • El carácter de valor decimal 127
  • El punto (.) sólo si no es antecedido por al menos un caracter permitido.

Técnicamente se permite el carácter espaciador y los del ASCII extendido (valor decimal del 128 al 255), sin embargo el primero no se recomienda porque puede hacer más complicado programar la generación de rutas; y lo segundo tampoco ya que la codificación no es estándar entre regiones geográficas (lo que puede llevar a una interpretación errónea del nombre en cuestión), eso sin contar que si el primer carácter es de valor 0xE5 (229 decimal), la librería podría después mal interpretarlo como un archivo eliminado (que no existe).

Curiosamente, las letras minúsculas están prohibidas; sin embargo esto no es cierto al crear e ingresar la ruta, ya que la librería automáticamente usa, en su lugar, las respectivas contrapartes mayúsculas al procesarla.

Comentarios

Hereda de la clase Stream, lo que quiere decir que prácticamente comparte la mayoría de métodos (y funcionalidad) de incluso la clase Serial. Que algunos no sean mencionados en esta página, no quiere decir que no se puedan usar.

Nota: a partir de la versión 1.0 del IDE de Arduino, se permite tener múltiples archivos abiertos a la vez.


Nota: El flujo de entrada y salida de esta clase se categorizan como por bloques.


Nota: Este objeto se puede introducir directamente en un contexto booleano (ej.: como condición de un if... else); se evaluará como verdadero o true si el archivo/carpeta que representa está abierto/a en dicha instancia, falso o false en el caso contrario.


Cómo agregar fecha y hora a los archivos

Todo archivo/fichero y directorio/carpeta tiene por atributos, además del nombre, la fecha y hora de creación, último acceso y última modificación (datos que se pueden mirar en las "propiedades" o "detalles" del elemento, en el explorador de archivos de tu PC). La librería por defecto no tiene definido cómo obtener dicha información; pero cuando es requerido, por defecto coloca el 01/01/2000 1:00:00 am aunque haya transcurrido un tiempo desde que el sistema ha arrancado.

Para definir la obtención de esos datos, primero debes crear una función con la siguiente "firma" (declaración):

void nombreFuncion(uint16_t* fecha, uint16_t* hora)

Quiere decir que dicha función DEBE retornar void y DEBE tener dos parámetros de tipo word o uint16_t*. El nombre no es importante.

En dicha función, programarás la obtención de la fecha y hora actualizados; que pueden provenir de un reloj generado por software, un reloj NTP o un RTC.

Luego, en el setup(), colocas esta línea para así otorgarle dicha definición a la librería:

SdFile::dateTimeCallback(nombreFuncion);

Advertencias

  • Para efectos del sistema de archivos, los nombres NO SON sensibles a las mayúsculas; por lo tanto, datos.txt, Datos.txt y DATOS.TXT hacen referencia al mismo archivo. Lo mismo aplica para directorios/carpetas.
  • Atento al uso de la SRAM, esta librería suele ser intensiva en ese recurso. Inicialmente consume alrededor de 700 bytes de este tipo de memoria.
  • La tarjeta debe estar formateada en FAT16 o FAT32 con SDFormatter (NUNCA CON LOS UTILITARIOS DEL SISTEMA OPERATIVO), de lo contrario no funcionará con la librería o podría tener un bajo rendimiento.

Ejemplo 1

void obtenerFechaHora(uint16_t* fecha, uint16_t* hora) {
  // Aquí llamas al reloj para que actualice los datos

  *fecha = FAT_DATE(anio, mes, dia);
  *hora = FAT_TIME(hora, minuto, segundo);
}

void setup() {
  // Todas las demás inicializaciones
  SdFile::dateTimeCallback(obtenerFechaHora);
}

void loop() {
  // El resto del programa
}

Siendo anio una variable de tipo unsigned int, mientras que el resto de componentes son de tipo byte. El año se agrega con un valor que tenga los cuatro dígitos.

El rango de fecha y hora válido es del 01/01/1980 12:00:00 am al 31/12/2107 11:59:59 pm.

Una vez "adjuntada", esta función se utiliza de manera similar a como ocurre en las interrupciones: implícitamente cuando la librería la necesite.

La fecha/hora de creación se aplica únicamente al momento de crear un archivo/carpeta que antes no existía; la de acceso con el simple hecho de lograr abrirla; y la de modificación cuando se cierra un archivo regular que fue abierto para escritura, o cuando una subcarpeta adquiere o pierde contenido.

Ejemplo 2

Este ejemplo muestra como conectar SD mediante SPI, con MOSI, MISO, CLK, CS (11,12,13,4). CS puede variar segun si es Arduino Shield (4), Adafuit (19, Sparkfun(8) o MKRZero. Es el mismo ejemplo de CardInfo, solo que los mensajes se han traducido al español.

#include <SPI.h>
#include <SD.h>

Sd2Card card;
SdVolume volume;
SdFile root;

const int chipSelect = 4;   //Arduino Ethernet shield, o cambiar según corresponda.

void setup() {
   Serial.begin(9600);
   Serial.print("Inicializando SD...");
   if (!card.init(SPI_HALF_SPEED, chipSelect)) {
      Serial.println("Error con SD:");
      Serial.println("* la trajeta SD esta puesta ?");
      Serial.println("* los cables estan correctos ?");
      Serial.println("* pin de chipSelect es correcto segun modelo ?");
      while (1);
   } else {
      Serial.println("Conexiones correctas y tarjeta SD en su lugar.");
   }

   Serial.println();
   Serial.print("Tipo de tarjeta:         ");
   switch (card.type()) {
   case SD_CARD_TYPE_SD1:
      Serial.println("SD1");
      break;
   case SD_CARD_TYPE_SD2:
      Serial.println("SD2");
      break;
   case SD_CARD_TYPE_SDHC:
      Serial.println("SDHC");
      break;
   default:
      Serial.println("Desconocido");
   }

   if (!volume.init(card)) {
      Serial.println("No encuentro particion FAT16/FAT32. La tarjeta esta formateada ?");
      while (1);
   }

   Serial.print("Clusteres:          ");
   Serial.println(volume.clusterCount());
   Serial.print("Sectores por Cluster:  ");
   Serial.println(volume.blocksPerCluster());
   Serial.print("Total de sectores:      ");
   Serial.println(volume.blocksPerCluster() * volume.clusterCount());
   Serial.println();
   uint32_t volumesize;
   Serial.print("El tipo de volumen es:    FAT");
   Serial.println(volume.fatType(), DEC);

   volumesize = volume.blocksPerCluster();
   volumesize *= volume.clusterCount();
   volumesize /= 2;                       // Bloques (sectores) de una SD son de 512 bytes (2 bloques abarcan 1 KB o 1024 bytes)
   Serial.print("Tamanio del volumen (KB):  ");
   Serial.println(volumesize);
   Serial.print("Tamanio del volumen (MB):  ");
   volumesize /= 1024;
   Serial.println(volumesize);
   Serial.print("Tamanio del volumen (GB):  ");
   Serial.println((float)volumesize / 1024.0);

   Serial.println("\r\nArchivos en SD (nombre, fecha y tamanio en bytes): ");
   root.openRoot(volume);

   // Mostrar contenido
   root.ls(LS_R | LS_DATE | LS_SIZE);
}

void loop(void) {
   // Nada
}

Ejemplo 3

Data logger.

#include <SPI.h>
#include <SD.h>

const int chipSelect = 4;

void setup() {
   Serial.begin(9600);
   Serial.print("Inicializando SD...");
   if (!SD.begin(chipSelect)) {
      Serial.println("SD fallo, esta puesta ?");
      while (1);
   }
   Serial.println("SD lista.");
}

void loop() {
   String data = "";
   for (byte analogPin=0; analogPin<3; analogPin++) {
      int sensor = analogRead(analogPin);
      data += String(sensor);
      if (analogPin < 2) {
         data += ",";
      }
   }
   File File = SD.open("datalog.txt", FILE_WRITE);
   if (File) {
      File.println(data);
      File.close();
      Serial.println(data);
   }else{
      Serial.println("Error abriendo datalog.txt");
   }
}

Ejemplo 4

Vea también


Referencias externas