Ámbitos con el Pre compilador, 4ª y última parte, DEBUG con estilo

Todo cometemos errores cuando realizamos un programa, pensar que no los vamos a cometer es el primer error que cometemos, por eso necesitamos un sistema de depuración de código, llamado DEBUG.

Como el IDE de Arduino no tiene un DEBUG, y para hacer bien debug con otra plataforma de desarrollo hay que utilizar hardware especializado, el cual no es que sea caro, es que es algo complejo y no se justifica si no te dedicas a esto de forma profesional, al final la mayoría lo que hacemos es usar el sufrido Serial.print

Imagina la situación: estás probando una función, un objeto o una librería; claro cuanto más complejo sea, más debug vas a tener que hacer, y al final estás metiendo y sacando código, quitarto y poniendo, porque dejarlo no es la mejor idea, ya que obliga a utilizar el puerto serial incluso cuando ya funcione, consume parte de la escasa memoria de tu Arduino y complica ver el flujo del programa. Al final la situación se parece a esto:

// --- Probando función */

float funcionQueFalla(float VALOR, int FACTOR) {
    Serial.print( "Recibo el valor " );
Serial.print( VALOR );
  Serial.print( " y el factor " );
        Serial.print( FACTOR );

    float aux = VALOR * FACTOR;
Serial.print( " y me ha dado " );
        Serial.print( aux );
Serial.println();
    return aux;
}

Y además, lo haces así, súper desordenado porque estás probando la función y luego lo vas a quitar, que yo se que sí lo haces así, con lo cual, la función es casi invisible (qué y porqué mezclado) y se hace un lío.

Al final imaginemos que descubres que el problema era multiplicar un int por un float sin convertir, y acabas arreglando la función y la dejas así:

float funcionOperativa(float VALOR, int FACTOR) {
    float aux = VALOR * (float)FACTOR;
    return aux;
}

O llegas al colmo del refinamiento y la dejas así

float funcionOperativaRefinada(float VALOR, int FACTOR) {
    return ( VALOR * (float)FACTOR );
}

Ahora sigues con tu desarrollo y le pasas un factor con decimales, que claro, no va a funcionar (el int), y regresas a volver a llenar tu función de sufridos Serial.print, hasta que la arreglas

float factor(float VALOR, float FACTOR) { return ( VALOR * FACTOR ); }

Si además tienes Serial.print necesarios en tu aplicación que no son del debug, te cuesta un mundo encontrar qué tienes que quitar y qué no.

Vamos a mejorar esto. Para ello separaremos el cuándo, del qué, del dónde y del cómo, todo lo que nos sea posible.

Primero vamos a evitar que se nos mezclen los Serial.print de nuestro programa, los verdaderos, del debug. Para ello vamos a usar las macros del precompilador, y vamos a declarar lo siguiente:

// --- Macros para DEBUG
#ifndef DEBUGMACRO
#define DEBUGMACRO
    #define DEBUG_TEX(a) Serial.print(a);
    #define DEBUG_LIN(a) Serial.println(a);
#endif

Quiero que imagines que eso lo tienes dentro de un archivo, llamémosle macros.h, y que vas a hacer #include donde lo necesites.

Acábamos de separar el cómo, le hemos pedido al precompilador que nos diga cómo debe mostrar la información. Ahora escribiremos la función que estamos probando de esta manera:

float funcionQueFallaba(float VALOR, int FACTOR) {


    #ifdef __DEBUG__
        DEBUG_LIN( "DEBUG BONITO " );
        DEBUG_TEX( "Recibo el valor " );
        DEBUG_TEX( VALOR );
        DEBUG_TEX( " y el factor " );
        DEBUG_LIN( FACTOR );    // --- Para que salte de línea, no como antes
    #endif

    float aux = VALOR * FACTOR;

    #ifdef __DEBUG__
        DEBUG_TEX( " y me ha dado " );
        DEBUG_LIN( aux );
    #endif

    Serial.println("Imaginemos que este print sí hace falta");
    return aux;
}

Mira que bonito. No se confunde el debug con el resto de tu código, pero es que en la línea 88 (esta vez sí voy a añadir el .ino para la descarga) tengo un traductor condicional de precompilador.

#define __DEBUG__

Cuando tu función funcione (¿eso parece una redundancia verdad?), y hasta que acabes tu programa definitivamente, puedes tomar la línea y cambiarla a:

//#define __DEBUG__

Ahora es un comentario, y no va a actuar. Puedes dejar el debug para otro momento, ya lo quitarás al final, cuando acabes, es más, sólo tienes que buscar con el editor de textos la cadena DEBUG_ (con el subrayado) y no se te mezclarán con los Serial.print buenos de tu programa

void setup() {
     Serial.begin( 9600 );
    funcionQueFalla(1248.3f, 5);
    funcionQueFallaba(1248.3f, 5);
}
void loop() {}

El compilador me ha dicho que, con DEBUG definido, mi programa ocupa
El Sketch usa 3622 bytes,

Cuando lo convierto en comentario me dice:
El Sketch usa 3240 bytes

Como ves, esta práctica no consume más memoria cuando lo conviertes en comentario, y te deja las cosas preparadas hasta que acabes el programa, por si acaso, o incluso para el futuro, por si no recuerdas qué hacías o cómo lo hiciste, que es el ámbito de programación denominado

QUE_MEMORIA_DE_TEFLÓN_QUE_TENGO

Una cosa más. Si usas Visual Studio Core u otro editor más refinado que el IDE de Arduino, puedes cambiar la opacidad de las líneas no operativas, y entonces tu programa en pantalla se vé así:

Captura de pantalla de 2020-11-22 15-46-37.png

Captura de pantalla de 2020-11-22 15-46-37.png

debugFASSION.ino (5.43 KB)