Go Down

Topic: RETO AL CÓDIGO (Read 688 times) previous topic - next topic

TonyDiana

Nov 12, 2020, 03:42 am Last Edit: Nov 12, 2020, 06:36 pm by TonyDiana
Para sustentar una pregunta que voy a hacer en breve en el foro, se me ocurrió primero este reto.

El reto es .....

¿Por qué no se apaga el led?

Code: [Select]
// --- punteros a funciones (https://forum.arduino.cc/index.php?topic=84682.0)

#include <Arduino.h>


// --- Yo soy una función que enciendo el led del Arduino
void encenderLed() { digitalWrite(13, HIGH); }

// --- Yo soy una función que apago el led del Arduino
void apagarLed() { digitalWrite(13, LOW); }

// --- Yo soy una función que imprimo hola por el serial
void decirHola() { Serial.println("HOLA COCACOLA"); }

// --- Yo soy una función que imprimo presto por el serial
void decirPresto() { Serial.println("PRESTO PICCOLO BAMBINO"); }

// --- Yo soy una función que hago tonterías
void tonteria() { Serial.println("--  ESTOY HACIENDO TONTERIAS --"); }


// --- YO EJECUTO LO QUE ME ECHEN ENCIMA
void ejecutador( void(*queHago)() ){ (*queHago)(); }

// --- byte, que la memoria está muy cara
byte veces=0;

// --- Un puntero ABSTRACTO A UNA FUNCION, NI IDEA DE CUAL, Global
void (* noSeLoQueSoy_GLOBAL)();




// --- Preparemos el escenario
void setup() {
   pinMode(13, OUTPUT);
   Serial.begin(9600);

   // --- Si, ya sé que es una tontería
   veces = 0;
}


// --- ¡¡ VAMOS A VER QUE PASA !!

void loop() {

   // --- Vamos a contar las veces que damos vueltas
   veces ++;

   Serial.println();Serial.println();Serial.println();
   Serial.println( "HOLA ARDUINERO, soy el ciclo " + String(veces) );


   // --- Un puntero ABSTRACTO A UNA FUNCION, NI IDEA DE CUAL, local
   void (* noSeLoQueSoy_LOCAL)();

   /* --- Aquí ocurren un montón de cosas complicadas que no las entiende ni el
          que las programó, pero que funcionan
    */

   if ( veces == 1) {
      noSeLoQueSoy_GLOBAL = decirHola;
      noSeLoQueSoy_LOCAL  = encenderLed;
   }

   /* --- Aquí ocurren un montón de cosas que pueden modificar el valor de veces
          no importa por qué, pero supongamos que ocurre, o incluso cambiar el
          puntero
    */

   if ( veces == 2) {
      noSeLoQueSoy_GLOBAL = decirPresto;
      noSeLoQueSoy_LOCAL  = apagarLed;
   }

   /* --- Aquí ocurren otro montón de cosas que pueden modificar el valor de
          veces o vete tu a saber
    */

   if ( veces == 3) {
      noSeLoQueSoy_GLOBAL = tonteria;
      noSeLoQueSoy_LOCAL  = encenderLed;
   }

   /* --- Más cosas raras
    */

   if ( veces == 4) {
      noSeLoQueSoy_GLOBAL = decirPresto;
      noSeLoQueSoy_LOCAL  = apagarLed;
   }

   /* --- Más cosas raras
    */

   if ( veces == 5) {
      noSeLoQueSoy_GLOBAL = decirHola;
      noSeLoQueSoy_LOCAL  = encenderLed;
   }

   /* --- Más cosas Más raras
    */

   if ( veces == 6) {
      noSeLoQueSoy_GLOBAL = decirPresto;
      noSeLoQueSoy_LOCAL  = apagarLed;
   }

   /* --- MUCHAS Más cosas Más raras
    */

   if ( veces == 7) {
      noSeLoQueSoy_GLOBAL = tonteria;
   }


   /* --- Por cierto ¿Piensas que cuando veces > 7 no pasará nada? JEJEJEJE
    */



   /* --- Pedazo de código más largo que el quijote
    */


   /* --- Y ahora se sabe qué se tendría que hacer de ese montón de cosas
          posibles. ¿Miles de if endif?
    */

   // --- YO EJECUTO LO QUE ME ECHEN ENCIMA
   ejecutador( noSeLoQueSoy_GLOBAL );
   ejecutador( noSeLoQueSoy_LOCAL );


   // --- Aquí pongo un delay de esos que tanto les gusta a la comunidad Arduino
   delay(3000);


   // --- PREMIO SI AVERIGUAS POR QUÉ DESPUÉS DEL CICLO 7 NO SE APAGA EL LED
}



TonyDiana

Les insto a @surbyte o a @gatul a que nos expliquen por qué, yo creo que es porque se destruye el puntero, pero ¿Por qué cambia el estado del led?

gatul

Eeeeeehhhhh...
Perá, perá, no me apuré...

surbyte

#3
Nov 12, 2020, 09:32 pm Last Edit: Nov 12, 2020, 10:48 pm by surbyte
Bueno, el ejercicio me ha hecho trabajar y debo confesar que la resolucion no me satisface del todo pero la expondré como si estuviera en un exámen y no tengo mas ideas.

Al ser un puntero local parece ser que la primer definición queda como x defecto.

En mis pruebas alteré que ponía en el primer condicional

Code: [Select]
if ( veces == 1) {
      noSeLoQueSoy_GLOBAL = decirHola;
      noSeLoQueSoy_LOCAL  = apagarLed;
   }


Si pones esto el valor que permanece luego del 7mo if es apagarLed, lo que prueba que esta primer asignación tiene cierto peso en el compilador y en como permanece el puntero asignado cuando no le digo a donde apuntar.

Lo detecté viendo la dirección a la que el puntero local apuntaba y descubrí que siempre arranca con la primer posición.

EDITO: solo corregí errores de redacción.

TonyDiana

No se me había ocurrido, muy interesante

surbyte

Por favor, Tony permite a otros dar su opinión. Lindo reto.

Creo tmb que este post podemos mantenerlo aqui o en donde tu lo pusiste, casi que me arrepiento de haberlo movido.
Es algo nuevo y aprecio tu idea para movilizar al foro!!
Gracias.

TonyDiana

No voy a comentar más para que todos jueguen, donde lo pongas me parece bien.

gatul

A mi me ha pasado por encima como una ola pero sigo sorprendido por ese código, desde la madrugada sigo así  :smiley-eek-blue:
Claramente no tengo explicación de por qué sucede lo que a todas luces no debería.
La explicación de @surbyte me ha dejado satisfecho por ahora.

TonyDiana

Es que una parte de la pregunta es ¿es sano declarar punteros locales a funciones globales? o mejor preguntado ¿punteros a funciones en diferentes ámbitos?, de entrada parece ya un problema serio

surbyte

Punteros locales yo uso todo el tiempo en cosas insignificantes como sprintf y su correspondiente buffer, pero punteros a funciones locales no he usado jamás.
Por eso me llamó la atención e investigué que pasaba y porque se daba la situación.
Estuve buen tiempo intentando mostrar la dirección hexa.
Esta fue mi código ayuda.

Code: [Select]
// --- punteros a funciones (https://forum.arduino.cc/index.php?topic=84682.0)

#include <Arduino.h>

// --- Yo soy una función que enciendo el led del Arduino
void encenderLed() { Serial.println("LED ON"); }

// --- Yo soy una función que apago el led del Arduino
void apagarLed() { Serial.println("LED OFF"); }

// --- Yo soy una función que imprimo hola por el serial
void decirHola() { Serial.println("HOLA COCACOLA"); }

// --- Yo soy una función que imprimo presto por el serial
void decirPresto() { Serial.println("PRESTO PICCOLO BAMBINO"); }

// --- Yo soy una función que hago tonterías
void tonteria() { Serial.println("--  ESTOY HACIENDO TONTERIAS --"); }


// --- YO EJECUTO LO QUE ME ECHEN ENCIMA
void ejecutador( void(*queHago)() ){ (*queHago)(); }

// --- byte, que la memoria está muy cara
byte veces=0;

// --- Un puntero ABSTRACTO A UNA FUNCION, NI IDEA DE CUAL, Global
void (* noSeLoQueSoy_GLOBAL)();

void imprimirPuntero(void(*queHago)() ){
  char buffer[30];
  sprintf(buffer, "%p\n", queHago);
  Serial.print(buffer);
}


// --- Preparemos el escenario
void setup() {
   pinMode(13, OUTPUT);
   Serial.begin(9600);

   // --- Si, ya sé que es una tontería
   veces = 0;
}


// --- ¡¡ VAMOS A VER QUE PASA !!

void loop() {
   // --- Vamos a contar las veces que damos vueltas
   veces ++;

   Serial.println();Serial.println();Serial.println();
   Serial.println( "HOLA ARDUINERO, soy el ciclo " + String(veces) );

   // --- Un puntero ABSTRACTO A UNA FUNCION, NI IDEA DE CUAL, local
   void (* noSeLoQueSoy_LOCAL)();

   /* --- Aquí ocurren un montón de cosas complicadas que no las entiende ni el
          que las programó, pero que funcionan
    */
   imprimirPuntero(noSeLoQueSoy_LOCAL);
   if ( veces == 1) {
      noSeLoQueSoy_GLOBAL = decirHola;
      noSeLoQueSoy_LOCAL  = apagarLed;
   }


   /* --- Aquí ocurren un montón de cosas que pueden modificar el valor de veces
          no importa por qué, pero supongamos que ocurre, o incluso cambiar el
          puntero
    */

   if ( veces == 2) {
      noSeLoQueSoy_GLOBAL = decirPresto;
      noSeLoQueSoy_LOCAL  = apagarLed;
   }
   /* --- Aquí ocurren otro montón de cosas que pueden modificar el valor de
          veces o vete tu a saber
    */

   if ( veces == 3) {
      noSeLoQueSoy_GLOBAL = tonteria;
      noSeLoQueSoy_LOCAL  = encenderLed;
   }
   imprimirPuntero(noSeLoQueSoy_LOCAL);
   /* --- Más cosas raras
    */

   if ( veces == 4) {
      noSeLoQueSoy_GLOBAL = decirPresto;
      noSeLoQueSoy_LOCAL  = apagarLed;
   }
   /* --- Más cosas raras
    */

   if ( veces == 5) {
      noSeLoQueSoy_GLOBAL = decirHola;
      noSeLoQueSoy_LOCAL  = encenderLed;
   }
   /* --- Más cosas Más raras
    */

   if ( veces == 6) {
      noSeLoQueSoy_GLOBAL = decirPresto;
      noSeLoQueSoy_LOCAL  = apagarLed;
   }
    /* --- MUCHAS Más cosas Más raras
    */

   if ( veces == 7) {
      noSeLoQueSoy_GLOBAL = tonteria;
   }

   /* --- Por cierto ¿Piensas que cuando veces > 7 no pasará nada? JEJEJEJE
    */



   /* --- Pedazo de código más largo que el quijote
    */


   /* --- Y ahora se sabe qué se tendría que hacer de ese montón de cosas
          posibles. ¿Miles de if endif?
    */

   // --- YO EJECUTO LO QUE ME ECHEN ENCIMA
   ejecutador( noSeLoQueSoy_GLOBAL );
   ejecutador( noSeLoQueSoy_LOCAL );
   imprimirPuntero(noSeLoQueSoy_LOCAL);   
   
   // --- Aquí pongo un delay de esos que tanto les gusta a la comunidad Arduino
   delay(5000);


   // --- PREMIO SI AVERIGUAS POR QUÉ DESPUÉS DEL CICLO 7 NO SE APAGA EL LED
}


Igualmente creo que hay otra explicación.

TonyDiana

¡¡ ESTOY ASOMBRADO !!

He modificado el sketch

He creado una función global


Code: [Select]
// --- Yo no hago nada
void nadaDeNada() { Serial.println("YO NO HAGO NADA"); }


Y luego he modificado el ciclo 1


Code: [Select]
   if (veces == 1) {
      noSeLoQueSoy_LOCAL  = nadaDeNada;
      ejecutador( noSeLoQueSoy_LOCAL );
      noSeLoQueSoy_GLOBAL = decirHola;
      noSeLoQueSoy_LOCAL  = encenderLed;
   }


El resultado es que el LED no se apaga tampoco, así que empiezo a pensar que, cuando muere una función/puntero a un elemento Hardware, este regresa a su estado inicial o de reposo, que en el PIN 13 es encendido, lo cual tiene grandes implicaciones en el comportamiento del Arduino.
Empiezo a pensar que tener punteros locales a funciones que interactúan con el Hardware, es mala idea.

victorjam

#11
Nov 13, 2020, 03:00 pm Last Edit: Nov 13, 2020, 03:03 pm by victorjam
Pues más te va a sorprender esto:


Code: [Select]

// --- punteros a funciones (https://forum.arduino.cc/index.php?topic=84682.0)

#include <Arduino.h>


// --- Yo soy una función que enciendo el led del Arduino
void encenderLed() { digitalWrite(13, HIGH); }

// --- Yo soy una función que apago el led del Arduino
void apagarLed() { digitalWrite(13, LOW); }

// --- Yo soy una función que imprimo hola por el serial
void decirHola() { Serial.println("HOLA COCACOLA"); }

// --- Yo soy una función que imprimo presto por el serial
void decirPresto() { Serial.println("PRESTO PICCOLO BAMBINO"); }

// --- Yo soy una función que hago tonterías
void tonteria() { Serial.println("--  ESTOY HACIENDO TONTERIAS --"); }


// --- YO EJECUTO LO QUE ME ECHEN ENCIMA
void ejecutador( void(*queHago)() ){ (*queHago)(); }

// --- byte, que la memoria está muy cara
byte veces=0;

// --- Un puntero ABSTRACTO A UNA FUNCION, NI IDEA DE CUAL, Global
void (* noSeLoQueSoy_GLOBAL)();




// --- Preparemos el escenario
void setup() {
   pinMode(13, OUTPUT);
   Serial.begin(9600);
   Serial.println("Soy encenderLed y mi direccion es: " + String((uint32_t)encenderLed));
   // --- Si, ya sé que es una tontería
   veces = 0;
}


// --- ¡¡ VAMOS A VER QUE PASA !!

void loop() {

   // --- Vamos a contar las veces que damos vueltas
   veces ++;

   Serial.println();Serial.println();Serial.println();
   Serial.println( "HOLA ARDUINERO, soy el ciclo " + String(veces) );


   // --- Un puntero ABSTRACTO A UNA FUNCION, NI IDEA DE CUAL, local
   void (* noSeLoQueSoy_LOCAL)();

   // --- Y aquí solo un poco de información:
   Serial.println("Hola colega mi direccion es:" + String((uint32_t)&noSeLoQueSoy_LOCAL));
   Serial.println("y apunto a:" +String((uint32_t)*noSeLoQueSoy_LOCAL));
   

   /* --- Aquí ocurren un montón de cosas complicadas que no las entiende ni el
          que las programó, pero que funcionan
    */

   if ( veces == 1) {
      noSeLoQueSoy_GLOBAL = decirHola;
      noSeLoQueSoy_LOCAL  = encenderLed;
   }

   /* --- Aquí ocurren un montón de cosas que pueden modificar el valor de veces
          no importa por qué, pero supongamos que ocurre, o incluso cambiar el
          puntero
    */

   if ( veces == 2) {
      noSeLoQueSoy_GLOBAL = decirPresto;
      noSeLoQueSoy_LOCAL  = apagarLed;
   }

   /* --- Aquí ocurren otro montón de cosas que pueden modificar el valor de
          veces o vete tu a saber
    */

   if ( veces == 3) {
      noSeLoQueSoy_GLOBAL = tonteria;
      noSeLoQueSoy_LOCAL  = encenderLed;
   }

   /* --- Más cosas raras
    */

   if ( veces == 4) {
      noSeLoQueSoy_GLOBAL = decirPresto;
      noSeLoQueSoy_LOCAL  = apagarLed;
   }

   /* --- Más cosas raras
    */

   if ( veces == 5) {
      noSeLoQueSoy_GLOBAL = decirHola;
      noSeLoQueSoy_LOCAL  = encenderLed;
   }

   /* --- Más cosas Más raras
    */

   if ( veces == 6) {
      noSeLoQueSoy_GLOBAL = decirPresto;
      noSeLoQueSoy_LOCAL  = apagarLed;
   }

   /* --- MUCHAS Más cosas Más raras
    */

   if ( veces == 7) {
      noSeLoQueSoy_GLOBAL = tonteria;
   }


   /* --- Por cierto ¿Piensas que cuando veces > 7 no pasará nada? JEJEJEJE
    */



   /* --- Pedazo de código más largo que el quijote
    */


   /* --- Y ahora se sabe qué se tendría que hacer de ese montón de cosas
          posibles. ¿Miles de if endif?
    */

   // --- YO EJECUTO LO QUE ME ECHEN ENCIMA
   ejecutador( noSeLoQueSoy_GLOBAL );
   ejecutador( noSeLoQueSoy_LOCAL );


   // --- Aquí pongo un delay de esos que tanto les gusta a la comunidad Arduino
   delay(3000);


   // --- PREMIO SI AVERIGUAS POR QUÉ DESPUÉS DEL CICLO 7 NO SE APAGA EL LED
}



Básicamente he añadido estas dos líneas, justo despues de crear la funcion noSeLoQueSoy_LOCAL:


Code: [Select]

// --- Y aquí solo un poco de información:
   Serial.println("Hola colega mi direccion es:" + String((uint32_t)&noSeLoQueSoy_LOCAL));
   Serial.println("y apunto a:" +String((uint32_t)*noSeLoQueSoy_LOCAL));



E increiblemente el led se apaga...

Con esas dos líneas muestro la dirección de la variable noSeLoQueSoy_LOCAL y a donde apunta. En el setup del sketch empecé a escribir las direcciones de cada función.

En teoria, un puntero es una dirección de memoria. Lo que apunta puede ser cualquier cosa, en este caso es la dirección de una función. Cuando el compilador crea una variable, asigna una posicion de memoria. Y comprobando las direcciones y viendo a donde apunta me he quedado flipando al ver el comportamiento.

Desde que hacer mal un puntero significa reiniciar un ordenador tengo la mala costumbre de que cuando creo uno lo asigno a NULL. Y luego si o si, antes de usarlo compruebo que este no es NULL. En este código sería:




Code: [Select]

void ejecutador( void(*queHago)() ){
  if ( quehago!=NULL) quehago();
}

void loop() {
  ...
  void (* noSeLoQueSoy_LOCAL)()=NULL;
}


Con lo cual el problema también desaparece.

Ahora bien, sigo sin entender muy bien lo que está ocurriendo con tu código original. Pensaba
que al crearse la variable en el mismo lugar que ocupaba en el loop anterior y al no modificar
el valor al que apunta, entonces debería ejecutar la última que fue asignada
(veces==6, apagarLed), pero entonces va y enciende el led...



TonyDiana

Gracias @victorjam, creo que le has dado en el clavo, creo que los punteros a funciones locales que van a ser destruidos hay que redireccionarlos a NULL, a fin de cuentas es un C++ y no hay recolector de basura como en C#,así que, sobre todo en punteros, hay que pensar muy bien que ocurren con ellos cuando cambiamos el ámbito o cuando mueren, gracias

PeterKantTropus

Code: [Select]
void static (* noSeLoQueSoy_LOCAL)();
Funciona bien, pero de hecho cuando  vi el código dije: "El error es que no se  declaro volatil" .
//-----------------------******------------------------
if (Codigo_con_delay==True) {
Proyecto=Fracaso;
 } 
//-----------------------******-----------------------

TonyDiana

¡¡ ERES UN GENIO !!

Ahora os dejo el segundo reto

https://forum.arduino.cc/index.php?topic=713589.0

Porque a mí me ha superado

Go Up