viernes, 1 de agosto de 2014

Escribir una librería para Arduino




Arduino Library Tutorial



Transcripción de la entrada localizada en la web de Arduino.cc

Escribir una librería para Arduino
Este documento explica cómo crear una librería para Arduino. Se inicia con un programa de código Morse y explica cómo convertir sus funciones en una librería. Esto permite que otras personas usen el código que has escrito y puedan actualizarlo facilmente a medida que mejora la librería.
Comenzamos con un programa de código Morse:
int pin = 13;
void setup() {
  pinMode(pin, OUTPUT);
}
void loop() {
  punto(); punto(); punto();
  raya(); raya(); raya();
  punto(); punto(); punto();
  delay(3000);
}
void punto() {
  digitalWrite(pin, HIGH);
  delay(250);
  digitalWrite(pin, LOW);
  delay(250);
}
void raya() {
  digitalWrite(pin, HIGH);
  delay(1000);
  digitalWrite(pin, LOW);
  delay(250);
}
Si ejecuta este programa, se representará el código de SOS (llamada de auxilio) en el pin 13.
El programa tiene unas pocas partes que tendremos que poner en nuestra librería. En primer lugar, tenemos las funciones punto() y raya() que hacen el parpadeo. En segundo lugar, tenemos la variable ledPin que indica el pin a utilizar. Por último, está la llamada a pinMod () que inicializa el pin como salida.
Vamos a empezar a convertir el programa en una librería!
Para una librería necesita al menos dos arcivos: un archivo de cabecera (w / con extensión. H) y el código fuente (w / extensión. cpp). El archivo de cabecera contiene definiciones para la librería: básicamente un listado de todo lo que hay dentro, mientras que el archivo del código fuente tiene el código real. Vamos a llamar a nuestra librería "Morse", por lo que nuestro archivo de cabecera será Morse.h. Echemos un vistazo a lo que contiene. Puede parecer un poco extraño al principio, pero tendrá más sentido una vez que vea el código fuente que lo acompaña.
El archivo de cabecera consiste básicamente en una clase con una línea para cada función de la librería, junto con las variables que se van a usar:
class Morse {
  public:
    Morse(int pin);
    void punto();
    void raya();
  private:
    int _pin;
};
Una clase es simplemente una colección de funciones y variables agrupadas en un mismo lugar. Estas funciones y variables pueden ser públicas, lo que significa que las podrán usar las personas que están utilizando la librería, o privada, lo que significa que sólo se puede acceder a ellas desde la propia clase. Cada clase tiene una función especial conocida como constructor, que se utiliza para crear una instancia de la clase (o sea, un objeto). El constructor tiene el mismo nombre que la clase, y no devuelve nada.
Se necesitan un par cosas más en el archivo de encabezado. Una de ellas es una instrucción # include que da acceso a los tipos estándar y las constantes del lenguaje Arduino (esto se agrega automáticamente a los programas normales, pero no a las librerías). Se parece a esto (y se coloca antes de la definición de la clase mostrada anteriormente):
  1. Include "WProgram.h"
Por último, es común añadir las siguientes lineas de código :
  1. Ifndef Morse_h
  2. Define Morse_h
// La declaración # include y el código van aquí ...
  1. endif
Básicamente, esto evita problemas si alguien accidentalmente usa dos veces el #include con la librería que estamos construyendo, evitando que se declaren las variables y funciones más de una vez.
Por último, se suele poner un comentario en la parte superior de la librería con su nombre, una breve descripción de lo que hace, quién lo escribió, la fecha y el tipo de licencia.
Echemos un vistazo a la cabecera completa:
/*
  Morse.h - Library for flashing Morse code.
  Created by David A. Mellis, November 2, 2007.
  Released into the public domain.
  • /
  1. ifndef Morse_h
  2. define Morse_h
  3. include "WProgram.h"
class Morse {
  public:
    Morse(int pin);
    void punto();
    void raya();
  private:
    int _pin;
};
  1. endif
Vamos a repasar las distintas partes del código fuente de Morse.cpp.
Lo primero son un par de # include. Con esto el resto del código tendrá acceso a las funciones estándar de Arduino, y a las definiciones definidas en Morse.h:
  1. Include "WProgram.h"
  2. Include "Morse.h"
A continuación viene el constructor. Una vez más, en el constructor se establece lo que debe ocurrir cuando alguien crea una instancia de la clase. En este caso, el usuario especifica el pin que le gustaría utilizar. Configuramos el pin como salida en una variable privada para su uso en las otras funciones:
MORSE:: Morse (pin int) (   pinMode (pin, OUTPUT);   _pin = pin; )
Hay un par de cosas extrañas en este código. La primera es el Morse:: antes del nombre de la función. Esto indica que la función es parte de la clase Morse. Verás esto en otras funciones de la clase. Lo segundo es el subrayado en el nombre de nuestra variable privada, _pin. Esta variable puede tener cualquier nombre, siempre y cuando coincida con la definición que figura en el archivo de encabezado. Agregar un subrayado al inicio del nombre es una convención común para dejar claro que las variables son privadas, y también para diferenciarlas del argumento de la función (el pin en este caso).
Después viene el código del programa que estamos convirtiendo en una librería (¡por fin!). Se ve más o menos lo mismo, salvo Morse:: delante de los nombres de las funciones, y en lugar de _pin pin:
void Morse::punto() {
  digitalWrite(_pin, HIGH);
  delay(250);
  digitalWrite(_pin, LOW);
  delay(250);  
}
void Morse::raya() {
  digitalWrite(_pin, HIGH);
  delay(1000);
  digitalWrite(_pin, LOW);
  delay(250);
}
Por último, es típico incluir un comentario en la parte superior del código fuente. Vamos a ver el código:
/*
  Morse.cpp - Library for flashing Morse code.
  Created by David A. Mellis, November 2, 2007.
  Released into the public domain.
  • /
  1. include "WProgram.h"
  2. include "Morse.h"
Morse::Morse(int pin) {
  pinMode(pin, OUTPUT);
  _pin = pin;
}
void Morse::punto() {
  digitalWrite(_pin, HIGH);
  delay(250);
  digitalWrite(_pin, LOW);
  delay(250);  
}
void Morse::raya() {
  digitalWrite(_pin, HIGH);
  delay(1000);
  digitalWrite(_pin, LOW);
  delay(250);
}
Y eso es todo lo que necesita (hay algunas otras cosas opcionales, pero hablaremos de eso más adelante). Vamos a ver cómo usar la librería.
En primer lugar, hay que crear el directorio Morse dentro del subdirectorio de librerías . Copia o mueve los archivos Morse.h y Morse.cpp a ese directorio. Ahora ejecuta el IDE de Arduino. Si vas al menú Sketch > Import Library deberías ver el una opción Morse. La librería será compilada con los programas que la utilizan. Si no aparece la librería, asegúrate de que los nombres de los archivos terminan realmente ten .cpp y .h (y no en .pde o .txt, por ejemplo).
Vamos a ver cómo podemos modificar nuestro programa de SOS para hacer uso de la nueva librería:
  1. include <Morse.h>
Morse morse(13);
void setup() { }
void loop() {
  morse.punto(); morse.punto(); morse.punto();
  morse.raya(); morse.raya(); morse.raya();
  morse.punto(); morse.punto(); morse.punto();
  delay(3000);
}
Hay algunas diferencias con el programa original (aparte del hecho de que parte del código se ha trasladado a la librería).
En primer lugar, hemos añadido una declaración # include al principio del programa. Esto hace que la librería Morse esté disponible para el programa y que se envíe a la placa de Arduino. Cuando ya no necesite una librería en un programa, debe eliminar la sentencia # include para ahorrar espacio.
En segundo lugar, creamos una instancia de la clase Morse llamada morse:
Morse morse(13);
Cuando esta línea se ejecute ( esto sucede incluso antes de que se ejecute la función setup () ), se llamará al constructor de la clase Morse, y se le pasará un parámetro (en este caso, el valor 13).
Tenga en cuenta que nuestro setup() está vacío, esto se debe a que la llamada a pinMode () se produce dentro de la librería (cuando se construye la instancia).
Por último, para llamar a las funciones punto() y raya(), tenemos que precederlas del prefijo morse (que es el nombre de la instancia que hemos creado). Podríamos tener varias instancias de la clase Morse, cada una con su propio PIN almacenado en la variable privada _pin de esa instancia. Al llamar a una función se indica que instancia de la clase se debe utilizar. Es decir, si tuviéramos:
Morse morse (13); Morse morse2 (12);
la llamada a morse2.dot (), hace que la salida sea por el pin 12.
Si pruebas el nuevo programa, probablemente te darás cuenta de que el IDE de Arduino no reconoce las funciones de la librería y no resalta el código. Por desgracia, por ahora el software de Arduino no puede averiguar lo que hay definido en la librería (aunque sería una buena característica a tener en cuenta), así que tienes que ayudarle un poco. Para ello, crea un archivo llamado keywords.txt en el directorio de Morse.. Que debe tener este aspecto:
Morse KEYWORD1 raya KEYWORD2 punto KEYWORD2
Cada línea tiene el nombre de la palabra clave, seguido de un tabulador (no espacios), seguido por el tipo de palabra clave. Las clases deben ser del tipo KEYWORD1 y se muestran de color naranja; las funciones deben ser del tipo KEYWORD2 y serán de color marrón. Tendrá que reiniciar el entorno Arduino para conseguir que reconozca las nuevas palabras clave.
Es conveniente acompañar las librerías con algún programa de ejemplo que haga uso las mismas. Para ello, cree un directorio examples dentro del directorio Morse. A continuación, copie el directorio que contiene el programa de ejemplo que escribimos arriba (lo llamaremos SOS) en el directorio de ejemplos. (Puedes encontrar el programa de ejemplo con la opción Sketch > Show Sketch Folder) Si reinicias el entorno Arduino (esta es la última vez, lo prometo) – verás la opción Library-Morse dentro de File > Sketchbook > Examples que contiene su ejemplo. Es posible que quieras agregar algunos comentarios para explicar mejor cómo usar la librería.
Si quieres echa un vistazo a la librería completa (con palabras clave y el ejemplo), puede descargarlo: Morse.zip.
Eso es todo por ahora, pero probablemente voy a escribir una colección de tutoriales avanzados pronto. Mientras tanto, si tienes cualquier problema o sugerencia, por favor escribe en el foro de desarrollo de software.

2 comentarios:

  1. Hola... Una duda... en arduino se pueden tener multiples constructores o solo uno por clase?

    ResponderEliminar
  2. Aunque la sobrecarga de métodos o constructores es habitual en lenguajes como Java, que sepamos el IDE de Arduino no te lo permite.
    Puedes ver el tipo de error que te daría, simplemente intentando hacer una librería del ejemplo del LED parpadeante: "Blink.ino".
    Copia este código y verás que el IDE te da un mensaje de error del tipo: "void Blink::parpadeo() cannot be overloaded"


    #ifndef Blink_h
    #define Blink_h
    #include "arduino.h"

    class Blink {
    public:
    Blink(int pin);
    void parpadeo();
    private:
    int _pin;

    public:
    Blink();
    void parpadeo();
    };
    #endif

    ResponderEliminar