Optimización de Memoria de nuestro código de Arduino

A veces en proyectos grandes, hay que tener muy en cuenta el tamaño de los datos y el tamaño de nuestro programa ya que arduino, como cualquier otro programa para sistemas empotrados, tiene un hardware limitado y por lo tanto hay que tener en cuenta varios puntos en cuenta. Lo primero que hay que saber, es diferenciar el tipo de memoria que hay disponible en Arduino:

  • Flash: Esta memoria almacena el código del programa.
  • RAM: Esta memoria almacena los datos del programa y es volátil cuando se apaga arduino se pierden los datos.
  • EEPROM: Esta memoria almacena datos que son persistentes. Esta memoria puede ser utilizada para guardar configuración o cualquier otro dato que podamos utilizar si se apaga y enciende Arduino.

Con estos datos, podemos ver en primer lugar, que tipo de Arduino puede ser más correcto para nuestro proyecto. Aquí os dejamos una tabla de comparación con algunas de las placas más famosas de Arduino.

UNOMEGA 2560MiniPRO Mini
SONY DSC11061-01b11303-01a51eeb8f9ce395f0778000000
32KB Flash256KB Flash32KB Flash16KB Flash
2KB RAM8KB RAM2KB RAM1KB RAM
1KB EEPROM4KB EEPROM1KB EEPROM512 B EEPROM

Una vez hemos visto las distintas placas que podemos obtener, vamos a ver las distintas técnicas que podemos utilizar para mejorar la memoria y poder optimizar el código de nuestros proyectos al máximo.

  1. Utilizar tipos de datos correctos
  2. Optimizar las cadenas de caracteres
  3. Optimizar nuestro código de programa
  4. Optimizar las variables del programa pasándolas a la PROGMEM.
  5. Optimizar los datos guardando información en la EEPROM.

Estas son las técnicas que vamos a estudiar en este artículo. Ahora las analizaremos una por una para mostrar como utilizarlas.

1. Utilizar tipos de datos correctos.

Obviamente lo más sencillo y básico que podemos hacer es utilizar correctamente los tipos de dato que utilizaremos en nuestras variables. Ya que en función de lo que necesitemos, podemos utilizar uno u otro. Seguidamente mostramos una tabla con los tipos de datos básicos con Arduino:

 TipoTamañoRango
byteentero1 byte0-255
short/intentero2byte-32,767 a 32768
longentero4byte2,147,483,647 a -2,147,483,648
floatreal4byte3.4028235E+38 a -3.4028235E+38.

Con los datos de la tabla debemos elegir los tipos de datos correctos para nuestros proyectos.

2. Optimizar Cadenas de Caracteres

Otro de los problemas que más memoria puede gastar, es las cadenas de caracteres con respecto a los mensajes que mostraremos. Esto puede ser un problema de gasto de memoria RAM. Por ello, se puede utilizar una función llamada F la cual hace que las cadenas de caracteres, queden almacenadas en la memoria de programa y no en la memoria RAM.

  Serial.print("Hola Mundo");//Gasto de memoria RAM.
  Serial.print(F("Hola Mundo"));//Gasto de Memoria Flash.

Por lo tanto para no malgastar RAM, interesa utilizar la función F.

3. Optimizar el código de nuestro programa

Otro tema que tenemos que tener en cuenta, es la optimización de nuestro código para Arduino; hay que tener en cuenta que necesitaremos gastar el mínimo de tamaño de nuestro programa ya que como hemos visto anteriormente el tamaño de programa esta limitad. Os dejamos unos consejos para optimizar este tamaño:

1. Utilizar Constantes:

Para variables que no cambien tamaño, es mejor utilizar constantes y así no gastar memoria ni de programa ni RAM:

int led = 13;//Utilizar una variable para definir un PIN gasta RAM y Memoria de Programa
#define LED 13 // SI utilizamos una constante no se gastará RAM y se gastará mucho menos espacio de programa.

2. Utilizar Macros

A la hora de crear funciones, podemos utilizar Macros para operaciones mecánicas. De esta manera ahorraremos en primer lugar, RAM, Memoria de Programa e incluso evitaremos el desbordamiento de PILA ya que no se utiliza la pila de programa a la hora de utilizar una macro.

   void mostrarenpantalla(String cadena){ lcd.print(cadena); } //esta función gasta RAM y Memoria de Programa. Además de que utiliza la pila de llamadas.
   #define mostrarenpantalla(cadena){ lcd.print(cadena); } // no gasta RAM pero si memoria de Programa y además, no utiliza pila de llamadas.

3. Revisar nuestro código

Por último, tenemos que tener en cuenta  que debemos utilizar poco código de manera eficiente para poder gastar menos memoria de programa. Uno de las técnicas que se puede utilizar, es usar el bucle ‘for’ de manera inversa:

   for(byte i=0;i < 10;i++) // este es un bucle for normal
    for(byte i=10;i > = 0;i--)// Este bucle for se recorre de forma inversa para optimizar el acceso a memoria.

Otro método, es utilizar los operadores de asignación aritmetica.

c = c+1; // esto no es eficiente
c++; //Esto es más eficiente

4. Optimizar las variables del programa pasándolas a la PROGMEM.

Para ahorrar RAM, podemos utilizar la palabra PROGMEM para poder definir las variables dentro de la memoria de programa y así ahorrar memoria RAM. Aquí definiremos como utilizar esta palabra. Esta palabra reservada, se utiliza para definir arrays dentro de la memoria de programa.

Además, existen unos tipos de datos predefinidos para poder definir variables de tipos básicos en la memoria de Programa.

TipoDescripción
prog_charCaracter de 1 byte
prog_ucharCaracter sin signo de 1 byte
prog_int16_tEntero de 2 bytes
prog_uint16_tEntero sin signo de 2 bytes
prog_int32_tEntero largo de 4 bytes
prog_uint32_tEntero largo sin signo de 4 bytes

utilizando estos datos, podemos utilizar parte de la memoria de programa para nuestras variables. Recordamos que esta memoria también es finita y que tampoco podemos utilizarla para todo.

5. Guardar las variables en la EEPROM

Otro aspecto para guardar nuestros datos de forma persistente, es utilizar la EEPROM la cual nos permite guardar datos en la memoria de manera de que si se apaga nuestra placa de arduino, no se pierdan estos datos. Esto es interesante para poder guardar variables de configuración o cualquier otro tipo de dato. Os dejamos un ejemplo de código.

#include < EEPROM.h > //incluimos la libreria para guardar o leer de la EEPROM
int i=0;
void setup(){
  Serial.begin(9600);
}
void loop(){
 
 for(byte i=10;i > 0;i--){
     EEPROM.write(i,i); //Escritura en EEPROM.
   }
 
  for(byte i=10;i > 0;i--){
    int dato=EEPROM.read(i);
    Serial.println(i);
  }
}

Con este último ejemplo, ya hemos visto los mecanismos que tenemos para optimizar nuestro código en Arduino y mejorar el uso tanto de RAM como de memoria de programa. Más adelante, hablaremos de como aumentar la memoria por medio de una tarjeta SD o de memoria RAM adicional.

7 Comments on "Optimización de Memoria de nuestro código de Arduino"

  1. Excelente información, me ayudó demasiado, mejoré increíblemente el espacio en la memoria. Lo que no entendí muy bien es el uso de la palabra PROGMEM. Muchas gracias

  2. Pues sigo con la misma duda de Juan Carlos.
    Porqué recorrer un bucle a la inversa es mejor?, no encuentro la respuesta en tu contestación.

    Por cierto, buen artículo, muy interesante.

  3. Excelente!
    Gracias a estos consejos, conseguí, de estar en situación de inestabilidad (<75% de memoria usada) hasta un 64% de menoria usada.

    Muy recomendable =)

  4. Maximiliano Duarte | Febrero 27, 2015 en 8:19 pm | Responder

    Me ayudó mucho a mejorar mi forma de programar, olvidada de C++ cuando eran cientos de define.
    Y muy util las macros cuando usamos display o salidas por serial para debuger.

  5. No me quedo claro porque recorrer bucles for a la inversa, es mejor.

    Un saludo.

    • Es más eficiente ya que el procesador del arduino, accede a la memoria pero no obtiene por ejemplo cada dato de la memoria RAM de uno en uno. Si no que lo hace en bloques por lo que obtiene los bloques adyacentes. Muchas veces El propio Compilador optimiza este acceso. Por eso al obtener el bloque entero, el acceso es mucho más rápido ya que siempre el acceso a la RAM es mucho más lento que usar por ejemplo una pequeña Cache que trae el microcontrolador.

Deja un comentario.

Tu dirección de correo no será publicada.


*


*