Almacenamiento de datos en una tarjeta SD conectada a Arduino por SPI

publicado en: Portada | 47

El procedimiento para almacenar un registro de datos o log en una tarjeta de memoria SD con la librería SD de Arduino es similar al que se sigue para trabajar con métodos derivados de la clase Stream, como los de la popular Serial o como ocurre con la librería Ethernet, de la que hable en la guía para hacer consultas HTTP con la librería de comunicaciones Ethernet de Arduino. En líneas generales, los pasos que hay que seguir son:

  1. Inicializar las comunicaciones y el dispositivo
  2. Abrir el documento en el que se almacenan los datos
  3. Escribir los datos (el registro o log)
  4. Cerrar el documento en el que se han grabado los datos

En el siguiente ejemplo se muestra un sesión de grabación de datos en una tarjeta de memoria SD con la Librería SD estándar de Arduino. Se han resaltado las líneas que son relevantes para ayudar a explicar el proceso que se sigue, aunque revisar los comentarios y los mensajes mostrados con las órdenes Serial.println() es también ilustrativo del proceso.

1. Inicializar las comunicaciones y/o el dispositivo

La librería SD viene con el resto de los recursos de desarrollo de Arduino pero no se carga por defecto: no es seguro que vaya a necesitarse y utiliza recursos a los que se les puede dar otro destino si no se va a trabajar con tarjetas SD. Todo esto quiere decir que es necesario incluirla (cargarla) antes de poder utilizarla, para eso se escribe #include en la primera línea del ejemplo anterior.

La función SD.begin(PinCS) inicializa la librería y el dispositivo, siendo el parámetro PinCS número de pin al que está conectada la salida SS/CS del puerto bus SPI. Si no se incluye el parámetro en la llamada a la función se utiliza por defecto el pin que tenga asignado el hardware de la placa (normalmente el 10, como ocurre en un Arduino Uno, o el 54 en una placa Arduino Mega) La función devuelve true o false en caso de que se inicialice con éxito o no la librería y la tarjeta.

Las comunicaciones entre la tarjeta y la placa Arduino se realizan usando el bus SPI, normalmente valiéndose de que las tarjetas de memoria SD tienen un modo de funcionamiento compatible con SPI, como se explica en el artículo sobre la conexión de una tarjeta SD por SPI a Arduino. Las comunicaciones SPI utilizan la señal CS (por cable select o SS, por slave select) para activar por nivel bajo el dispositivo antes de enviar la información. La librería SD de placa Arduino considera por defecto el pin correspondiente del hardware (normalmente el 10, lo que puede ser un inconveniente en algunas placas como Leonardo) por eso, si se utiliza dicho pin, no es necesario indicarlo al inicializar las comunicaciones y el dispositivo con SD.begin() pero, en cualquier caso, será necesario declarar como salida con pinMode(10,OUTUPUT) aunque se utilice otro pin, que también habrá que establecer para salida de datos como puede verse en el código de ejemplo de arriba.

2. Abrir el documento en el que se almacenan los datos

La librería incluye el tipo de datos File, un puntero a un fichero con el que hacer referencia al mismo, por ejemplo, para leer o escribir. Una variable de tipo File puede evaluarse como una expresión lógica, lo que es muy práctico para saber si la operación de apertura ha tenido éxito usando, por ejemplo if() o while().

La función SD.open(nombre_documento,modo) es el paso previo para poder acceder a un documento (abrirlo) conforme al modo solicitado por el segundo parámetro que puede ser FILE_READ (leer datos) o FILE_WRITE (escribir datos) Si el modo de apertura se omite se considera de lectura.

El primero de los parámetros nombre_documento no puede omitirse; indica la ruta al documento expresándolo como (1) el nombre de la carpeta en las que se encuentra y (2) su nombre separado por el carácter barra o slash (/) También se utiliza la barra o slash para separar carpetas que estuvieran incluidas dentro de otras. Por ejemplo, grande/chica/fichero serviría para acceder a un documento llamado fichero incluido dentro de la carpeta chica que a su vez estuviera dentro de una carpeta llamada grande.

El valor de retorno de la función SD.open() es un puntero al fichero con el que referirse al mismo en posteriores accesos. Como se ha dicho, si no fuera posible abrir el documento en el modo solicitado el valor devuelto es false para que sea sencillo verificar si la operación ha tenido éxito o no.

Para el objetivo de este artículo, explicar cómo almacenar un registro de datos en una tarjeta de memoria SD, puede ser un poco pobre acceder a un documento sólo para escribirlo (sobrescribirlo) o leerlo. Por ejemplo, es común crear un nuevo documento si el previsto ya existe (y en ese sentido es frecuente utilizar una numeración como parte del nombre del archivo) o añadir los nuevos datos a un documento que ya existe.

Al objeto de resolver el primer caso, crear un nuevo documento si ya existe otro, la librería SD incluye la función SD.exists(documento) que permite consultar el sistema de archivos para saber si el parámetro documento, que puede hacer referencia tanto a un documento (fichero) como a una carpeta (directorio), existe o no devolviendo true o false respectivamente. Una vez que se sabe que el documento existe, si se quiere conservar, se puede utilizar otro nombre (por ejemplo incrementando una numeración que es parte del mismo, como se ha dicho) para crearlo respetando el que ya está grabado.

Como alternativa, sería posible borrar un documento utilizando el método SD.remove(fichero) siendo fichero el nombre del documento de la tarjeta de memoria SD que debe borrarse. El nombre del documento se expresa utilizando el formato carpeta/nombre explicado antes.

Las opciones para el segundo caso, añadir datos a un documento, pueden no ser tan evidentes, y seguramente será necesario utilizar alguno de los (no muy documentados) modos de apertura:

  • O_READ abrir para leer
  • O_RDONLY abrir de sólo lectura (equivalente a O_READ)
  • O_WRITE abrir para escritura de datos
  • O_WRONLY abrir como sólo escritura (equivalente a O_WRITE)
  • O_RDWR abrir como lectura y escritura (equivalente a O_READ|O_WRITE)
  • O_ACCMODE abrir en modo de acceso (equivalente a O_RDWR)
  • O_APPEND abrir para añadir (abrir para escritura grabando los datos nuevos al final de los actuales)
  • O_SYNC abre para escritura sincronizando a cada grabación
  • O_CREAT crea el documento si no existe
  • O_EXCL abre el documento sólo si es necesario crearlo
  • O_TRUNC abre un documento que existe borrando (truncando) previamente su contenido

Considerando los modos de apertura anteriores, puede utilizarse O_APPEND en la apertura, de manera que se añadirán a un documento que ya existan los nuevos datos, incrementando el registro ya existente, resolviendo así el segundo inconveniente planteado al principio.

3. Escribir los datos

Como en otras librerías con métodos basados en la clase Stream, en la librería SD están disponibles, para grabar datos, los métodos print(dato,base) y println(dato,base) para almacenar texto y write(buffer,longitud) para grabación de datos en modo binario.

Las funciones print() y println() pueden usarse con un único parámetro de entrada («dato», en la referencia de arriba) que permite escribir un dato como texto o convertirlo a una base si se indica el segundo parámetro opcional («base», en la referencia de arriba) Para expresar la conversión con el segundo parámetro puede usarse alguna de las constantes BIN para convertir a binario (base 2), OCT para convertir a octal (base 8), DEC para decimal (base 10) o HEX para hexadecimal (base 16)

Para los archivos de registro de datos (log) es habitual utilizar formatos de texto porque son muy sencillos de grabar y leer, por lo que, por ejemplo, se podrán consultar o procesar con multitud de aplicaciones. El principal inconveniente a la hora de grabar es su menor rendimiento: normalmente ocupan más en proporción cuando se almacenan datos numéricos; a la hora de leer, el inconveniente es el acceso aleatorio a una parte concreta del documento: con frecuencia es necesario leer toda la información previa hasta encontrar la buscada, lo que hace mucho más lento el proceso. La función de escritura write() resuelve estos inconvenientes grabando en modo binario. La función necesita un parámetro, «buffer», que es una matriz de byte o char y acepta un segundo parámetro opcional «longitud» con el que especificar la cantidad de bytes que se graban del total del buffer; si se omite este segundo parámetro se almacena la totalidad de la matriz.

4. Cerrar el documento en el que se han grabado los datos

Cuando se ha terminado de grabar todo el registro de datos en el archivo se finaliza su uso (se cierra) con la función close() del objeto File, que además liberará los recursos que estaba utilizando. La llamada se hace con el formato habitual archivo.close() en el que archivo representa el puntero devuelto por SD.open().

Por el uso habitual de un dispositivo basado en un microcontrolador de pequeña escala, como es el caso de de un Arduino Uno e incluso de un Arduino Mega, no necesariamente hay un final en la ejecución del programa en el que usar la función close(), sino que es posible que la aplicación se esté ejecutando hasta apagar el dispositivo. Este comportamiento puede hacer que se pierdan más o menos datos dependiendo del buffer utilizado por el software y por el hardware (por ejemplo por una memoria intermedia en el módulo que soporta la tarjeta SD) Para minimizar este inconveniente se puede utilizar la función flush() que proporciona el objeto File y que vacía el contenido de la memoria intermedia forzando un grabado «real» de los datos en la tarjeta de memoria SD; como es lógico, realizar llamadas intensivas a este método ralentizará el funcionamiento del programa, por lo que debe calcularse con cuidado la necesidad de su uso.

Ejemplo de almacenamiento de datos en una tarjeta SD

En el siguiente ejemplo se muestra cómo sería el proceso de almacenamiento en una tarjeta de memoria SD de un registro de los datos obtenidos por un sensor. El formato elegido es CSV, que compensa el inconveniente de ocupar más de lo necesario (al ser datos numéricos grabados como texto) con la sencillez, tanto en la escritura de la aplicación desarrollada para Arduino como en su posterior interpretación para postprocesar el contenido.

La lectura del sensor del ejemplo corresponde con la monitorización de un circuito de vibración. Los valores monitorizados durante un periodo se acumulan antes de grabarlos para almacenar el número de vibraciones totales detectadas cada cierto tiempo y así estimar la cantidad o frecuencia de movimiento.

Al empezar el programa ya se monitoriza la vibración y puede seguirse en una consola serie. Para iniciar o terminar una sesión de grabación se acciona un pulsador que genera una interrupción. Además de disponer un condensador para evitar rebotes, se bloquea el inicio de una sesión hasta que transcurra cierto tiempo del último cierre.

Como la idea es grabar sesiones de forma consecutiva, el programa grabará un documento con un nombre y un número que se irá incrementando cada vez que se genere.

Como se ha explicado más arriba, especialmente en un dispositivo microcontrolado, es interesante almacenar el contenido del buffer del archivo con cierta frecuencia para evitar (lo más posible) la pérdida de datos. En este ejemplo se consigue utilizando la función flush() del objeto documento cada cierto intervalo de tiempo.

Víctor Ventura

Desarrollando aplicaciones para la web conocí el potencial de internet de las cosas, encontré la excusa perfecta para satisfacer la inquietud de aprender electrónica que había tenido desde siempre. Ahora puedo darme el gusto de programar las cosas que yo mismo diseño y fabrico.

Más entradas - Página web

Sígueme:
TwitterLinkedIn

Seguir Víctor Ventura:

Programador multimedia y web + IoT. Mejor con software libre.

Desarrollando aplicaciones para la web conocí el potencial de internet de las cosas, encontré la excusa perfecta para satisfacer la inquietud de aprender electrónica que había tenido desde siempre. Ahora puedo darme el gusto de programar las cosas que yo mismo diseño y fabrico.

47 Respuestas

  1. Arturo

    Hola buenos dias, estaba leyendo sobre la informacion que subio de como almacenar en la SD, pero en mi caso yo tengo un Arduino YUN, tengo que habiitar los pines como en tu programación? Es que la tarjeta SD ya lo trae en el mismo Arduino YUN, sin necesidad de una shield. me podria ayudar o dar un tutorial

    • Víctor Ventura

      Hola, Arturo.

      No lo he probado en un Arduino Yun pero, hasta donde sé, el pin que usan Arduino Mega y Arduino Yun para CS (SS) es el 53.

      ¿Alguien con un Arduino Yun que lo confirme?

  2. Humberto

    Que tal Victor, estoy implementando el codigo y necesito el O_APPEND, ya que a veces cuando vuelvo a insertar la sd ya no me guarda los datos hasta que reinicio el arduino. Pienso que se podria quitar con dicho codigo ya que su funcion es escribir despues de cada escritura. Solo que me da el error aqui:
    File dataFile = SD.open("humedad.txt", FILE_WRITE | FILE_APPEND ) ;

    me marca error en FILE_APPEND
    me dice que was not declared in this scope

    • Víctor Ventura

      Hola, Humberto.

      El valor de O_APPEND es 0x04

      Para usar las constantes de los modos de apertura puedes añadir a la cabecera de tu código:

      Saludos. Gracias por participar en polaridad.es.

  3. Daniel Aguilar

    Buenas tardes. Muy interesante tu post, no obstante, tengo la siguiente duda: ¿CUàl es el tiempo de escritura de arduino si quiero almacenar en una SD datos provenientes de un ADC externo el cuál es bastante rápido?

    • Víctor Ventura

      Hola, Daniel.

      No sé decirte exactamente la velocidad. Puede medirse, si es que fuera relevante, pero no creo que todos los accesos, ni aún los del mismo tipo, tarden lo mismo.

      Sé que el acceso es bastante lento, así que tendrás que bloquear la recepción de datos desde el dispositivo que hace la ADC, y perder datos, o definir un buffer para grabar lo que no dé tiempo, si es que hay momentos en los que no llegan datos al ADC que se pueden aprovechar para sincronizar los que no fue posible grabar.

      Espero que esto te ayude un poco. Gracias por participar en polaridad.es

  4. Luis

    Buenas tardes y muchas gracias por este tutorial, que llevo meses buscando algo similar, claro y conciso y hoy lo encontre por fin.
    Tengo una pequeña duda: tengo dos archivos, encender.txt y apagar.txt, ambos estan ordenados 22121435 por dd/MM/hh/mm. o asi: 22/12 14:35 este para encender.txt y 22121641 (22/12 16:41 para apagar.txt, la pregunta seria si se podrian tener los dos archivos abiertos a la vez o tendria que ponerle una condicion como por ejemplo si son mas de las 15 horas abre el archivo apagar.txt.
    Lo que pretendo es que arduino compare a traves del rtc los archivos contenidos en la SD y si el dia, mes, hora y minutos del dia actual estan en el archivo endender.txt me encienda un led, si no estan lo deje apagado. Nuevamente cuando se aproxime la hora de apagar, lea el archivo apagar.txt y si coincide el dia, mes, hora y minutos actuales con los del archivo me apague el led si esta encendido. un saludo y perdon por als molestias

    • Víctor Ventura

      Hola, Luis.

      En efecto, no se pueden mantener abiertos los dos documentos a la vez usando la librería SD. Si los documentos con las fechas los gestionas tú ¿No podrías poner toda la información en uno solo?

      Supongo que tienes buenas razones para usar una tarjeta SD en lugar de, por ejemplo, leer los datos de la EEPROM, que me da la impresión de que es más eficiente, salvo que sean miles de veces las que enciendes y apagas los LED. Lógicamente, tú conoces mejor tu proyecto para optar por un método u otro 🙂

      Tampoco entiendo muy bien lo de leer todo el documento. Seguramente pensando en un dispositivo con pocos recursos (como un MCU) lo que yo haría, por si te ayuda en algo, sería leer de forma circular un valor, usarlo, y leer el siguiente indexándolo con un puntero (esto sería sencillísimo usando la EEPROM). Como hay fechas para encender y apagar, leería ambas, con el mismo criterio, y así las tendría preparadas. Después de utilizar cada fecha (cuando venzan y se encienda o apague cuando se alcancen) volvería a leer.

      ¿Te ayudo algo con esto? Gracias por participar en polaridad.es

  5. Luis

    Hola, si que me has ayudado, y lo de usar la sd es porque cada 3 meses se cambiaran las horas y dias de encendido y apagado, y habra que volver a escribirlas en la SD.
    El proyecto es para el bloqueo de una puerta de seguridad, en lugar del led habra un rele que de paso a 220v que cerrara o abrira segun sean las horas y dias, luego la siguiente parte que si utilizare la EEPROM, habra tarjetas con un codigo alfa-numerico que permitiran desbloquear o bloquear esa puerta a aquellas personas que tengan la clave en la tarjeta a cualquier hora y dia, mas que nada para evitar alguna caída, pero primero tengo que verificar que el codigo no me de muchos problemas. Un saludo y gracias

  6. Xabat Etxegia

    Hola buenos días, estamos haciendo un proyecto en tecnología en 2. de bachillerato y quiero saber como puedo pasar al mismo tiempo datos de diversos sensores de arduino a una SD.

    • Víctor Ventura

      Hola, Xabat.

      Si estás creando un documento en formato CSV puedes grabar en cada línea varios datos separándolos por comas (precisamente esa es la finalidad de ese formato de archivo).

      Por ejemplo, una línea podría contener una referencia al tiempo (puede ser el tiempo real o el transcurrido desde cierto instante), una coma, la temperatura obtenida de un sensor, otra coma, el consumo eléctrico y un fin de línea. Unas cuantas líneas de ese ejemplo podrían quedar así:

      20161219104412,20.5,0.75
      20161219104422,21.0,0.8
      20161219104442,21.5,0.75

      No das muchos datos del problema, así que solo puedo responderte genéricamente pero, usando la imaginación, puedo suponer que el problema sea grabar varios datos (a la librería SD no le gusta trabajar con varios documentos a la vez). La solución se puede intuir en la respuesta pero, por aclararlo, la idea es grabar todos los datos de los diferentes sensores de una vez (en una linea del documento CSV) almacenándolos en el MCU hasta que sea el momento, aunque la frecuencia de muestreo de ellos sea diferente, repitiendo u omitiendo datos si fuera necesario para sincronizarlos.

      Espero que esto os ayude un poco.

      Sería genial si nos contaras cómo es el proyecto y cómo se va desarrollando para que a todos nos enriquezca vuestra experiencia.

      ¡Suerte con el proyecto!

  7. Xabat Etxegia

    Gracias, nos ha servido de mucho. Queremos hacer un CanSat para el concurso nacional, y para ello tenemos que recopilar información de varios sensores y pasarlos a una tarjeta SD para luego hacer varios gráficos (tiempo-altura, temperatura-altura).
    Por otra parte, tenemos que utilizar el sensor NTC 10k pero no conseguimos calcular la temperatura real. Creo que el problema esta en que los valores que recibimos son de la resistencia y no sabemos como traducirlos en temperatura nos podrías ayudar?

  8. Eñaut

    Buenas tardes Víctor! Soy un compañero de grupo de Xabat. Lo primero darte las gracias por la ayuda y en general por invertir una parte de tu tiempo en ayudar a los demas! Por otra parte, te animo a que escribas el artículo del que hablas en tu último comentario, no solo porque nos serviría a nosotros sino para bien de todos los interesados en este tema. Por último, refiriéndome también a tu último comentario, no entiendo a que te refieres cuando dices «método de lectura de un termistor usando una tabla de búsqueda o el método de cálculo de la temperatura de un termistor con una fórmula (función), ambos del playground de Arduino». Si no te importa mucho explicarme un poco de que se trata, te lo agradecería!! Un saludo.

    • Víctor Ventura

      Hola, Eñaut

      Básicamente hay dos formas de calcular la temperatura en función de la resistencia del termistor: ① creando un vector que almacena la temperatura correspondiente a la resistencia medida (o que se obtiene a partir de él), recurso que en programación se suele llamar tabla de búsqueda o tabla de consulta (o más frecuentemente LuT) o ②  utilizando una función que permite calcular la temperatura conociendo la resistencia en el termistor, para lo que suele utilizarse la ecuación de Steinhart-Hart.

      En el comentario a que haces referencia enlazo a los correspondientes recursos del playground de Arduino desde donde puedes descargar código para calcular la temperatura por cada método. Puedes probar ambos y quedarte con el que te vaya mejor a tu proyecto.

      Hay muchos artículos sobre el uso de termistores pero si os parece interesante escribiré uno en cuanto tenga un rato libre. Espero que os guste 🙂

      Gracias por participar en polaridad.es

  9. Eñaut

    He subido el siguiente sketch (que es el del playground de Arduino) y los resultados me salen alrededor de 80.

    #include

    double Thermistor(int RawADC) {
    double Temp;
    Temp = log(10000.0*((1024.0/RawADC-1)));
    // =log(10000.0/(1024.0/RawADC-1)) // for pull-up configuration
    Temp = 1 / (0.001129148 + (0.000234125 + (0.0000000876741 * Temp * Temp ))* Temp );
    Temp = Temp – 273.15; // Convert Kelvin to Celcius
    Temp = (Temp * 9.0)/ 5.0 + 32.0; // Convert Celcius to Fahrenheit
    return Temp;
    }

    void setup() {
    Serial.begin(115200);
    }

    void loop() {
    Serial.println(int(Thermistor(analogRead(0)))); // display Fahrenheit
    delay(100);
    }

    • Víctor Ventura

      Hola, Eñaut.

      Pues si está en el exterior, con el frío que hace estos días, puede que sea un poco alto (26,7 °C ¿No prefieres usar grados Celsius?) Por cierto, creo que hay algún error en el código, seguramente al pegarlo en el comentario.

      Parece que la cosa prospera ¿No? ¡Ánimo con el proyecto!

  10. Eñaut

    Hola Víctor. No entiendo cual puede ser el fallo, ya que el sketch lo he «copiado» del Playground de Arduino y las conexiones (son muy simples) las he repasado y estan bien. Acabo de probar otra vez, ahora sí en grados Celsius, y estando en clase (interior) los resultados me salen alrededor de 30. Para que sepas, aparte de este sensor de temperatura utilizamos otro, LM35DZ, y con ese sensor no tenemos ningun problema.

    • Víctor Ventura

      Hola, Eñaut.

      Los termistores suelen ser bastante fiables y (en el rango que les corresponda) bastante precisos. Es raro que te dé un valor tan alto… suponiendo que lo sea.

      Para buscar el problema, lo que yo haría es:

      1. Verificar que la conexión es correcta. Seguro que sí, es trivial, pero es lo primero que descartaría.
      2. Utilizar un termómetro de confianza para verificar que en varias temperaturas la medida es (o no) correcta (solo haces referencia a un valor)
      3. Utilizando la hoja de datos del fabricante, verificaría que los coeficientes (o constantes) de Steinhart–Hart (que aparecen como A, B y C en la ecuación de Steinhart–Hart) y que pueden producir un error en el cálculo.
        Los valores que usa tu código son:

        • A=0.001129148
        • B=0.000234125
        • C=8.76741E-08

         
        Si no consigues esos valores del fabricante puedes calcularlos/estimarlos, pero es un poco delicado, a lo peor en tal caso te interesa usar otro componente ¿Ese LM35? 🙁

      Creo que ya sé el problema del código que has pegado: contiene los caracteres < y > en #include <math.h> que, usados como texto, no aparecen en el comentario porque tienen un significado especial en HTML.

      ¡Ánimo, ya casi lo tienes resuelto!

      Gracias por participar en polaridad.es

  11. Eñaut

    Buenas noches, la cosa es que nos obligan a utilizar los dos sensores de temperatura, no podemos elegir uno u otro. Bueno, para calcular la temperatura con el sensor NTC, partiendo de la fórmula «deltaV=R*I» consigo medir la resistencia del sensor (Rntc), pero luego como relaciono esa resistencia con la temperatura (aparte de utilizando la tabla que aparece en el «datasheet» del sensor)?

    • Víctor Ventura

      Hola, Eñaut.

      Las dos formas de calcular la temperatura con un termistor son ① por medio de la ecuación de Steinhart–Hart, que necesita las constantes correspondientes, que el fabricante debe proporcionar, o ② utilizando una tabla de búsqueda (LuT) que contiene los valores de temperatura en función de la resistencia que, como en el caso anterior, el fabricante proporciona en la correspondiente hoja de datos.

      Si no dispones de los datos del fabricante (parece que no es tu caso) tienes que crear tú la LuT midiendo temperaturas y resistencias. Con esos valores también podrías calcular los coeficientes que necesitas para aplicar la ecuación de Steinhart–Hart, aunque es algo delicado que no creo que merezca la pena en este caso (para el proyecto que estás haciendo).

      La ecuación de Steinhart–Hart es bastante precisa y los datos que se obtienen al aplicarla suelen ser los correctos siempre que las constantes o coeficientes correspondientes lo sean. Utilizar una LuT puede ser más sencillo (desde el punto de vista del MCU, ya que requiere menos cálculo) pero necesita cierta cantidad de memoria para almacenar los datos y, dependiendo de cantidad disponible y de la precisión que se necesite, puede ser necesario interpolar pero es un método perfectamente aceptable y muy utilizado tanto en electrónica como en programación.

      Entiendo que la hoja de datos del fabricante del termistor que estás usando te facilita una tabla de valores ¿Qué inconveniente tienes en utilizarla? Incluso, aunque optaras por usar la ecuación de Steinhart–Hart, me parecería interesante usar también la LuT para tener una doble comprobación en un programa de prueba.

      Si ya la has aplicado y el resultado también es incorrecto puede ser que hayas confundido el termistor, la hoja de datos o el circuito no esté bien ¿Lo revisaste como te sugerí en un comentario anterior? Es algo trivial pero, si hay errores, hasta lo más evidente puede haberlos producido.

      ¡Ánimo con el proyecto y un saludo!

  12. Frank

    Hola amigo, hago un proyecto en el que necesito guardar la medición de temperatura de un sensor, pero necesito guardar esta medición según la fecha y a la hora que se realizó ¿es posible? para luego visualizarla en un archivo de lectura.

  13. Johann

    Hola! queria saber como hago para leer un archivo con extension .HTML
    hice un servidor web con la ethernet shield y me ocupa mucha memoria de la placa. y quiero almacenar los codigos html en la tarjeta sd. asi que cuando yo le mande el comendo desde la web lo haga desde la tarjeta sd y las acciones del codigo que esta cargada en el microcontrolador atmega328p! tengo un Arduino Uno!

    • Víctor Ventura

      Hola, Johann.

      El método para leer de la tarjeta de memoria SD es similar al que se expone para escribir pero en lugar de enviar los datos con print o write se leen con read. A grandes rasgos, los pasos que hay que seguir son:

      • Cargar la librería SD con #include <SD.h>
      • Definir una variable de tipo de dato fichero para el acceso al documento que contiene el código HTML (que es un texto) con algo como File web;. Seguramente también necesites una variable de tipo texto para almacenar lo que vayas leyendo; podrías definirla con algo como char letra;.
      • Para inicializar la librería SD se usa SD.begin(PIN_CS);
      • Una vez inicializada la librería SD hay que elegir el documento con el que se va a trabajar y elegir el modo de acceso, lectura, en este caso. Puedes usar algo como web=SD.open("WEB.HTM",FILE_READ); para hacerlo.
      • Como te decía antes, tendrás que ir leyendo el documento con read hasta que devuelva -1, que es la forma de indicar que se ha llegado al final, o usar available para saber cuánto texto hay disponible. Para leer puedes usar algo como letra=web.read();.
      • Cuando hayas terminado, lo más conveniente es liberar el documento con algo como web.close();, aunque no sea imprescindible (si no lees más) lo correcto es cerrar el fichero al final de la lectura.

      Gracias por visitar polaridad.es

  14. Eñaut

    Hola Víctor, te he escrito anteriormente sobre como almacenar datos en la tarjeta SD. Como te dijimos, estamos preparando un CanSat para el concurso nacional y decidimos utilizar una cámara monocromática e ir poniéndole diferentes filtros para, durante el vuelo del CanSat, sacar varias fotos con los diferentes filtros y después sacar conclusiones. El problema es que tenemos que buscar una aplicación a la cámara y las fotos, esto es, para que serán las fotos o que conclusiones sacaremos de ellas; al principio pensamos en seguir los pasos de Sarah Parcak (arqueóloga estadounidense, la cual busca restos arqueológicos tomando fotos desde el aire y con diferentes filtros) pero no nos termina de convencer. Se te ocurre algúna otra aplicación?? (no se si sabrás mucho sobre esto, pero por si acaso te lo pregunto)

    • Víctor Ventura

      Hola, Eñaut.

      Mis conocimientos sobre arqueología se sitúan entre nada y absolutamente nada 🙁 Eres muy amable al pensar que yo sé de cosas tan variadas 🙂

      Con respecto a lo de la cámara, quería hacer una puntualización por si te ayuda. Los filtros lo que hacen es bloquear determinadas longitudes de onda, no añadirlas. Es decir, a una cámara que sea, por ejemplo, capaz de captar la radiación infrarroja (la mayoría) se le puede impedir que las detecte interponiendo en su objetivo un filtro infrarrojo. El filtro «quita» (bloquea) esa parte del espectro, no la aporta cuando la cámara no la «tiene».

      Como es fácil conseguir una cámara cuyo sensor detecte infrarrojos (y el filtro de infrarrojos) es un buen ejemplo, lástima que no os guste. También se puede usar (más o menos) para detectar calor y tiene aplicación en varios campos: encontrar incipientes incendios, presencia de animales, fugas de gases, humedad en las edificaciones… y restos arqueológicos, que me acabo de enterar 🙂 Para otros colores, sin usar cámaras multiespectrales específicas, ahora no caigo en ningún ejemplo interesante, pero si se me ocurre te mando un correo electrónico.

      ¡Qué nivel está alcanzando vuestro proyecto! ¿no os gustaría escribir artículos para polaridad.es? Espero por lo menos que nos contéis qué tal sale 🙂

      Hasta pronto.

  15. Eñaut

    Buenas tardes Víctor, siento no haber contestado antes a tu mensaje pero hemos estado bastante liados de trabajo… hemos mirado lo que dijiste de que se puede detectar el calor, pero no sabemos como hacerlo, tú sabes?
    Por otro lado, en cuanto al módulo SD, a que pines tengo que conectarlo en un Arduino Pro Micro (es el que nos han dado los de la organización de la competición)?(https://forum.arduino.cc/index.phptopic=240815.0) La información de este enlace trata sobre ello, pero he visto que unos dicen que las conexiones son de una manera y otros dicen que de otra. Me puedes ayudar?

    Por último, sintiéndolo mucho no tengo/tenemos tiempo para escribir artículos en tu blog (ni en ningún otro, claro), ya que estamos en 2º de bachillerato y es un año duro y difícil.

    Un saludo,

    Eñaut

    • Eñaut

      Perdona, la gente que ha comentado en dicho enlace dice que las conexiones son de una manera, pero en la librería de la SD he visto que son de otra manera: (cambia el SCSG—–>SS 0 CS)
      Pro Micro Pin 10 -> Módulo SD CS
      Pro Micro Pin 16 -> Módulo SD MOSI
      Pro Micro Pin 14 – > Módulo SD MISO
      Pro Micro Pin 15 -> SCK módulo SD

      o

      uint8_t const SS_PIN = 17;
      uint8_t const MOSI_PIN = 16;
      uint8_t const MISO_PIN = 14;
      uint8_t const SCK_PIN = 15;

      • Víctor Ventura

        Hola, Eñaut.

        He revisado el pinout del Pro Micro y ciertamente corresponde con lo que escribes (lo de usar el pin 10 para CS es discutible pero es lo habitual)

        No entiendo cuál es el problema ¿Que la numeración no corresponde con la de otras placas? eso es normal, cada placa (por supuesto, cada MCU tiene su propio pinout.

        Saludos.

    • Víctor Ventura

      Hola, Eñaut.

      Me alegra verte de nuevo por aquí. La forma de comunicación a la que se presta este canal es así, no te preocupes, escribe cuando te venga bien 🙂

      Básicamente, para detectar el calor con una cámara sin filtro infrarrojo hay que suponer que donde se detecta más intensidad de luz es donde hay más calor.

      Como no es una cámara térmica, la anterior afirmación es mentira: la cámara también detectará la luz en el espectro visible. A determinadas horas y con determinados objetos (¿arqueológicos?) el error es más admisible. A plena luz no sirve.

      Para poder ir más allá de simplemente concluir algo como «esto está más caliente que esto otro» (porque se ve más iluminado) tendrás que hacer mediciones en condiciones controladas para calibrar (o algo parecido) las imágenes que obtienes.

      La parte más delicada es la obtención de la imagen (imagino que no la tienes que procesar para que tu proyecto esté terminado) porque se trata de una cantidad de datos grande para un dispositivo pequeño (como el MCU de la placa Pro Micro) Lo más seguro es que necesites una cámara que incorpore un buffer (probablemente FIFO) que te permita leer de ahí las imágenes «sin prisas» en lugar de hacerlo desde la cámara.

      No he encontrado nada de código (ya listo) que te pueda servir, afortunadamente, estas cámaras suelen comunicar por el puerto serie y no son demasiado difíciles de manejar.

      No puedo ver el enlace que me dices 🙁 así que no sé a lo que te refieres.

      ¡Ánimo con tu bachillerato e intenta también pasártelo bien! Tenéis un centro muy interesante 😉

      ¡Te sigo esperando por polaridad.es!

  16. Eñaut

    De acuerdo, problema solucionado! Ahora, tengo que usar el sensor BMP180 para calcular la presión atmosférica, temperatura y altura, pero me piden utilizar una formula específica para calcular la altura. Para ello he buscado información en internet pero no encuentro ningun «sketch» en el que apliquen dicha fórmula para calcular la altura; entonces, la fórmula estará en la librería que utilizan? Si sabes donde puedo encontrar esa fórmula aplicada a un «sketch» te agradecería me lo comunicaras. Un saludo!

    Gracias

  17. Pedro Rubio

    Buenas!

    ¿habría alguna manera de que el programa guarde varios ficheros .txt?

    Gracias de antemano. Un Saludo

    • Víctor Ventura

      Hola, Pedro.

      ¿Varios ficheros a la vez? La respuesta corta es no. La respuesta larga empieza por sí, pero tiene tantos detalles que es mejor resumir que no se puede o no merece la pena, especialmente usando un MCU pequeño.

      Supongo que no te refieres a varios ficheros de manera secuencial (primero uno, luego otro… En tal caso, la respuesta sería sí y lo único que hay que hacer es abrirlos, almacenar la información cerrarlos y proceder con el siguiente de la misma forma.

      Para resolver con un rodeo lo de grabar varios documentos a la vez puedes establecer tu propio protocolo con en contenido (por ejemplo una línea de texto para cada uno de los documentos) y luego posprocesarlo en otro sistema (en un servidor, PC… depende de lo que vayas a hacer con los ficheros)

      Saludos y gracias por participar en polaridad.es

  18. jose luis

    hola amigo victor gracias por el post ..amigo victor pot favor necesito tu ayuda estoy empezando en esto de arduino y quiero hacer una maquinita que imprima en un lcd un usuario una contraseña guardados en una sd seria osea tendrai una lista de ejeplo 1000 usuarios con sus respectivas contraeñas ejemplo user :juan pass:122344 cada vez que ingrese una modena en un monedero amigo regalame un ejemplo por g¿favor gracias te lo agradezco de corazon

  19. salvador

    Buenos dias, estoy intentando sacar datos de una SD, consigo hacer un serial.print del fichero pero intento convertir este fichero en una variable para poder trabajar con ella pero no lo consigo. ¿Me puedes orientar sobre la forma de hacerlo?.
    Gracias

    • Víctor Ventura

      Hola, Salvador.

      No entiendo tu pregunta ¿Te refieres a tomar los valores del fichero para la variable? ¿Cómo se leerían a lo largo del tiempo?

      Si nos das más información, a lo mejor algún lector o yo mismo podemos ayudarte.

      Saludos.

  20. Adri

    Hola buenas, tengo un rfid un rtc y lector sd y quiero guardar el id de cada tarjeta con la hora y fecha en una sd, sabrias como poderlo almacenar? Estoy teniendo algunos problemas.
    Gracias

  21. Leyre

    Hola!
    estoy intentando hacer un proyecto en el que comunico el arduino con 9 sensores mediante CAN Open, e intento guardar los mensajes que estos sensores envían. La velocidad de comunicación es de 250kbps, y cada 50 ms los sensores envían sus datos.
    No consigo guardar todos los mensajes, creo que por que arduino no es capaz de guardar todos los mensajes en la SD tan rapidamente.
    ¿Se te ocurre alguna otra manera de hacerlo?

    #include
    #include
    #include

    long unsigned int rxId;
    unsigned char len = 0;
    unsigned char rxBuf[8];
    char msgString[128];
    volatile int contador=0;
    int guardar=0;
    #define CAN0_INT 18 //PIN INT MCP2515
    #define TarjetaSD 7 //PIN de la tarjeta SD
    MCP_CAN CAN0(4); // Set CS to pin 4
    File Archivo; //Genero el archivo donde se guardan los datos capturados

    void setup()
    {
    Serial.begin(250000);

    // Initialize MCP2515 running at 16MHz with a baudrate of 250kb/s and the masks and filters disabled.
    if(CAN0.begin(MCP_ANY, CAN_250KBPS, MCP_16MHZ) == CAN_OK)
    CAN0.setMode(MCP_NORMAL); // Set operation mode to normal so the MCP2515 sends acks to received data.

    pinMode(CAN0_INT, INPUT); // Configuring pin for /INT input
    pinMode(TarjetaSD, OUTPUT);

    attachInterrupt(digitalPinToInterrupt(CAN0_INT),Interrupcion,FALLING);//Si detecta flanco de bajada en la señal del pin CAN0_INT llama a la interrupcion.
    if (!SD.begin(TarjetaSD))
    {
    Serial.println(«Se ha producido un fallo al iniciar la tarjeta»);
    return;
    }
    Serial.println(«Se ha iniciado la comunicación correctamente»);
    Archivo = SD.open(«Captura.txt», FILE_WRITE);

    }

    void loop()
    {
    int a=5;
    //Archivo.close();
    }

    void Interrupcion()
    {
    CAN0.readMsgBuf(&rxId, &len, rxBuf); // Read data: len = data length, buf = data byte(s)
    Archivo = SD.open(«Captura.txt», FILE_WRITE);
    Archivo.print(«COB-ID»);
    Archivo.print(rxId);
    Archivo.print(rxBuf[0],HEX);
    Archivo.print(» «);
    Archivo.print(rxBuf[1],HEX);
    Archivo.print(» «);
    Archivo.print(rxBuf[2],HEX);
    Archivo.print(» «);
    Archivo.print(rxBuf[3], HEX);
    Archivo.print(» «);
    Archivo.print(rxBuf[4], HEX);
    Archivo.print(» «);
    Archivo.print(rxBuf[5], HEX);
    Archivo.print(» «);
    Archivo.print(rxBuf[6], HEX);
    Archivo.print(» «);
    Archivo.println(rxBuf[7], HEX);*/
    Archivo.close();
    //Limpio las variables
    for(int i=0;i<=7;i++)
    {rxBuf[i]=0;}
    }

  22. Andrès

    Buenas Colegas!

    Estoy intentando almacenar datos de una variable (pulso) que sera enviado
    a través de un modulo Wifi de arduino. La interrogativa es si se puede diseñar un sistema
    tipo SCADA ya que son diversas variables.

  23. Lautaro benitez

    Hola que tal, muy buen posteo. Mi pregunta es como debería hacer para que no me sobrescriba el mismo archivo utilizando la función SD.exists(filename), o sea que analice si existe un archivo con ese nombre que cree uno nuevo con el nombre variado así no me agrega mas datos al mismo archivo. o si no también como nombrar al archivo en base a una variable que pueda llegar a ser nombrar el archivo con la hora, temperatura, etc.
    Espero ser claro con mi cuestión. Muchas gracias. Lautaro

  24. LuIS

    Hola Victor
    Hace rato intento hacer funcionar Shierld Ethrnet, SD Card y Nrf24, los tres en el mismo proyecto
    Los tres utilizan Bus spi
    Me has ayudado mucho con SDCARD_ss_pin, no sabia de ello
    Me está faltando algo y no se que es……me podrás echar un cable….?
    MI nombre es Luis…..tresbien65@gmail.com
    Muchas gracias

  25. vicente

    Buenas tardes Victor.
    Ante todo darte las gracias por tus publicaciones. Tengo un pequeño problema. Con Arduino Uno necesito grabar en una micro sd una determinada variable todos los dias a una hora fija. A la vez que la grabo, tengo que recuperar el valor anterior y añadir a la primera la diferencia entre ambas. Pongamos el caso de un depósito de agua y un indicador de nivel. Diariamente recupero el último grabado, establezco la diferencia con el nivel actual y grabo nivelactual + diferencia. Consigo grabar, consigo recuperar, pero no consigo hacer la interpretación correcta. Me podrías echar un cable?
    Muchas gracias

  26. Danilo

    Estoy muy interesado en este desarrollo pero tengo problemas seria de gran ayuda tu opinion

    lo estoy desarrollando con Arduino uno pero lo unico que no hace es guarda en la SD sale (No guardado)

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *