Arduino: ¿Dónde está main()?
La principal característica de las placas Arduino es la rapidez con la que se pueden obtener resultados.
Como ya comenté en un artículo anterior, su punto fuerte es la suave curva de aprendizaje: para informáticos, electrónicos o curiosos en general.
Existen varias formas de programar Arduino. Algunos de sus compiladores son visuales, pero el que más llama la atención es el que usa código C/C++, que precisamente no es visual.
Para describir la forma del código usaré como ejemplo el sketch (nombre que reciben los programas Arduino) Blink, que viene con el entorno de desarrollo.
/* Blink Turns on an LED on for one second, then off for one second, repeatedly. This example code is in the public domain.*/ // Pin 13 has an LED connected on most Arduino boards. // give it a name: int led = 13; // the setup routine runs once when you press reset: void setup() { // initialize the digital pin as an output. pinMode(led, OUTPUT); } // the loop routine runs over and over again forever: void loop() { digitalWrite(led, HIGH); // turn the LED on (HIGH is the voltage level) delay(1000); // wait for a second digitalWrite(led, LOW); // turn the LED off by making the voltage LOW delay(1000); // wait for a second }
La sintaxis anterior es C. Las primeras líneas arrancan con comentarios.
Luego viene una declaración de la variable “led”. Esta variable es global porque no está dentro de ningún procedimiento ni función.
Después aparece la función ”setup()”. Se ejecuta una sola vez. Cuando se conecta Arduino o compila el sketch. En ella se hace uso de la variable “led” global. Aunque no es el objetivo de este artículo detallar el código que hay en las funciones.
Tras esta nos encontramos con la función “loop()”. Se ejecutará continuamente, como su propio nombre puede hacernos pensar.
Y luego …, si habíamos dicho que es C/C++ ¡Dónde está “main()”!.
Cuando programamos para Arduino no hacemos un programa. Lo que escribimos es un fragmento de programa, que se unirá a otro fragmento y los dos formarán el programa completo.
Se me antoja, a bote pronto, que ese otro sketch en algún lugar tendrá una función “main()” que llamará una vez a “setup()” y que luego en un bucle infinito llamará repetidas veces a “loop()”.
Si en este sketch introducimos la declaración “void main(){};” el compilador se queja y dice que “main()” tiene que devolver un entero. Así pues Arduino espera un “int main(){…return 0};” por ejemplo.
Podemos ir a la raíz de la instalación de Arduino y buscar los ficheros que contengan “int main(“.
Encontraremos un “main.cpp” con este código:
#include int main(void) { init(); #if defined(USBCON) USBDevice.attach(); #endif setup(); for (;;) { loop(); if (serialEventRun) serialEventRun(); } return 0; }
Misterio resuelto. Existe un “main()” que devolvería “0” si alguna vez llegase al final. Primero ejecuta una función “init()” Luego hay un objeto “USBDevice” con un miembro “attach()”.
Ahora vienen las dos funciones conocidas “setup();” y dentro del bucle infinito “loop();”.
Me llama la atención que después de ejecutarse “loop()” se llama a otra función “serialEventRun()”.
Buscando los tres pies al gato, podríamos prescindir del código que hay en “setup();” y ponerlo dentro de “loop()”, con un “if” para que se ejecutase solo una vez. Aunque sería una pérdida de tiempo para nuestro Arduino. Y una bonita forma de liar nuestro código. Dejémoslo estar, pues.
Con esta estructura de ejecución, que nos propone Arduino, se plantean interesantes patrones de diseño.A la hora de poner código dentro de “loop()” podemos optar porque sea “bloqueante”: por ejemplo, poner un bucle que quede a la espera de una señal digital de entrada. O “no bloqueante”: por ejemplo, colocando un contador (o diferenciador de tiempo) que en los n ciclos de “loop()” siguientes esté expectante de esa señal digital, sin impedir que otro código continue su flujo.
Un tema interesante, el de los patrones de diseño para Arduino, que desarrollaré en próximos artículos.
Deja una respuesta