Me gustaría usar este post para mencionar un par de cosas que creo que son muy útiles y que he ido descubriendo como suele ser habitual a base de horas y quebraderos de cabeza, junto con lecturas infinitas de foros, etc...
Esto va dirigido a los menos avanzados (como yo) que poco a poco nos ponemos con proyectos mas grandes y mas complejos.
Cuando realizamos un proyecto pequeño nos olvidamos de ciertas limitaciones que tienen estos pequeños microcontroladores, nos olvidamos que no son ordenadores con grandes capacidades de memoria o calculo. Conforme ampliaba un proyecto que empece cuando todavía encender un led era motivo de sonrisa de satisfacción, empece a tener problemas de estabilidad en mi programa. No entendía porque de forma aleatoria se reiniciaba mi Arduino, se bloqueaba, fallaban las lecturas etc.
Poco a poco he aprendido 3 o 4 puntos importantes que me gustaría mencionar aquí para todos aquellos que se identifiquen con mi caso, seguro que a alguno le ahorra una infinidad de horas y de quebraderos de cabeza....que yo sufrí.
Vamos a utilizar como ejemplo el Arduino UNO ya que es el mas utilizado comúnmente, aunque esto es aplicable a otras placas.
Flash Memory 32 KB (ATmega328) of which 0.5 KB used by bootloader
SRAM 2 KB (ATmega328)
EEPROM 1 KB (ATmega328)
Nota: No voy a entrar a la explicación técnica de cada uno de estos puntos porque esta documentado en la red y yo no soy ningún experto y seguro que me dejo cosas.
Punto 1: Memoria SRAM
Cuando incluimos en nuestro programa lineas como las siguientes...
Serial.println(" ------------------------- Iniciando Arduino --------------------------");
Estamos ocupando memoria SRAM que resulta ser la mas escasa en nuestro pequeño microcontrolador. Si no controlamos el espacio libre llegaremos a machacar la memoria con datos unos encima de otros lo cual finalmente se traducirá en inestabilidad del programa y el reinicio del Arduino
Solución
Con un pequeño código podemos controlar la memoria SRAM disponible en cualquier momento. Yo suelo hacer que me muestre este valor al final del setup() y luego lo pongo el el loop() y compruebo que el valor no disminuye con el tiempo.
#include <MemoryFree.h>
Serial.print("freeMemory()="); Serial.println(freeMemory());
Crear la libreria con estos dos archivos. No los pongo como adjuntos porque al ser tan cortos creo que es mejor tener el código aquí por si se eliminan los adjuntos.
File: MemoryFree.cpp
extern unsigned int __bss_end;
extern unsigned int __heap_start;
extern void *__brkval;
#include "MemoryFree.h";
int freeMemory() {
int free_memory;
if((int)__brkval == 0)
free_memory = ((int)&free_memory) - ((int)&__bss_end);
else
free_memory = ((int)&free_memory) - ((int)__brkval);
return free_memory;
}
File: MemoryFree.h
// memoryFree header
#ifndef MEMORY_FREE_H
#define MEMORY_FREE_H
#ifdef __cplusplus
extern "C" {
#endif
int freeMemory();
#ifdef __cplusplus
}
#endif
#endif
Se aconseja disponer al menos de 200 bytes de memoria SRAM libre durante la ejecución del programa para evitar problemas.
¿Como liberar espacio?
Para utilizar la Memoria Flash en lugar de la SRAM que es mucho mas escasa, podemos utilizar PROGMEM, esta todo descrito aquí:
http://arduino.cc/es/Reference/PROGMEM
Punto 2: Flash Memory.
En el caso de sobrepasar la memoria flash para almacenar el programa nos sera imposible subirlo a la placa, al intentarlo obtendremos un error.
Binary sketch size: 27242 bytes (of a 32256 byte maximum)
El problema es que en el compilador nos indica que tenemos kB totales para nuestro programa. No obstante hay un fallo en el IDE por el cual obtendremos un error que nos impedirá subir nuestro programa al Arduino con programas de tamaño ligeramente menor a ese valor, lo cual puede confundirnos respecto al origen del problema.
El tamaño total que puede tener nuestro programa es de
28672 bytes
sobrepasado este valor, no podremos subir el programa y el error que nos aparece no da mucha idea del motivo por el cual esta fallando. Así que recordarlo !
**Punto 3: Reinicios del Arduino debido a perdida de internet**[/size][/u]
Usando el Ethernet Shield Oficial.
En ocasiones debido a un problema de conexión a internet cuando usamos el Ethernet Shield se puede ocasionar reinicios del Arduino. Añadiendo unas lineas podemos limitar el tiempo de espera que el Arduino intentara establecer la conexión y si no lo consigue seguirá con el programa.
Para ello añadiremos la librería.
[/u] [u] #include <utility/w5100.h> // Advance Ethernet functions[/u] [u]
En el setup() de nuestro programa añadiremos estas dos lineas
[/u] [u] W5100.setRetransmissionTime(0x07D0); //setRetransmissionTime sets the Wiznet's timeout period, where each unit is 100us, so 0x07D0 (decimal 2000) means 200ms. W5100.setRetransmissionCount(3); //setRetransmissionCount sets the Wiznet's retry count.[/u] [u]
De esta forma cuando hagamos...
[/u] [u]if (client.connect()) {[/u] [u]
evitaremos que se quede colgado si la conexión no es exitosa.
Punto 4: Utilizar Watchdog.
Esta es una función muy útil para evitar que nuestro Arduino se quede en un bucle infinito o bloqueado en alguna parte del código. No voy a entrar en describirlo ya que esta muy documentado en la red pero si me parece importante mencionar que si disponemos de un Arduino duemilanove tendremos que actualizar el bootloader ya que el que viene de serie tiene un fallo que en esencia hara que cuando se ejecute el watchdog, se establezca un valor de reinicio de muy bajo tiempo por lo que el Arduino se reiniciara constantemente.
Para solucionarlo si nos pasa esto no nos queda otra que crear un programa "vació" con un setup() y loop() y probar y probar a subirlo al arduino hasta que entre.
Al margen de esto, el Watchdog se asegurara que no tengas que ir y manualmente reiniciar el Arduino en caso de fallo eventual. Muy útil cuando el Arduino se encuentra trabajando en una localización de difícil acceso o desatendido.
Punto 5: Tipos de Variables
Es muy importante cuando declaremos variables y cuando metamos datos en ellas que recordemos la capacidad de cada variable y el tipo. Esto también nos sera útil para ahorrar SRAM cuando sea posible, declarando variables de tamaño acorde al dato que ira dentro.
Aquí podéis ver que valores engloban cada variable y su tamaño.
[u]http://sites.google.com/site/mechatronicsguy/arduinocheatsheet/Arduino%20cheet%20sheet%20v02bsmall.png[/u]
> Datatype RAM usage
> void keyword N/A
> boolean 1 byte
> char 1 byte
> unsigned char 1 byte
> int 2 byte
> unsigned int 2 byte
> word 2 byte
> long 4 byte
> unsigned long 4 byte
> float 4 byte
> double 4 byte
> string 1 byte + x
> array 1 byte + x
> enum N/A
> struct N/A
> pointer N/A
Espero que esto le sea de ayuda a alguien ya que sin duda a mi me habria ahorrado muchisimas horas de "que esta pasando!!" al no entender porque mi Arduino no se comportaba como yo esperaba.
Por favor, cualquier error o información adicional que penseis que puede ser util hacermelo saber y podemos ampliar todo lo aquí expuesto.
En cuanto lo revise una vez mas lo pasare a ingles por cubrir mas audiencia
Un saludo,
Sergegsx