La forma habitual de hacer debug en arduino usar la instrucción Serial.print() para mostrar en la consola de monitorización del IDE de arduino los datos.
Este sistema tiene varias pegas:
- Aumenta el tamaño del codigo y el espacio que ocupa el mismo
- Consume tiempo de ejecución
- Interfiere con el uso del puerto USB o de la comunicacion serie
- No aporta ninguna informacion para saber en que parte del codigo ocurre.
- No distingue entre mensajes de log, traza, debug, error…..
Una forma de resolver parte de estos problemas es usando el preprocesador de C.La idea es definir una serie de macros cuyo valor dependa de que se haya definido una variable del preprocesador. De tal forma que si la variable no esta definida la macro se reemplazada por nada asi evitamos que cuando no consuma espacio en memoria, que interfiera con el uso del puerto serie cuando no estamos depurando.
#ifdef DEBUG
#define DEBUGPRINT(X) Serial.print(X);
#else
#define DEBUGPRINT(X) // nothing
#endif
De tal forma que cuadno queremos depurar definimos la siguiente variable
#define DEBUG
Y todas los sitios dodne aparezca DEBUGPRINT(X) seran sustituidos por Serial.print(X); Pero cuando la quitamos todas las lineas son reemplazadas por nada y desaparecen del programa no ocupando ni esapcio ni tiempo de ejecución.
Hay que definir otro más, DEBUGPRINTLN(X) para el caso de que en lugar de quere un Serial.print(X) queramos usar un Serial.println(X)
Ademas vamos a permitir incluir alguna informacion de en que funcion, archivo y linea del codigo estmos.
#define DEBUGMSG(X) \
Serial.print("DEBUG: "); \
Serial.print(__PRETTY_FUNCTION__); \
Serial.print(' '); \
Serial.print(__FILE__); \
Serial.print(':'); \
Serial.print(__LINE__); \
Serial.print(' '); \
Serial.println(X);
Podemos definir varias macros según el los «niveles» de log mostrando solo los que nos interesen, en nuestro caso vamos a definir cinco:
DEBUG
TRACE
INFO
ERROR
TEST
Al final nos quedan quince macros, a las que se han añadido dos más ENTER y EXIT para indicar la entrada y salida de una función que resultan muy útiles para la traza del código.
DEBUG:
DEBUGPRINT(X) Serial.print(X);
DEBUGPRINTLN(X) Serial.println(X);
DEBUGMSG(X) Serial.println(«DEBUG function file.ino:line X»);
TRACE:
TRACEPRINTLN(X) Serial.println(X);
TRACEPRINT(X) Serial.print(X);
TRACEMSG(X) Serial.println(«TRACE function file.ino:line X»);
ENTER Serial.print(«TRACE: ENTER -> function»);
EXIT Serial.print(«TRACE: EXIT -> function»);
INFO:
INFOPRINTLN(X) Serial.println(X);
INFOPRINT(X) Serial.print(X);
INFOMSG(X) Serial.println(«INFO function file.ino:line X»);
ERROR:
ERRORPRINTLN(X) Serial.println(X);
ERRORPRINT(X) Serial.print(X);
ERRORMSG(X) Serial.println(«ERROR function file.ino:line X»);
TEST:
TESTPRINTLN(X) Serial.println(X);
TESTPRINT(X) Serial.print(X);
TESTMSG(X) Serial.println(«TEST function file.ino:line X»);
Todo estas macros y alguna funcionalidad más se puden encontrar en la libreria debugino.
En un ejemplo de su uso podemos ver como funciona. Hay que señalar la necesidad de inicializar la comunicación serie con Serial.begin(9600);. Para configurar que mensajes se muestran y cuales no basta con quitar el #define correspondiente y esos mensajes desaparecerán.
#define DEBUG
#define TRACE
#define INFO
#define ERROR
#define TEST
#include <Debug.h>
int c = 0;
void setup() {
Serial.begin(9600);
}
void loop() {
TRACEMSG("Start loop");
inc();
TEST(c < 30);
DEBUGPRINT("Value of C ")
DEBUGPRINTLN(c);
#ifdef ERROR
if(c > 40)
STOP
#endif
delay(500);
}
void inc(){
ENTER
c++;
EXIT
}
Este texto mejorado y ampliado forma parte de mi libro sobre como mejorar tus programas en Arduino. Puedes echarle un vistazo aquí.
También puedes ver el vídeo sobre este post en mi canal:
Pingback: Test de código en Arduino | Construyendo a Chispas