En esta lección vamos a ver el uso de funciones. Una vez que aprendamos a programar funciones y tras haber estudiado las comunicaciones por puerto serie y el uso de variables estaremos preparados para hacer programas de verdad interaccionando con periférios y comunicando con otros dispositivos.
¿Funciones para qué?
Las funciones no son más que un conjunto de líneas de código que realizan una tarea determinada y a las que ponemos un nombre. No son necesarias, ya que ese código podría ser insertado en todos los puntos del programa que lo necesiten, sin embargo permiten desarrollar el código de modo más limpio y ordenado.
El objetivo fundamental de las funciones es triple:
- Realizar un código más ordenado, limpio y mantenible
- Favorecer la reutilización del código, mediante bibliotecas de funciones
- Favorecer la mejora y crecimiento del código
Efectivamente, las funciones facilitan enormemente el trabajo del desarrollador, no sólo cuando desarrolla su propio código, sino fundamentamente cuando pretende utilizar código que ha sido desarrollado por otros.
La función “Hola Mundo”
¿Cómo sería la función más básica, que se limita a imprimir por puerto serie “Hola Mundo”?
1 2 3 |
void holamundo(){ Serial.println("Hola Mundo"); } |
Vamos a analizarla
- void – Esta palabra se usa porque la función no devuelve nada, es decir, no produce ningún resultado. Lo verás más claro cuando hagamos una función que sí produzca un resultado.
- holamundo – Es el nombre de la función, podríamos haberle puesto el que quisiéramos
- ( ) – Entre paréntesis habríamos puesto parámetros en caso de que los hubiera, en este caso no hay y por eso no se escribe nada. También lo entenderás mejor cuando hagamos una función que use parámetros.
¿Cómo sería un programa que use la función holamundo?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
void holamundo(){ Serial.println("Hola Mundo"); } void setup() { Serial.begin(9600); } void loop() { holamundo(); delay(3000); } |
¿Qué hace este programa? Pruébalo tú mismo, solo indicarte que este programa sería idéntico a este:
1 2 3 4 5 6 7 8 9 10 |
void setup() { Serial.begin(9600); } void loop() { Serial.println("Hola Mundo"); delay(3000); } |
Utilizando parámetros
Imaginemos ahora una función que queremos que nos envíe por puerto serie el resultado de sumar dos números a y b. Como a la hora de programar no sabemos cuánto valdrán a y b se los pasamos como parámetro (estos podrían ser la lectura de algún sensor).
1 2 3 4 |
void sumar(int a, int b){ int suma = a + b; Serial.println(String(suma)); } |
La analizamos
- void – de nuevo está función no devuelve nada.
- sumar – sumar es el nombre de la función
- (int a, int b) – son los dos parámetros que toma esta función con los que hará los cálculos. a y b son variables locales de la función por lo que no pueden usarse fuera de ella.
¿cómo sería un programa completo?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
void sumar(int a, int b){ int suma = a + b; Serial.println(String(suma)); } void setup() { Serial.begin(9600); } void loop() { sumar(4,5); delay(3000); } |
Esta función mandaría por puerto serie la cadena 9.
Un uso INCORRECTO de variables en funciones
A continuación vamos a poner un código que compila y funciona, pero que sin embargo no se debería hacer nunca.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
int a,b; //declaramos a y b como variables globales void sumar(){ int suma = a + b; //usamos las variables globales a y b Serial.println(String(suma)); } void setup() { Serial.begin(9600); a=5; //inicializamos a y b b=4; } void loop() { sumar(); delay(3000); } |
Este programa compila y funciona, sin embargo es una mala praxis de programación, ¿por qué? Estamos declarando las variables globales a y b y por ser globales se pueden usar en cualquier parte de nuestro programa. Luego declaramos la función sumar, sin ningún parámetro, que suma a y b. Dado que son globales utilizará los valores que tengan a y b en cada caso. Finalmente asignamos un valor a a y b y hacemos la suma. Hasta aquí todo OK. Sin embargo, no deberíamos usar variables globales dentro de funciones, sino que deberíamos pasarle los valores que necesite a través de parámetros (como hemos hecho anteriormente), aunque esto funcione, no es correcto ya que no cumple con los objetivos de limpieza, reutilización, evolución y mantenimiento del código que hemos dicho anteriormente.
Ahora sí, devolvemos un valor
Finalmente, vamos a hacer una función, que además de hacer cosas devuelva un valor, por ejemplo el producto de dos números. Como todos os podríais esperar, la función, y el programa que la usa seŕia así.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
/** * Esta función multiplica dos enteros y devuelve el resultado */ int multiplicar(int a, int b){ int producto = a*b; //multiplicamos ambos parámetros return producto; //devolvemos el producto, que es un entero. } void setup() { Serial.begin(9600); } void loop() { int resultado = multiplicar(2,5); //guardamos lo que devuelve la función en la variable resultado Serial.println(String(resultado)); //mandamos por puerto serie el resultado delay(3000); } |
Pruébala y verás como funciona.
Un ejercicio
Haz tú ahora una función que detenga la ejecución de un programa hasta que le llegue algo por puerto serie. Esta función la usaremos más adelante. Básicamente debe dejar la función loop en espera hasta que llega algo por puerto serie, en ese momento, lee todo lo que llega (aunque no haga nada con ello) y sigue ejecutándose el programa normalmente. Es útil por ejemplo cuando nuestro programa está esperando a que le lleguen comandos a través de bluetooth para saber qué debe hacer. Mientras no llega nada, espera y una vez que llega actúa en consecuencia.
En el siguiente video te dejo una posible solución: