Objetivos

 

  • Vamos ver como reescribir el programa Led como una clase con sus métodos.
  • Mostraremos el procedimiento general.
  • Montaremos el armazón básico de un programa con clases.

Material Requerido

 

 

 

Vista principal  Un Arduino UNO o similar

 

Clases, Objetos y demás zarandajas

 

Bueno, ahora es cuando la matan. Hay una especie de temor reverencial en relación con la programación orientada a objetos y en general hay muchísima gente que tiene pánico al tema y evita a toda costa empezar a usar la OOP (Object Oriented Programing) en sus programas con excusas varias: «Mis programas no son tan grandes» ; «No me compensa el lío» ; «hay que dedicarle mucho tiempo y yo ya no estoy para aprender cosas nuevas».

En realidad, todo eso son tonterías. Te compensa y mucho. No es tan complicado de aprender y si no estás para aprender cosas nuevas, lo mejor que puedes hacer es meterte en el ataúd y cerrar la tapa.

La OOP es, una cosa sencilla, que puedes aprender con rapidez mediante un mínimo esfuerzo y expande enormemente tu capacidad de hacer programas, y más importante de mantenerlos en estado óptimo de funcionamiento. No quiero enrollarme con esto, pero si nunca has usado la OOP o quieres hacer un repaso te dejo aquí una serie de tutos que tenemos en prometec para iniciarse, y no repetirnos:

Introducción a la OOP

En este tuto no entraremos a habar de lo que ya dejamos escrito allí sobre la OOP, sino que nos vamos a centrar en escribir nuestro primer programa con la clase Led, de la que hablábamos en el último tuto (Y que te recomiendo que revises antes de empezar con este) y de la que vamos a partir en este tutorial

Así que déjate de excusas y vamos al lío.

 

La Clase LED

 

En la sesión previa habíamos definido nuestro fichero Led.h así:

#ifndef LED_H
#define LED_H
#include <arduino.h>

void Init(int pin);
void on(void);
void off(void) ;
void blink(int repeat, int pause) ;
#endif

Vamos a empezar definiendo la Clase Led en una primera aproximación que nos deje encender y apagar un led que definamos como una instancia de ella, modificando o reescribiendo el fichero Led.h:

#ifndef LED_H
define LED_H
#include <arduino.h>

class LED
{   private:
       int _pin; // Pin al que está conectado el LED

    public:
       LED(int pin); // Constructor
       void On();  // Métodos para controlar el LED
       void Off();
       void Blink(int ms);
};

#endif

Ya conoces las tres primeras líneas. Después declaramos la clase LED, en la que definimos dos apartados principales: “private:” y “public”. Básicamente las funciones y variables que definas en la clase private no se pueden usar desde el exterior, es decir que son variables y funciones para uso interno, Solo se pueden usar desde el interior de las funciones propias de la clase pero se impedirá usarlas en una llamada externa. ¿Por qué algo tan extravagante? Pues si os habéis leído los tutos de la OOP, se trata de evitar que ciertas cosas se puedan manipular desde fuera para evitar errores.

En la parte private, solo hemos definido la variable _pin en la que guardaremos el valor del pin definido cunado se construya la clase. Mas adelante en el ficero.cpp veremos que hacemos esto:

LED::LED(int pin)            // Constructor
{  _pin = pin;
pinMode(_pin, OUTPUT); // Configurar el pin como salida
}

Una función que se llama igual que la clase, se la llama constructor y se invoca siempre que se cree una instancia de esa clase. En cristiano: Cada vez que crees una instancia de la clase LED en tu programa se invocará el constructor y en este sencillo caso, simplemente guardamos el valor del pin que le pasamos en una variable privada llamada pin, de forma que tengamos identificado el pin al que corresponde la instancia ¿Vale? (De ese modo podremos crear multiples instancias led1, led2… etc)

  • Merece la pena comentar aquí, que en muchas ocasiones esto también se suele escribir, de esta forma:
      • this->_pin = pin;
  • Esto crearía una variable interna llamada pin y le asignaría el valor que le pasamos al constructor, evitando la necesidad de crear otra variable, que la costumbre dicta que empiece por el símbolo de subrayada y después el nombre de la variable.

Después definimos las funciones públicas que son las habituales en un led incluyendo el constructor:

class LED
{   private:
       int _pin; // Pin al que está conectado el LED

public:
   LED(int pin); // Constructor
   void On();  // Métodos para controlar el LED
    void Off();
    void Blink(int ms);
};

Fíjate bien que al cerrar las llaves de definición de la clase hay un humilde “;” que suele torturar, con frecuencia, a los novicios que se suelen olvidar de él. Pasemos al fichero Led.cpp:

#include "LED.h"
LED::LED(int pin)     // Constructor
{ _pin = pin;
  pinMode(_pin, OUTPUT); // Configurar el pin como salida
}

void LED::On()                  // Encender el LED
{   digitalWrite(_pin, HIGH); }

void LED::Off()                  // Apagar el LED
{  digitalWrite(_pin, LOW);}

void LED::Blink(int ms)                  // Hacer parpadear el LED durante 'ms' milisegundos
{   digitalWrite(_pin, HIGH);
    delay(ms);
    digitalWrite(_pin, LOW);
    delay(ms);
}

La idea del programa.cpp es definir todas las funciones que emplearemos en la clase, pero como puede haber más de una clase definida en un fichero .cpp es imperativo definir a que clase pertenece cada función y para eso tienes que escribir el nombre de la función precedida por el nombre de la clase y doble dos puntos “::”. Es decir, la función que enciende el LED se llama On() así que su definición debe ser:

void LED::On()                  // Encender el LED

Al principio es bastante frecuente olvidarte de esto y volverte ligeramente majara hasta que aprendes (A golpes, me temo). Por último, hemos hecho que el constructor configure el pin de la instancia Led como salida:

LED::LED(int pin)     // Constructor
{  _pin = pin;
   pinMode(_pin, OUTPUT); // Configurar el pin como salida
}

Pero en Arduino es habitual hacer esto con una función Begin(), que podríamos haber escrito modificando ese constructor del siguiente modo:

LED::LED(int pin)     // Constructor
     { _pin = pin;           }

Y luego crear otra función de la clase Led llamada Begin():

LED::Begin()
{ pinMode(_pin, OUTPUT); // Configurar el pin como salida }

Pero en este caso es tan sencillo que os lo dejo como ejercicio para vosotros.

 

Programa Final

 

 

Bien, como ya tenemos la clase y el fichero de implementaciones, podemos escribir nuestro programa para hacer parpadear un LED:

#include "LED.h"
LED led13(13);   // Crear un objeto LED conectado al pin 13

void setup()
{    // led13.Begin() ;   }

void loop()
{   led13.On();
    delay(500);
    led13.Off();
    delay(500);
}

Como ves, es más simple que el mecanismo de un chupete. Al haber definido todas las funciones en el fichero.cpp y las declaraciones en el fichero.h, lo único que tenemos que hacer grear una instancia de la clase LED a la que llamamos led13 (Por qué conectamos el led a ese pin y listo)

LED led13(13);   // Crear un objeto LED conectado al pin 13

Con la descripción de programa que hemos hecho no hay método Begin() pero si tú lo creas (Y te lo recomiendo como practica) tendrás que invocarlo en el setup() como es habitual en Arduino. Después simplemente usamos las funciones de la clase On() y Off() tal y como es habitual en cantidad de programas Arduino que habrás usado antes (Si esto no te resulta habitual, es mejor que vuelvas al curso de inicio antes de seguir por aquí)

Aquí os dejo el programa completo: Class_Led_1 es tan simple que no pienso hacer un video para esto. Pues no se si te has dado cuenta pero acabas de escribir un programa Arduino con clases y más importante: Reusable, porque puedes convertir fácilmente los ficheros .h y .cpp en una librería y en un tuto próximo, veremos cómo se hace , pero no adelantemos acontecimientos.

Como veréis, en el ejemplo hemos usado la función delay() para hacer el blink, pero esto, aunque sencillo, es terrible para tus programas y deberías evitarlo siempre. En la próxima sesión veremos cómo resolver este problema modificando el método Blink() para evitar marrones.

 

Deja una respuesta