Librerías Arduino

Manejar Librerías Arduino

Las librerías son trozos de código hechas por terceros que usamos en nuestro sketch. Esto nos facilita mucho la programación y permite la abstracción haciendo que nuestro programa sea más sencillo de hacer y de entender. En este apartado también veremos cómo escribir o modificar librerías.

Disponemos de infinidad de librerías a nuestra disposición para facilitarnos el trabajo, todas ellas son open source y disponemos de su código.

Las librerías normalmente incluyen los siguientes archivos comprimidos en un archivo ZIP o dentro de un directorio. Estas siempre contienen:

  • Un archivo .cpp (código de C++)
  • Un archivo .h o encabezado de C, que contiene las propiedades y métodos o funciones de la librería.
  • Un archivo Keywords.txt, que contiene las palabras clave que se resaltan en el IDE (opcional).
  • Muy posiblemente la librería incluye un archivo readme con información adicional de lo que hace y con instrucciones de como usarla.
  • Directorio denominado examples con varios sketchs de ejemplo que nos ayudará a entender cómo usar la librería (opcional).

La distintas formas de instalar librerías se puede ver en https://aprendiendoarduino.wordpress.com/2016/06/27/librerias-3/

Para usar una librería que acabamos de instalar, lo que hay que hacer es leer la documentación de esa librería si es que está disponible y luego leer y probar los ejemplos que dispone la librerías.

Pero ahora que ya sabemos manejar clases y objetos, si queremos entrar a fondo en una librería para saber usarla, podemos abrir el fichero del encabezado (.h) y ver las propiedades y métodos, ver si hereda de otra librería, etc… y luego incluso ver cómo funciona la propia librería leyendo el código en el fichero .cpp e incluso si nos atrevemos añadir nuevos métodos o modificar un método que nos interese.

Problemas comunes con las librerías: https://learn.adafruit.com/adafruit-all-about-arduino-libraries-install-use/common-library-problems

Con el nuevo gestor de librerías es mucho más fácil gestionar las librerías instaladas así como su versión y actualización, algo que antes había que hacer manualmente

El listado de librerías se actualiza de internet y se guarda en:

  • C:\Users\usuario\AppData\Local\Arduino15\library_index.json

Las placas se actualiza de internet (del gestor de tarjetas) y se guarda en:

  • C:\Users\usuario\AppData\Local\Arduino15\package_index.json

El fichero library_index.json se actualiza al abrir el IDE y en caso de tener problemas, se puede borrar y se genera de nuevo al abrir el IDE.

Es importante darse de alta en github puesto que nos permite estar al día de las novedades en las librerías y recibir notificaciones cada vez que haya una modificación en las mismas. Además podemos fácilmente actualizar nuestro repositorio de librerías con el comando PULL de git y poner una u otra versión en nuestro repositorio con el comando checkout.

Librería Time y Timezone

Como ejemplo para aprender a usar una librería, veamos las librerías Time y Timezone.

Para aprender a manejarlas, simplemente leer el fichero readme que viene en el repositorio de github y luego los ejemplos.

Algunas funciones librería Time:

  • hour();            // the hour now  (0-23)
  • minute();          // the minute now (0-59)
  • second();          // the second now (0-59)
  • day();             // the day now (1-31)
  • weekday();         // day of the week, Sunday is day 0
  • month();           // the month now (1-12)
  • year();            // the full four digit year: (2009, 2010 etc)
  • hourFormat12();    // the hour now in 12 hour format
  • isAM();            // returns true if time now is AM
  • isPM();            // returns true if time now is PM
  • now();             // returns the current time as seconds since Jan 1 1970
  • setSyncProvider(getTimeFunction);  // set the external time provider
  • setSyncInterval(interval);         // set the number of seconds between re-sync

Algunas funciones librería Timezone:

  • time_t toLocal(time_t utc); Converts the given UTC time to local time, standard or daylight as appropriate.
  • TimeChangeRule myRule = {abbrev, week, dow, month, hour, offset};
    • abbrev is a character string abbreviation for the time zone; it must be no longer than five characters.
    • week is the week of the month that the rule starts.
    • dow is the day of the week that the rule starts.
    • hour is the hour in local time that the rule starts (0-23).
    • offset is the UTC offset in minutes for the time zone being defined.

Ejemplos:

  • TimeChangeRule usEDT = {«EDT», Second, Sun, Mar, 2, -240};  //UTC – 4 hours
  • TimeChangeRule usEST = {«EST», First, Sun, Nov, 2, -300};   //UTC – 5 hours

Una vez visto el manual de la librería, veamos cómo está escrita la librería Time de Arduino que nos ofrece funcionalidades para mantener la fecha y hora con un hardware externo o sin él. Nos permite obtener la fecha y hora como: segundo, minuto, hora, día, mes y año. También da el tiempo con el tipo de dato del estándar C time_t, siendo sencillo el cálculo del tiempo transcurrido.

Existe una nueva versión de la librería Time cuyo código está derivado librería DateTime del Arduino Playground pero está actualizada para ofrecer una API que es más flexible y fácil de usar.

Más información de la librería time: http://www.prometec.net/time-arduino/

La librería Time no requiere de ningún HW especial. Internamente depende de la función millis() de Arduino para llevar un registro del tiempo transcurrido. El tiempo se puede sincronizar con varios tipos de HW como GPS, NTP, RTC, etc…

Veamos cómo está escrita la librería. El código lo encontramos en https://github.com/PaulStoffregen/Time. En el readme.txt explica con detalle el uso de la librería. Explica las funciones disponibles, los ejemplos dentro del directorio examples y el funcionamiento interno de la librería. también hay un fichero keywords.txt con las palabras clave que se van a resaltar en el IDE.

También pueden verse los ficheros:

  • library.json – Información de la librería
  • library.properties – datos de la librería y clasificación que sale en el Gestor de Librerías

Los ficheros que componen la librería son:

  • Time.h — Simplemente incluye a TimeLib.h, se hace por temas de compatibilidad
  • TimeLib.h — Fichero de cabecera de la libreria Time.
  • Time.cpp — código de la librería time
  • DateStrings.cpp — contiene los strings de las fecha en inglés, pero se podría hacer una versión modificada para español.

Fichero TimeLib.h:

  • #ifdef __cplusplus permite a la sección del programa que está dentro ser compilado solo si la macro especificada como parámetro de ha definido. en este caso __cplusplus es una macro definida cuando el compilador de c++ está en uso. Esto se usa para comprobar si una cabecera está compilada bajo C o C++
  • #include <inttypes.h> incluye la cabecera de inttypes.h que está en C:\Program Files (x86)\Arduino\hardware\tools\avr\avr\include, cuyo propósito es proveer un conjunto de tipos de enteros cuyas definiciones sean consistentes en todas las máquinas e independientes de sistemas operativos. Define una serie de macros para usar con printf y scanf, así como funciones para trabajar con el tipo de dato intmax_t que es un entero con el máximo de anchura soportado. Ver http://www.cplusplus.com/reference/cstdint/
  • Se define el tipo de dato http://www.cplusplus.com/reference/ctime/time_t/ del estandar C++ que no dispone el avr libc y se “simula” la librería time.h de C++ que no tiene implementada AVR.
  • Se definen una serie de variables enumeradas con typedef enum y typedef struct
  • Se definen unas macros para convertir los años de tmYear a un valor de 4 dígitos
  • El valor de domingo es 1 como se puede ver en:
    typedef enum {dowInvalid, dowSunday, dowMonday, dowTuesday, dowWednesday, dowThursday, dowFriday, dowSaturday} timeDayOfWeek_t; y como lo define en la macro #define dayOfWeek(_time_)
  • Se definen luego las funciones y se puede ver que hay sobrecarga en las funciones. Por ejemplo en la función setTime que puede ajustar el tiempo pasando un time_t o los datos de hora, minuto, segundo, día, mes y año.

Ficheros Time.cpp y DateStrings.cpp:

  • La función más importante es now() que calcula el numero de segundo transcurridos desde la última llamada a now()
  • En la función now() es donde comprueba si toca sincronizar de nuevo la hora con (nextSyncTime <= sysTime)
  • En la variable sysTime se guarda la hora, es una variable privada.
  • Se definen primero las funciones públicas en Time.cpp y luego las funciones de bajo nivel.
  • Para sincronizar la hora externamente se definen las funciones:
    • setSyncProvider(getTimeFunction);  // set the external time provider
    • setSyncInterval(interval);         // set the number of seconds between re-sync
  • En DateStrings.cpp está la definición de los strings de fechas. Los strings los guarda en la memoria flash para no ocupar memoria RAM. Para ello usa PROGMEM y si no es para AVR, define el PROGMEM y las funciones de progmem de AVR.
  • Se modifican las funciones que devuelven el string del día y del mes pasando el entero con el número de día o mes.

Adicionalmente tenemos otras librería:

La librería Time no dispone de ajuste de hora por zona horaria (time zone o TZ) ni ajuste de DST (Daylight Saving Time): https://en.wikipedia.org/wiki/Daylight_saving_time. Se podría añadir estas funcionalidades a la librería Time o se puede crear una nueva librería que implemente estas funcionalidades y haga uso de la librería Time.

Para solucionar esta carencia disponemos de la librería Time zone https://github.com/JChristensen/Timezone. Esta librería no es accesible desde el gestor de librerías, por lo que habrá que hacer una instalación manual de la misma.

La librería Timezone está diseñada para trabajar en conjunto con la librería Time y debe ser referenciada en el sketch que se use con timezone. Esta librería convierte el Universal Coordinated Time (UTC) a la hora local correcta incluso si hay Daylight Saving Time (DST). La hora puede obtenerse de un GPS, NTP server o un RTC.

La librería Timezone implementa dos objetos para facilitar la conversión de zona:

  • Un objeto TimeChangeRule que describe cuando la hora local cambia de hora estándar a hora de verano y viceversa.
  • Un objeto Timezone que usa TimeChangeRule para hacer las conversiones y las funciones relacionadas. También puede escribir y leer de la EEPROM el TimeChangeRule. Es posible implementar varias zonas horarias definiendo varios objetos Timezone.

Para establecer la TimeChangeRule se hace mediante dos reglas por zona, una para definir cuando comienza el horario de verano y otra cuando comienza el horario estándar. En España el cambio de horario se produce el último domingo de octubre a las 3.00 y el último domingo de marzo a las 2.00 (https://es.wikipedia.org/wiki/Horario_de_verano_en_el_mundo)

Definir un Timezone:

  • TimeChangeRule SDT = {«SDT», Last, Sun, Mar, 2, 60};  //Spain Daylight Time UTC + 0 hours
    TimeChangeRule SST = {«SST», Last, Sun, Oct, 3, 180};   //Spain Standard Time UTC + 1 hours
  • Timezone spainTZ(SDT,SST)

Métodos asociados:

  • toLocal(time_t utc) — Convierte la hora obtenida en UTC a hora local

Ficheros librería:

  • Timezone.h
    • Implementa compatibilidad con IDEs Arduino anteriores a version 1.x comprobando la versión de ARDUINO
    • Incluye la librería Time
    • Define las constantes de los nombres con enum y el número de inicio. Define como día 1 el Domingo en lugar del Lunes
    • TimeChangeRule es un struct con el nombre (abbrev), 4 bytes para: semana, día de la semana, mes y hora y un entero para el offset de la zona horaria
    • Clase Timezone con dos constructores, 7 métodos públicos, 2 métodos privados y 6 variables privadas.
  • Timezone.cpp
    • __AVR__ es una macro que indica si el compilador puede usar procesadores AVR y en ese caso uso la librería EEPROM
    • Puedo construir un objeto Timezone con el par de reglas DST o si la tengo guarda en la EEPROM, pasando la dirección donde la tengo guardada.
    • calcTimeChanges() calcula el nuevo dst start y std start al llamarlo.
    • Al usar toLocal() ya autocalculo las fechas de dst start y std start. Ver ejemplo https://github.com/JChristensen/Timezone/blob/master/examples/Clock/Clock.pde

Más información del uso de la librería Timezone en:

NOTA: la librería timezone no soporta leapsecond https://es.wikipedia.org/wiki/Segundo_intercalar pero podría implementarse en la librería. Ver http://stackoverflow.com/questions/9168970/arduino-leap-second-clock

Crear Librerias Arduino

Las librerías son trozos de código hechos por terceros que usamos en nuestro sketch. Esto nos facilita mucho la programación y permite la abstracción haciendo que nuestro programa sea más sencillo de hacer y de entender. En este apartado veremos cómo escribir o modificar librerías.

Librerías Arduino: https://www.arduino.cc/en/Main/Libraries

El IDE de Arduino incluye una serie de librerías ya instaladas: https://www.arduino.cc/en/Reference/Libraries

Listado de librerías del playground de Arduino: http://playground.arduino.cc/Main/LibraryList, pero existen otras muchas librerías creadas por usuarios o por los fabricantes de HW para facilitar el uso de esos dispositivos con Arduino.

Este tutorial explica como crear una librería: http://arduino.cc/en/Hacking/LibraryTutorial. Explica cómo convertir la función morse en en una librería.

Ejemplo morse.ino

int pin = 13;

void setup()
{
  pinMode(pin, OUTPUT);
}

void loop()
{
  dot(); dot(); dot();
  dash(); dash(); dash();
  dot(); dot(); dot();
  delay(3000);
}

void dot()
{
  digitalWrite(pin, HIGH);
  delay(250);
  digitalWrite(pin, LOW);
  delay(250);
}

void dash()
{
  digitalWrite(pin, HIGH);
  delay(1000);
  digitalWrite(pin, LOW);
  delay(250);
}

Para convertir en una librería de código morse, vemos que hay dos funciones dot() y dash() para iluminar un led durante 250 ms y 1 segundo y  una variable que es ledPin que determina que pin usar. Este es un estilo de programación clásico usando funciones en lugar de objetos.

Para una librería se necesitan al menos dos ficheros:

  • Un fichero de cabecera con la extensión .h. Este fichero tiene las definiciones de la librería, básicamente un listado de todo lo que hay dentro de la librería
  • Un fichero fuente con la extensión .cpp. Este fichero el que contiene el código

En este caso la librería se va a llamar morse y generamos un fichero de cabecera llamado morse.h.

Veamos el código de morse.h donde se define la clase Morse donde tiene una línea por cada función o método y también una línea por cada variable o propiedad de la clase.

class Morse
{
  public:
    Morse(int pin);	//constructor
    void dot();
    void dash();
  private:
    int _pin;
};

Una clase es una colección de funciones (métodos) y variables (propiedades) que se guardan todas juntas en un solo lugar. Las funciones pueden ser públicas (public), es decir, pueden llamarse por quien usa la librería o privadas (private), es decir, que solo pueden llamarse desde dentro de la propia clase. Todas las clases tienen una función llamada constructor, que es usada para crear una instancia de la clase. El constructor tiene el mismo nombre que la clase y no tiene tipo de variable de devolución.

En el fichero de cabecera de una librería es necesario la declaración #include que de acceso a los tipos y constantes estándar del lenguaje de Arduino (esto se añade automáticamente en los sketches pero no a las librerías). Esta declaración debe ponerse antes de la definición de la clase. La declaración debe ser:

  • Versión IDE 1.x: #include “Arduino.h”
  • Versión IDE 0.x: #include “WProgram.h”

También es común poner todo el fichero de cabecera entre estas instrucciones:

#ifndef Morse_h
#define Morse_h
// the #include statment and code go here…
#endif

Esto evita problemas si alguien accidentalmente incluye dos veces la librería, lo que provocaría un error de compilación. A esto se llama guardián de inclusión múltiple o include guard

// Guardián de inclusión múltiple
#ifndef FICHERO_YA_INCLUIDO
#define FICHERO_YA_INCLUIDO

Así se evita que un compilador poco sofisticado abra otra vez el mismo conjunto de ficheros cuando se incluye un fichero de cabecera dos o más veces. Puede darse el caso de no poner las inclusiones en el inicio de un fichero.

La directiva #include existe en dos versiones. En una se pone el nombre de fichero entre comillas, en la otra entre paréntesis angulares (el signo menor y mayor como “comillas”).

#include «fichero_con_comillas.h»
#include <fichero_entre_menor_y_mayor.h>

La versión con los paréntesis angulares busca los ficheros en todos los directorios que se han especificado en la llamada al compilador – normalmente con la opción “-I”. Estos directorios se suelen rastrear por el fichero incluido en el orden en que aparecen en la línea de comando.

Cuando se incluye un fichero entre comillas, entonces el compilador busca este fichero primero en el mismo directorio que el fichero actualmente compilado y después en los demás directorios. Es decir, la versión con comillas se diferencia de la versión con paréntesis angulares únicamente por buscar primero en el directorio del fichero compilado. Tras no encontrarlo ahí actaa igual.

Cuando se crea una librería se debe documentar poniendo un comentario al comienzo de la librerías con el nombre, breve descripción, quien la ha escrito, fecha, licencia, etc…

El fichero de cabecera queda:

/*
  Morse.h - Library for flashing Morse code.
  Created by David A. Mellis, November 2, 2007.
  Released into the public domain.
*/
#ifndef Morse_h
#define Morse_h

#include "Arduino.h"

class Morse
{
  public:
    Morse(int pin);
    void dot();
    void dash();
  private:
    int _pin;
};

#endif

Una vez hecho el fichero de cabecera hay que codificar el fichero fuente Morse.cpp

Primero deben ponerse las declaraciones, esto da al resto de código acceso a las funciones estándar de Arduino y a las definiciones del fichero de cabecera:

#include «Arduino.h»
#include «Morse.h»

Lo siguiente es poner el constructor de la clase. Esto define que ocurre cuando se crea una instancia de la clase. En este caso el usuario debe especificar cual es el pin que se va a usar. Configuramos el pin como salida y los guardamos en una variable privada para usarlo desde otras funciones.

Morse::Morse(int pin)
{
  pinMode(pin, OUTPUT);
  _pin = pin;
}

El código “Morse::” antes del nombre de la función indica que la función es parte de la clase Morse. Esto se ve en todas las funciones de la clase. La variable llamada “_pin” es una variable privada tal y como se ha definido en el fichero de cabecera y se pone el simbolo “_” delante por convención para indicar que es privada y para diferenciarlo del argumento de la función, pero puede llamarse de cualquier forma mientras coincida con la definición en el fichero de cabecera.

Después de definir el constructor, se deben definir las funciones o métodos de la clase. Son las funciones que se habían definido anteriormente en el sketch:

void Morse::dot()
{
  digitalWrite(_pin, HIGH);
  delay(250);
  digitalWrite(_pin, LOW);
  delay(250);  
}

void Morse::dash()
{
  digitalWrite(_pin, HIGH);
  delay(1000);
  digitalWrite(_pin, LOW);
  delay(250);
}

También es habitual añadir el comentario del fichero al principio del fichero. El fichero Morse.cpp queda de la siguiente forma:

/*
  Morse.cpp - Library for flashing Morse code.
  Created by David A. Mellis, November 2, 2007.
  Released into the public domain.
*/

#include "Arduino.h"
#include "Morse.h"

Morse::Morse(int pin)
{
  pinMode(pin, OUTPUT);
  _pin = pin;
}

void Morse::dot()
{
  digitalWrite(_pin, HIGH);
  delay(250);
  digitalWrite(_pin, LOW);
  delay(250);  
}

void Morse::dash()
{
  digitalWrite(_pin, HIGH);
  delay(1000);
  digitalWrite(_pin, LOW);
  delay(250);
}

De esta forma ya tenemos una librería completa. Ahora para incluirla en nuestro IDE debemos crear un directorio Morse dentro del subdirectorio “libraries” del directorio de nuestro entorno de trabajo definido en las propiedades del IDE. Copiar Morse.h y Morse.cpp dentro del directorio Morse y abrir o reiniciar el IDE de Arduino. A partir de este momento veremos nuestra librería disponible en el IDE y podremos incluirla en los sketches con la declaración #include <Morse.h>. La librería será compilada por los sketches que la usen.

El anterior sketch quedaría ahora sustituido por:

#include <Morse.h>

Morse morse(13);

void setup()
{
}

void loop()
{
  morse.dot(); morse.dot(); morse.dot();
  morse.dash(); morse.dash(); morse.dash();
  morse.dot(); morse.dot(); morse.dot();
  delay(3000);
}

Podemos ver que primero se llama a la declaración de la librería Morse. Esto hace que la librería esté disponible en el sketch y lo incluye en el código enviado a la placa Arduino, lo que hace que si la librería es muy pesada, ocupe mucha más memoria nuestro sketch y si no voy a usar una librería es mejor no incluirla para ahorrar espacio.

También observamos que creamos una instancia de la clase Morse llamada “morse”. Al ejecutar esta línea el constructor de la clase es llamado pasando un argumento, creando así el objeto “morse” en nuestro sketch. Luego podemos llamar a los métodos dot() y dash() precedidos del prefijo morse del nombre del objeto.

Es posible tener múltiples instancias de la clase Morse, cada una un pin diferente guardado en la variable privada “_pin”.

Si creamos una librería es conveniente crear el fichero keywords.txt dentro del directorio Morse. De esta forma conseguiremos resaltar las palabras clave que definamos en el fichero keywords. En cada línea del fichero keywords.txt se indica el nombre de la palabra clave y seguido por un tabulador, el tipo de keyword.

  • Las clases deben ser del tipo KEYWORD1 que se resaltan en naranja.
  • Las funciones deben ser del tipo KEYWORD2 que se resaltan en marrón

Para que el fichero keywords.txt se aplique al IDE es necesario reiniciar el IDE.

El fichero keywords.txt quedaría:

Morse KEYWORD1
dash KEYWORD2
dot KEYWORD2

También es aconsejable ofrecer ejemplos de uso de la librería para que los posibles usuarios sepan usarla. Esto se hace creando un directorio “examples” dentro del directorio Morse y añadir en el subdirectorio los sketches de ejemplos que serán visibles desde el IDE.

La librerías morse con los ejemplos y el fichero keywords.txt se puede descargar en: http://www.arduino.cc/en/uploads/Hacking/Morse.zip

Para más información sobre la creación de librerías con un buen “estilo Arduino”, ver la Guía de Estilo de API. Guia de estilo para escribir librerías: http://arduino.cc/en/Reference/APIStyleGuide

Ver ejemplos simples de librerías:

Más información:

Guía de estilo para escribir una librería de Arduino

Para facilitar el entendimiento de las librerías o APIs de Arduino y hacer que el entorno de Arduino sea más homogéneo, desde arduino.cc dan unas pautas para escribir librerías al “estilo Arduino”. Algunas de estas prácticas van en contra de la programación programación profesional, pero esto hace posible a los principiantes comenzar a trabajar de forma sencilla con Arduino.

  • Se amable con el usuario. Tener una modelo claro del concepto que va tratar la librería y las funciones que se van a implementar.
  • Organizar las funciones pública alrededor de los datos y funcionalidades que el usuario quiere. Frecuentemente el conjunto de comandos para un módulo electrónico son demasiado complicado, pero podemos reorganizar las funciones desde un punto de vista de uso a alto nivel. Pensar en lo que hace la mayoría de las personas y organizar la API en función de ese uso. Un ejemplo es la librería https://github.com/adafruit/Adafruit-BMP085-Library. La función readPressure() hace todos los pasos para obtener la presión final, siendo transparente para el usuario todos los complejos pasos intermedios. Esto abstrae al usuario no solo de los comandos I2C necesarios, sino de de los cálculos intermedios.
  • Usar palabras claras para escribir la librerías. Usar nombres de funciones y variables claros que expresen claramente lo que son o hacen y no usar términos técnicos.
  • Evitar palabras que tengan diferente significado para el público en general.
  • Documentar todo. Al escribir ejemplos usar esta guía: http://www.arduino.cc/en/Reference/StyleGuide
  • Usar las librerías del core de Arduino y su estilo:
    • Usar read() para leer entradas y write() para escribir salidas
    • Usar las librerías Stream.h y print.h cuando se estén manejando byte streams. Si no es posible al menos intentar usar su modelo de API.
    • Para aplicaciones de redes, usar las librerías de Client y Server como base.
    • Usar begin() para inicializar unas instancia de una librería, normalmente con unos parámetros de configuración. Usar end() para finalizarla.
  • Usar funciones camel case, no con guión bajo. Por ejemplo analogRead en lugar de analog_read. Esto es una adopción de processing por motivos de facilidad la lectura.
  • No usar nombre de constantes largos que son difíciles de leer.
  • Evitar usar argumentos booleanos. En su lugar es preferible ofrecer dos funciones diferentes con nombres que describan la diferencia entre ellas.
  • No asumir conocimiento de punteros. Los principiantes en C suelen encontrar dificultades con el uso de & y *, en la medida de lo posible tratar de evitar el uso de punteros.
  • Al usar la comunicación serie de cualquier tipo, permitir al usuario especificar el objeto de stream en lugar de solo “Serial”, esto hará la librería compatible con los los puertos del Arduino Mega y Due y también poder usar interfaces alternativos como el SoftwareSerial. ver el uso de begin(Stream &serial) en las librerías https://github.com/firmata/arduino y https://github.com/andrewrapp/xbee-arduino
  • Cuando se escriba una librería que ofrezca comunicación byte-stream heredada de la la clase Stream de Arduino, de forma que la librería pueda ser usada por otras librerías que acepte objetos Stream: si es posible, el método read() inmediatamente accede a los datos del buffer sin esperar a que lleguen más datos y si es posible el método write() debe guardar los datos al buffer de transmisión, pero debe esperar si el buffer no tiene suficiente espacio para guardar inmediatamente todo los datos salientes. La función yield() debe llamarse mientras se espera. De esta forma mantenemos compatibilidad con el restos de librerías Stream.

Unos ejemplos de librerías que definen realmente bien las funciones de alto nivel son:

Viendo los métodos públicos que definen es muy fácil entender que es lo que hacen.

Otro buen ejemplo de abstracción de la librerías wire (I2C) se puede ver en: https://github.com/adafruit/RTClib donde con una serie de métodos obtengo los datos del RTC siendo totalmente transparente para el usuario el uso de la librería wire.

Es frecuente que nos encontremos que algunas librerías se quedan cortas para algunas funcionalidades avanzadas, puesto que como se ha visto en la guía de estilo se tiende a simplificar. Un ejemplo de esto es la librería ethernet donde muchas de las funcionalidades del Wiznet 5100 no están implementadas en la librería, pero esto no impide que nosotros podamos añadirlas.

Más información: https://www.arduino.cc/en/Reference/APIStyleGuide

Modificar librerías

Es habitual que al usar una librería necesitemos una propiedad o un método que no esté implementado o queramos modificar el comportamiento, para ello podemos modificar localmente la librería que tengamos instalada en nuestro IDE.

En el caso que queramos colaborar en una librería hecha, podemos hacer un fork de esa librería en nuestra cuenta de github y añadir una nueva funcionalidad o corregir ese fallo e incluso podemos hacer un pull request para que se añada en la librería original nuestra modificación. También podemos tener nuestra propia librería como un fork de la librería original.

Un pull request es una petición que el propietario de un fork de un repositorio hace al propietario del repositorio original para que este último incorpore los commits que están en el fork. Explicación de pull request: http://aprendegit.com/que-es-un-pull-request/

Para modificar la librería time y añadir una funcionalidad, lo primero es hacer un fork del código https://github.com/PaulStoffregen/Time en tu repositorio, en mi caso en https://github.com/jecrespo/Time y luego clonarlo en el ordenador para modificarlo.

Ejercicios Librerías

Modificar Librería Ethernet

Ver como averiguar la IP de quien se ha conectado y  modificar librería ethernet para implementar un método que de devuelva la IP de origen.

Librería ethernet modificada en https://github.com/jecrespo/Aprendiendo-Arduino/tree/master/Otros/Ethernet%20Modificada

Crear una librería para NTP

Ejercicio: A partir del ejemplo de Arduino para obtener la hora de un servidor NTP https://www.arduino.cc/en/Tutorial/UdpNtpClient, crear una librería para obtener de forma sencilla la hora con una llamada a la función readNTP().

Ver Ejercicio39-NTP para obtener fecha y hora en Arduino sin necesidad de un RTC usando NTP: https://github.com/jecrespo/Aprendiendo-Arduino/tree/master/Ejercicio39-NTP

Basado en:

Protocolo:

Las firmas de tiempo que se usan en NTP, son de 32 bits indicando la parte entera en segundos desde  el 1 de Enero de 1900, y una parte fraccionaria también de 32 bits. Por ello la resolución teórica de NTP sería de 232 segundos =136 años, y una resolución teórica de 2E-32 segundos, o sea 0,233 nanosegundos.

Nota: Ojo al llamar al constructor de algo p.e. ethernet sin hacer el begin ethernet antes.

Solución: https://github.com/jecrespo/simpleNTP  

2 comentarios en “Librerías Arduino

    1. jecrespom Autor

      Así es, he traducido (no literalmente) la página https://www.arduino.cc/en/Hacking/LibraryTutorial puesto que creo que explica muy bien el proceso, pero primero introduzco el manejo de varias librerías explicando como están construidas para luego aprender a hacer una librería con el ejemplo que propone la web oficial de Arduino y para acabar propongo unos ejercicios.

      Esta web es parte del curso avanzado de arduino http://www.aprendiendoarduino.com/arduino-avanzado-2016/ y este post es parte de la documentación y del material de apoyo, lógicamente en el curso se hacen explicaciones adicionales y demostraciones.

      Si necesitas alguna explicación adicional de como usar o construir una librería, puedes mandarme un correo a aprendiendoarduino@gmail.com con tus dudas y te las resuelvo con mucho gusto, de paso amplio este post con las dudas que tengas para aclarar más este capítulo del curso.

      Le gusta a 2 personas

      Responder

Deja un comentario

Este sitio utiliza Akismet para reducir el spam. Conoce cómo se procesan los datos de tus comentarios.