CAB 8. Lenguaje Arduino. Funciones

8.1 Introducción

Una función es un conjunto de instrucciones agrupadas que generalmente realizan una tarea concreta y particular.

Las funciones nos permiten organizar el código haciéndolo más legible, sostenible, reutilizable, mejorando su mantenimiento y la participación de varios programadores en un mismo proyecto.

La mejor forma de imaginar que es una función es pensar en una caja negra que a partir de unos parámetros de entrada devuelve un resultado o realiza una serie de tareas agrupadas con un fin común.

La sintaxis de una función es la siguiente

tipo_dato nombre_función(tipo_parametro_1 nombre_parámetro_1) {
   // Conjunto de instrucciones de la función
}

En una función, por lo tanto podemos distinguir

  • tipo_dato, es el tipo de datos que devuelve la función como resultado. Si la función no devuelve ningún valor este tipo de datos será void
  • nombre_función, es el nombre con el que nos referiremos a la función
  • tipo_parametro_1, es el tipo de datos del nombre_parámetro_1 de la función
  • nombre_parámetro_1, es el nombre de la variable nombre_parámetro_1 que hemos pasado como primer argumento de entrada a la función

Los parámetros o argumentos de entrada de una función pueden ser varios o no tener ninguno.

En el caso de tener varios parámetros de entrada deben estar separados por comas entre sí.

Ejemplo de la definición de una función que devuelve un valor entero y que tiene dos parámetros de entrada

// Ejemplo de definición de una función que devuelve un valor entero y que tiene dos parámetros de entrada
// La función devuelve el mayor de los dos números pasados como argumentos de entrada a la función

int calcular_mayor_dos_numeros (int a, int b) {
   int mayor_numero;  // Variable local a la función
   if (a > b) {
      mayor_numero = a;
   }
   else {
      mayor_numero = b;
   }
   return mayor_numero;   // La función devuelve como salida el valor contenido en la variable mayor_numero
}

Para llamar a una función en el código de un Sketch bastará con poner el nombre de la función pasando los parámetros de entrada que contenga y asignar el resultado a una variable en el caso de devolver un valor diferente de void.

Ejemplo de llamada a la función del ejemplo anterior

int d = 100;
int e = 50;

int may_num = calcular_mayor_dos_numeros (d, e);

// Esta función devolvería en la variable may_num el valor 100

Cuando llamamos a una función en nuestro programa en el puntoA el control salta a la función, la ejecuta y posteriormente el flujo de ejecución continua con la siguiente instrucción desde el puntoA.

Podremos definir tantas funciones como consideremos necesarias para nuestro programa y utilizarlas cuando corresponda.

También resultan muy útiles las funciones que vienen definidas directamente en el lenguaje Arduino y que veremos en un apartado a continuación, pues podremos utilizarlas directamente sin conocer su código y sin la necesidad de programarlo.

Sólo necesitaremos conocer el tipo de dato de salida y los parámetros de entrada junto a sus tipos de datos para poder utilizarlas.

8.2 Funciones Específicas del Lenguaje Arduino

Como hemos indicado anteriormente, existe una serie de funciones que ya vienen directamente definidas en el lenguaje Arduino y que para su uso no es necesario incluir ninguna libreria.

A continuación vamos a ver algunas de las funciones propias del lenguaje Arduino y que son las más utilizadas en la programación de Sketchs, agrupadas por su funcionalidad.

8.3 Funciones de Entrada y Salida

Estas funciones son las encargadas de la gestión de los conectores o pines de las tarjetas Arduino.

Estos conectores, como ya sabemos, pueden ser Analógicos o Digitales, siendo su control completamente diferente. Veremos a continuación funciones para ambos.

8.3.1 Funciones Conectores Digitales

Algunas funciones para la gestión y control de los pines o conectores digitales de la placa Arduino son

8.3.1.1 Función pinMode()

Los conectores o pines digitales pueden funcionar en Modo Lectura o Modo Escritura.

Esta función nos permite configurar el modo de funcionamiento de cada conector digital que vayamos a utilizar en nuestro Sketch.

Se suele llamar en la función de configuración setup() del Sketch.

Su sintaxis es

pinMode(número_pin, modo_funcionamiento);

Donde

  • número_pin, en Arduino UNO, por ejemplo, serían los puertos etiquetados en la propia tarjeta y que van del 0 al 13.
  • modo_funcionamiento, se utilizan las constantes INPUT y OUTPUT definidas en el propio lenguaje. INPUT para lectura (por defecto todos los conectores digitales están configurados con esta opción), OUTPUT para escritura.

Ejemplo de funcionamiento

// Ejemplo de pinMode()

void setup(){
   pinMode (11, OUTPUT);   // Configuramos el pin o conector número 11 en modo escritura
   pinMode (12, INPUT);    // Configuramos el pin o conector número 12 en modo lectura
}

Cabe resaltar, que los conectores analógicos también pueden utilizarse como conectores de entrada / salida digital. Pero en este caso y en una tarjeta Arduino UNO, por ejemplo, mientras que a los pines digitales nos referimos directamente con su número de conector (0 al 13) en el caso de los pines analógicos en la función pinMode() se identificarán como A0, A1, A2, A3, A4 y A5.

8.3.1.2 Función digitalWrite()

Una vez configurados los pines o conectores podemos escribir o leer por ellos.

Esta función nos permite escribir un valor en un pin configurado en modo escritura.

Su sintaxis es

digitalWrite(número_pin, valor_escribir);

Donde

  • número_pin, el numero de conector que vamos a utilizar
  • valor_escribir, el valor que vamos a enviar por ese pin. Este valor puede ser uno de los dos definidos en el lenguaje Arduino, que son las constantes LOW o HIGH.

8.3.1.3 Función digitalRead()

Es similar a la función anterior pero para la lectura.

Es decir, nos permite leer un valor por un pin o conector configurado en modo lectura.

Su sintaxis es

byte valor_leido;
valor_leido = digitalRead(número_pin);

A continuación veremos un ejemplo de uso de estas tres funciones

// Ejemplo uso funciones de Entrada / Salida con Conectores Digitales

void setup(){
   pinMode (11, OUTPUT);   // Configuramos el pin o conector número 11 en modo escritura
   pinMode (12, INPUT);    // Configuramos el pin o conector número 12 en modo lectura
}

void loop(){
   digitalWrite(11, HIGH);  // Escribimos HIGH en el pin 11

   byte valor_lectura;
   valor_lectura = digitalRead(12);   // Leemos el valor del pin 12 y lo almacenamos en la variable valor_lectura

   break;
}

8.3.2 Funciones Conectores Analógicos

Los conectores o pines analógicos tienen una función similar pero un comportamiento diferente a sus homólogos los pines digitales.

Mientras que los conectores digitales admiten solo valores LOW o HIGH, los conectores analógicos pueden gestionar un rango más amplio de valores.

Las placas Arduino permiten medir o mejor dicho convertir cantidades analógicas de tensión en valores numéricos enteros.

Señalar que estos valores oscilan entre el valor 0 para una tensión eléctrica nula hasta el valor 1023 que equivale al máximo de tensión eléctrica.

A continuación veremos algunas funciones que nos permiten operar con los pines o conectores analógicos de la placa Arduino

8.3.2.1 Función analogRead()

Esta función permite leer un valor de un conector o pin analógico.

Este valor de tensión eléctrica, la tarjeta Arduino lo convierte en un valor digital de tipo entero.

En este caso no necesitamos preceder con la letra A al número de pin o conector como si ocurría en la función pinMode().

Su sintaxis es

int valor_leido;
valor_leido = analogRead(número_pin);     // número_pin en Arduino UNO sería un valor entre 0 y 5

Hay que tener en cuenta que en el caso de la lectura de un pin analógico que no es instantáneo. Necesita 0,0001 segundos para su lectura. Es decir, solo se puede leer 10.000 veces en cada segundo.

8.3.2.2 Función analogWrite()

Esta función requiere una explicación algo más compleja que las anteriores, pues realmente no existe ninguna función en Arduino que nos permite generar una señal analógica propiamente dicha.

Sin entrar en tecnicismos y de forma esquemática diremos que

  • Una tarjeta Arduino es capaz de generar señales PWM (Pulse Width Modulation), es decir, Modulación de Ancho de Pulso
  • Esta técnica PWM permite reproducir señales analógicas a partir de señales digitales
  • Las señales PWM solo se pueden reproducir en algunos pines de las tarjetas Arduino. Por ejemplo, en Arduino UNO están marcados los conectores 3, 5, 6, 9, 10 y 11 como puede verse en dicha placa

La sintaxis de esta función es

analogWrite(número_pin, valor_escribir);

El parámetro valor_escribir es un entero del tipo byte que puede tomar valores desde 0 (tensión de 0v) hasta 255 (100% de tensión, es decir 5v). Define el porcentaje máximo de tensión que queremos aplicar al conector número_pin.

8.4 Funciones de Control del Tiempo

En el lenguaje Arduino, existen funciones encargadas de la gestión y administración del tiempo.

Son funciones específicas utilizadas en el entorno de programación del microcontrolador Arduino.

Algunas de ellas son

8.4.1 Función delay()

Esta función nos permite introducir una pausa en nuestro Sketch.

Su sintaxis es

delay(pausa_milisegundos);

El argumento pausa_milisegundos define el tiempo en milisegundos que queremos detener la ejecución del programa antes de pasar a ejecutar la siguiente instrucción. Es un valor de tipo unsigned long, que por lo tanto, nos permite un tiempo en la pausa que puede ser bastante largo.

8.4.2 Función delayMicroseconds()

Es una función muy similar a la anterior, pero en este caso el tiempo de la pausa en lugar de milisegundos lo expresamos en microsegundos.

Su sintaxis es

delayMicroseconds(pausa_microsegundos)

El argumento pausa_microsegundos es el tiempo en microsegundos que queremos pausar la ejecución del programa.

Recordar que 1 microsegundo equivale a 1/1000 milisegundos.

La función que se utiliza de forma más habitual es delay(), pero hay que tener en cuenta las dos pues dependiendo de la casuística concreta del algoritmo podemos necesitar utilizar cualquiera de las dos.

8.4.3 Función millis()

Esta función nos permite contar el tiempo en milisegundos desde que se ha iniciado el Sketch.

El tiempo medido es devuelto en un entero de tipo unsigned long.

Su sintaxis es

unsigned long tiempo_transcurrido;
tiempo_transcurrido = millis();

8.4.4. Función micros()

Esta función es idéntica a la anterior, pero el tiempo medido en este caso es en microsegundos en lugar de milisegundos.

El tiempo medido también se almacena en un entero de tipo unsigned long.

Su sintaxis es

unsigned long tiempo_transcurrido;
tiempo_transcurrido = micros();

8.5 Funciones de Generación de Números Aleatorios

Los números aleatorios están íntimamente ligados a la informática y programación.

Como podrás comprobar en la práctica resultan útiles y necesarios en muchas situaciones para la resolución de numerosos problemas algorítmicos.

Pero, también debes saber que la realidad es que informáticamente no es posible la generación PURA de números aleatorios.

Cuando ejecutamos una función para la generación de números aleatorios dará como resultado una secuencia no finita de números aleatorios… ¿Entonces dónde está el problema?

Para dicha generación de números aleatorios , el método que suele utilizarse consiste en la generación de números pseudo-aleatorios a partir de un valor que se denomina semilla.

El problema está en que en realidad lo que sucede es que dos secuencias de números pseudo-aleatorios que se basan en la misma semilla serán idénticas.

Por lo tanto, para la obtención de una secuencia de «números lo más aleatorios posibles» debemos utilizar semillas diferentes. Para que sean aleatorias estas semillas deben ser no controlables y no reproducibles.

En el lenguaje Arduino, el método más usual es utilizar como semilla la lectura del valor de un conector o pin analógico en el que no hay nada conectado, mediante la función analogRead().

Esto es debido a que un pin que no tiene nada conectado se ve afectado en sus valores por las perturbaciones del entorno, con lo cual la lectura del mismo dará como resultado valores «suficientemente aleatorios», pues realmente lo que estamos leyendo es un valor de ruido que será diferente en cada instante.

8.5.1 Función randomSeed()

Esta función permite inicializar una secuencia de números pseudo-aleatorios a partir de una semilla pasada como argumento de entrada.

Su sintaxis es la siguiente

randomSeed(semilla);

El argumento semilla debe ser un número de tipo long o tipo int.

8.5.2 Función random()

Con esta función obtenemos el siguiente número de la secuencia de números pseudo-aleatorios obtenida con la función anterior.

Su sintaxis puede ser de dos formas diferentes, tal y como vemos a continuación

random (valor_min, valor max);

random (valor_max) ;

Los números obtenidos con esta función siempre estarán contenidos entre dos valores, uno mínimo y otro máximo, que son los que definimos en la llamada a la función con los argumentos de entrada valor_min y valor_max, respectivamente. En este caso los valores estarán entre valor_min y valor_max-1.

Cuando no pasamos el valor_min el ordenador elige como mínimo el 0, con lo cual en este caso los valores estarán entre 0 y valor_max-1.

A continuación veremos un ejemplo que clarifica el uso estas funciones para la generación de números aleatorios

// Ejemplo de Generación de Números Aleatorios
// Estos los mostramos por el Monitor Serie de Arduino

long num_aleatorio;   // Definimos variable para valor Número Aleatorio con el tipo long

void setup() {
  Serial.begin(9600);   // Configuramos la velocida del Monitor Serie a 9600 baudios
  
  randomSeed(analogRead(0));   // Inicializamos el Generador de Números Aleatorios tomando como valor de semilla
                               // el valor de ruido del puerto analógico 0 de la tarjeta Arduino
}

void loop() {
  Serial.print("Número Aleatorio (0..499): ");
  num_aleatorio = random(500);   // Obtendremos un valor entre 0 y 499
  Serial.println(num_aleatorio);   

  Serial.print("Número Aleatorio (50..99): ");
  num_aleatorio = random(50, 100);   // Obtendremos un valor entre 50 y 99
  Serial.println(num_aleatorio);

  Serial.println("--------------------------------------");
  
  delay (1000);  // Haccemos una pausa de 1 seg antes de ejecutar de nuevo el Bucle
}

En la siguiente imagen podemos ver un ejemplo de la ejecución del Sketch anterior.

Figura CAB8.1 Ejemplo Números Aleatorios Monitor Serie de Arduino

8.6 Funciones Manipulación Bits, Control Interrupciones

Existen más funciones definidas en el lenguaje Arduino, pero su explicación considero que no corresponde a un Nivel Básico de programación del lenguaje.

Sin embargo debemos saber que existen funciones que nos permiten manipular bits, controlar las interrupciones …

Estas funciones se verán con detalle en el siguiente curso …

8.7 Continuación…

Próximamente…

Curso de Arduino – Nivel Medio (CAM)

¡¡¡ No te lo pierdas !!!

Este sitio web utiliza cookies para que usted tenga la mejor experiencia de usuario. Si continúa navegando está dando su consentimiento para la aceptación de las mencionadas cookies y la aceptación de nuestra política de cookies, pinche el enlace para mayor información.plugin cookies

ACEPTAR
Aviso de cookies