Una sesión de #define para Arduino

Scooter

Cascarrabias crónico
Hace poco discutimos la conveniencia de usar o no #define en el lenguaje wiring del arduino.
El hilo fue a moderación porque en realidad colgaba de un hilo en el que se hablaba de otra cosa, pero creo que el tema es interesante porque yo le veo bastantes ventajas a #define pero el manual del arduino desaconseja su uso.
Wiring es un "casi C" pero no es C, de ahí el origen de la discusión.

He hecho unas pruebas:
Hacer dos define uno que incluye al otro:
#define bomba 3
#define bombardeo 6


Luego en el código he puesto:
Serial.print(bomba);
Serial.println(bombardeo);

Aparece 36 que es lo correcto, así que el compilador no se lía con eso

Hacer un #define de una palabra clave
#define if 3

Serial.print(if);

Aquí da error, en una de las líneas hay una sentencia if y da el error:
"PhysicalPixel:40: error: '3' cannot be used as a function", osea que cambia el if por un 3 quedando el código:
3(condición);
Eso no cuela lógicamente.

Hacer #define de un trozo de palabra clave
#define digital 3

Serial.print (digital);

Aquí todo funciona correctamente, en el código hay una orden "digitalWrite" que no se convierte en "3Write"


Osea que no se por qué en el manual desaconseja usar los #define. Está claro que hay que tomar ciertas precauciones, si uso un nombre de constante igual al de una función por ejemplo, pero eso creo que también pasa con variables o constantes.

No se si las versiones previas del compilador se atascaban con eso, he usado la 1.0.5

Me parece muuuucho mas eficiente definir ciertas cosas con #define que declarar variables.
En todos los ejemplos define los pines como variables tipo INT cuando eso gasta 2bytes de preciada RAM para cada uno, si defines unos 20 pines son 40 BYTES (mas los punteros que usen) tirados a la basura. Por cierto no se por que no usa variables tipo BYTE que ocupan la mitad. Además por desbordamiento de un array o algo así se podrían corromper con lo que puede fallar que des la orden de apagar el pin 3 y se apague el 12 por decir algo.
Así que por lo menos las asignaciones de los pines creo que se deben de hacer con #define por una cuestión de seguridad, por gasto de ram y posiblemente velocidad.

No se que código compila pero si haces:
funcion(3); // esto es lo que harías indirectamente con un #define
Repito que no se lo que compila pero lo lógico es que haga algo así como un "carga acumulador inmediato 3" y eso va en rom todo y es un ciclo

Si haces:
funcion(variable_que_contiene_un_3);
Entonces habrá un puntero que apunte a la posición de ram en la que está la variable, osea que será algo como "carga acumulador con el contenido de la ram xxx" con suerte será igual de rápido pero puede que el puntero sea de 16 bits y tarde un ciclo mas etc. Desde luego corres el riesgo de que en la ram xxx no tengas un 3 por el motivo que sea.

Quizás la ventaja de definir como variable, es que si hago INT if =3; me de el error en esa línea y sea fácil de localizar y solucionar, si hago #define if 3 , el error sale en la línea en la que esté el if(), si además el #define lo hice cuando no habían if en el programa todo funcionaba correctamente y de repente al añadir la condición salta un error que puede que no sepas de donde cae. Pero bueno eso se soluciona #definiendo con sentido común
 
Última edición:
Yo no diría que Arduino es "Casi C", será basado en Wiring, peeero el compilador es AVR-GCC osea que al final de cuentas es C/C++ quieras o no, solo que algunas cosas quedan declaras implícitas como la llamada a Arduino.h, el resto es un simple main que llama a setup() y loop(), de ahí ya pasa al contenido del sketch.

Fuera de eso anterior, yo diría que lo más conveniente es usar el #define para nombrar periféricos y datos recurrentes de control, las constantes para los números de funciones matemáticas y/u otros datos recurrentes que pueden ser te utilidad conservar en memoria.
 
Ya, si lo veo claro pero en la documentación desaconseja su uso, dice que hay que usar const de ahí la discusión.
Todos los ejemplos están declarados como int lo cual es doblemente absurdo; byte ocupa la mitad y no hay 255 pines
 
He seguido haciendo pruebas.
Por cada
int pin_de_salida = 3;
que cambio por
#define pin_de_salida 3
El código disminuye en unos 10~15 bytes de tamaño
 
Porque estas trabajando con un número de 16bits y necesitas más operaciones para trabajarlo.

En cambio el define trabaja con 8 bits y en forma inmediata como dijiste en el 1er mensaje.

Como decís la variable debería ser unsigned char o algo similar de 8 bits.
 
Si no mal recuerdo la longitud de palabra era 16bits así que digamos ocupa 2x2 para tratar con el puntero, 2 para comparar y 2 para cambiar el pin 2x2 de salto condicionales 2x2 parra las posiciones de salto... lleva 14... no se si haya que hacer algo más :p
 
al parecer la explicacion mia y de byaxel en aquel tema no sirvio de nada....:(

const y #define no son para nada comparables.

#define es un "sobrenombre"
Const es declarar una constante .
 
Yo creo que lo tengo claro, no se.
Si el pin 3 es la bobina de relé del nosequé es mejor usar #define releTal 3
No se por qué todos los ejemplos están con int , no le encuentro sentido.
 
El caso es que es un lenguaje mutante XD, Wiring, C, C++ bueno... si los autores indican ciertas configuraciones como más recomendables... bienvenido sea... pero solo con Arduino (el compilador), no crean que va para todo... eso NO.

Siendo superficiales, el método que se utilice ya es cosa de cada quién... y solo se busca que funcione.
Siendo más analíticos, puede convenir una u otra forma por decir viendo la cantidad de y que recursos se utilizan, buscando mejor respuesta en procesamiento o robustez por ejemplo.

Hablando de pines, puede que tenga más sentido usar int... vamos, que al fin y al cabo un puerto.pin es como una porción de memoria que se puede leer/escribir y el compilador lo trata como tal... "como una variable".

#define, ya lo dijeron que es más como un sobrenombre que oculta bloques de código y cuando se utliza, el compilador hace copias de ese código... colocando en los lugares que se utiliza... también llamado macro.
 
Mmmmm ahí precisamente a mi no me gusta tanto usar #define para muestras_max, si está claro que si y solo si haré 16 muestras vale pero podría ser útil mirar 17 o 15 en otro momento en el mismo programa y usar la misma rutina, en ese caso ya no valdría.
Si en el pin 3 hay un relé que enciende lo que sea, o voy con un destornillador y cambio la carga de sitio y cambio el relé con su transistor de pin o eso no va a cambiar de ninguna de las maneras.
Usar el pin 3 como variable solo le veo ventaja, por ejemplo, una rutina de dimerizado, que da salida por uno u otro pin según una condición, en ese caso el pin de salida es un parámetro
 
Mmmmm ahí precisamente a mi no me gusta tanto usar #define para muestras_max, si está claro que si y solo si haré 16 muestras vale pero podría ser útil mirar 17 o 15 en otro momento en el mismo programa y usar la misma rutina, en ese caso ya no valdría.
...

La idea si uno quiere cambiar el tamaño del buffer con #define es cambiar muestras_max a otro valor, compilar, programar, y ejecutar el programa.

La cuestión es que para definir límites de arrays en C no queda otra que usar define, mientras que en C++ se puede usar const :eek:.
Quiero decir

#define BUFFER_SIZE 8
uint8_t buffer[BUFFER_SIZE];

funciona siempre. En cambio

const uint8_t BufferSize 8;
uint8_t buffer[BufferSize];

al compilar tira error en C, pero no en C++. Por eso hay detractores de #define en C++.
De alguna manera el compilador tiene que saber el tamaño de la memoria a asignar a buffer. De lo contrario solo queda usar memoria dinámica con malloc pero para micros chicos no tiene sentido.
 
Mmmmm ahí precisamente a mi no me gusta tanto usar #define para muestras_max, si está claro que si y solo si haré 16 muestras vale pero podría ser útil mirar 17 o 15 en otro momento en el mismo programa y usar la misma rutina, en ese caso ya no valdría.

Hacer un promedio móvil con muestras variables durante el programa es raro, puede ser que te sirva para promediar distintos datos y ahí si tiene sentido, pero eso sería útil para reusar la función promedio móvil (ahí deberías modificar el código).

En todo caso, el define te sirve para dejar bien en el claro cual será el límite que tendrán los distintos buffers y en caso de tratarse del mismo buffer, por mas que sea variable el muestreo a la hora de definirlo es necesario hacerlo con la máxima cantidad de elementos que tendrá.

Si en el pin 3 hay un relé que enciende lo que sea, o voy con un destornillador y cambio la carga de sitio y cambio el relé con su transistor de pin o eso no va a cambiar de ninguna de las maneras.
Usar el pin 3 como variable solo le veo ventaja, por ejemplo, una rutina de dimerizado, que da salida por uno u otro pin según una condición, en ese caso el pin de salida es un parámetro

No solo llama la atención el consejo de usar una variable para este tipo de menesteres en vez de un define, sino además usar una variable de tipo "int" en un uC que es de 8bits, ya no es solo lo que conlleva el derroche de RAM, sino que es complicar el código (analizándolo en assembler) sin ningún sentido, no hay ventaja alguna, todo lo contrario.

Es muy probable que todo este despelote, sea porque Arduino usa una mezcla rara entre C y C++.

Por cierto, como dato de color, en Java (hermano menor de C++), los define no existen, ahí si tenés que usar variables inicializadas.
 
Última edición:
Por cierto, como dato de color, en Java (hermano menor de C++), los define no existen, ahí si tenés que usar variables inicializadas.

En C# tampoco existe, bueno si existe pero solo devuelven un valor booleano para ser empleado con #if en el preprocesador, no se pueden usar para indicar constantes, ahí se tiene que usar a fuerzas const.

El lenguaje Arduino se basa en Processing, ¿por que desaconsejar el uso de #define? por que en Processing NO EXISTE, como el compilador de Arduino es en C/C++ soporta esa función pero si intentan emplear en Processing eso el compilador falla desde el principio, recuerden que Processing es sobre Java, es por eso que se desaconseja, si en el lenguaje que se supone estas usando esa función no existe entonces no deberías usarla.
 
Muy bueno, ese es un buen motivo; si algo lo migro de arduino a rasPI por ejemplo no irá.
Lo tendré en cuenta pero de momento lo voy a usar masivamente.
 
Atrás
Arriba