Librerías

Lo que realmente hace muy versátil al Arduino es que su entorno se puede ampliar mediante el uso de librerías, al igual que la mayoría de las plataformas de programación. Una librerías proporcionan una funcionalidad adicional para usar en el Arduino, por ejemplo: trabajar con algún modulo (hardware especifico) o manipular datos. Para usar una librería selecciónela desde el IDE y dele a Importar librería. Las librerías mas comunes ya vienen instaladas con el IDE, pero Ud puede descargar mas librerías desde el repositorio oficial que tiene 1529 librerías (18-MAY-2017) y puedes encontrar algunas referencias de uso en referencias de librerías, la comunidad que lo soporte o crear las suyas propias.

Arduino = hardware + software + comunidad

1. Time

La librería Time.h

Métodos Time
MétodoDescripción
year()Año de 4 dígitos, 2018
month()Mes del año (1~12)
day()Dia del mes (1~31)
weekday()Dia de la semana. 1 = sábado
hour()Horas (0~23)
minute()Minutos (0~59)
second()Segundos (0~59)
hourFormat12()Formatea la hora en 0~12
isAM()Verdadero y es AM
isPM()Verdadero si es PM
now()Hora unix actual en segundos. Desde 1-ENE-1970.
time_t t = now(); //Guarda la hora actual Unix
hour(t); //Da los horas
minute(t); //Da los minutos
second(t); //Da los segundos
Funciones para usar en print()
FuncionDescripción
monthStr()Mes del año (1~12)
monthShortStr()Mes del año (1~12)
dayStr()Dia del mes (1~31)
dayShortStr()Dia del mes (1~31)
setTime()Establece fecha
adjustTime()Ajusta fecha
timeStatus()Indica si la hora esta puesta
setSyncProvider(getTimeFunction)Pone un proveedor externo
setSyncInterval(seg)Intervalo entre re-sincronizaciones.
time_t t = now(); //Guarda la hora actual Unix
monthStr(t); //No funciona
monthStr(month(t)); //Si funciona
dayStr(weekday(t)); //Si funciona
setTime(22,30,00,14,07,2018);

Las posibles respuestas de timeStatus() son: timeNotSet (1-ENE-1970, no disponible); timeNeedSync la hora debe ser sincronizada y timeSet.

if (timeStatus() == timeNotSet){
	Serial.println("Esperando para sincronizar");
}else{
	Serial.print(hour());
	Serial.print(":");
	Serial.print(minute());
	Serial.print(":");
	Serial.println(second());
}

2. RTC sin hardware

La librería RTClib.h permite simular fecha & hora mediante un estimado partiendo de la hora de inicio de Arduino y sumando los millis() transcurridos. No requiere hardware adicional.

#include <Wire.h>
#include <RTClib.h>

RTC_Millis rtc;

void setup () {
    Serial.begin(57600);
    //Toma como referencia de fecha & hora de compilacion
    rtc.begin(DateTime(F(__DATE__), F(__TIME__)));
    //11 de marzo del 2018 a las 7 pm
    //rtc.adjust(DateTime(2018, 3, 11, 17, 0, 0));
}

void loop () {
    DateTime hoy = rtc.now();
    Serial.print(hoy.year(), DEC);
    Serial.print('-');
    p2dig(hoy.month());
    Serial.print('-');
    p2dig(hoy.day());
    Serial.print(' ');
    p2dig(hoy.hour());
    Serial.print(':');
    p2dig(hoy.minute());
    Serial.print(':');
    p2dig(hoy.second());
    Serial.print('.');
    p3dig(millis()%1000);
    Serial.println();   
    delay(1500);
}

//Funcion para imprimir siempre 2 digitos
void p2dig(int num) {
  if (num < 10) {
     Serial.print('0');
  }
  Serial.print(num);
}

//Funcion para imprimir siempre 2 digitos
void p3dig(int num) {
  if (num < 100) {
     Serial.print('0');
     if (num < 10) {
        Serial.print('0');
     }
  }
  Serial.print(num);
}

3. NTP cliente

La libreria NTPClient.h esta GitHub permite controlar que un Arduino mediante una conexion: ethernet o WiFi, consulte un servidor horario como ntp.org. Por omision se conecta al servidor "time.nist.gov" cada 60 segundos sin cambio de zona horaria.

NTPClient timeClient(ntpUDP, "pe.pool.ntp.org", -18000, 86400); //Servidor, Zona (-5 hr), intervalo (diario)
Métodos NTPClient
MétodoDescripción
begin()Inicia servicio
setTimeOffset()Cambiar la zona horaria (segundos)
setUpdateInterval()Cambiar el intervalo de actualización (segundos)
update()Hace una actualización y da TRUE si lo logra
forceUpdate()Fuerza una actualización y da TRUE si lo logra
getDay()Dia de la semana 0=domingo
getHours()Horas
getMinutes()Minutos
getSeconds()Segundos/td>
getFormattedTime()Cadena h:m:s
getEpochTime()UnixTimeStamp, segundos desde 1970.
end()Finaliza servicio
#include <ESP8266WiFi.h>
#include <NTPClient.h>
#include <WiFiUdp.h>

const char *ssid     = "<SSID>";
const char *password = "<CLAVE>";

WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP);
//NTPClient timeClient(ntpUDP, "pe.pool.ntp.org", -18000, 86400);

void setup(){
   Serial.begin(115200);
   WiFi.begin(ssid, password);
   Serial.println("");
   Serial.print("WiFi");
   while (WiFi.status() != WL_CONNECTED) {
      delay(1000);
      Serial.print(".");
   }
   Serial.println("");
   Serial.print("IP: ");
   Serial.println(WiFi.localIP());
   timeClient.begin();
   Serial.print("NTP");
   while (!timeClient.update()){
      Serial.print(".");   
      delay(500);
   }
   Serial.println("");   
}

void loop() {
   Serial.println(timeClient.getFormattedTime());
   delay(1000);
}

4. Wire

La librería Wire.h permite la comunicación entre dispositivos o sensores conectados a través del bus de interfaz de dos hilos I2C. En Arduino UNO R3, la SDA (línea de datos) es pin A4 y SCL (línea de reloj) es pin A5.

A partir de Arduino 1.0, la biblioteca hereda de las funciones Stream, lo que la hace compatible con otras bibliotecas de lectura/escritura. Debido a esto, send() y receive() han sido reemplazados por read() y write().

Hay versiones de 7 y 8 bits de direcciones I2C. 7 bits identifican el dispositivo, y el octavo bit determina si se está escribiendo o leyendo. La biblioteca Wire usa direcciones de 7 bits en todo momento. Si tiene una hoja de datos o un código de muestra que usa una dirección de 8 bits, querrá soltar el bit bajo (es decir, desplazar el valor un bit hacia la derecha), obteniendo una dirección entre 0 y 127. Sin embargo, las direcciones de 0 a 7 no se usan porque están reservados, por lo que la primera dirección que se puede usar es 8. Tenga en cuenta que se necesita una resistencia de pull-up al conectar los pines SDA/SCL.

La biblioteca Wire usa un búfer de 32 bytes, por lo tanto, cualquier comunicación debe estar dentro de este límite. El exceso de bytes en una sola transmisión simplemente se eliminará.

5. SPI

La librería SPI.h permite comunicarse via Bus SPI (Serial Peripheral Interface), con el Arduino como dispositivo maestro.

SPI es un protocolo de datos en serie sincronía usado por los uC para comunicarse rápidamente con uno o más dispositivos periféricos en distancias cortas. También se puede usar para la comunicación entre dos uP. Con una conexión SPI, siempre hay un dispositivo maestro (generalmente un uP) que controla los dispositivos periféricos. Normalmente, hay tres líneas comunes a todos los dispositivos:

Características SPI
NombreDescripciónPin Arduino
MISOLa línea esclava para enviar datos al maestro. (Master In Slave Out)12 o ICSP-1
MOSILa línea maestro para enviar datos a los periféricos. (Master Out Slave In)11 o ICSP-4
SCKLos pulsos de reloj que sincronizan la transmisión de datos generada por el maestro. (Serial Clock)13 o ICSP-3
SSPin en cada dispositivo que el maestro puede usar para habilitar y deshabilitar dispositivos específicos. (Slave Select)10

Cuando el pin de SS de un dispositivo está LOW, se comunica con el maestro. Cuando es HIGH, ignora al maestro. Esto le permite tener múltiples dispositivos SPI compartiendo las mismas líneas MISO, MOSI y CLK, pero comunicarse solo con uno la la vez. Con la mayoría de los dispositivos SPI, después SPI.beginTransaction(), escribirá el pin SS a LOW, invoque SPI.transfer() las veces que necesite para transferir datos, luego escriba el pin SS a HIGH y finalmente llamará SPI.endTransaction() para liberar SPI.

SPI.beginTransaction(SPISettings(14000000, MSBFIRST, SPI_MODE0));
SPI.transfer()
SPI.endTransaction()

6. Protocolo Firmata

La librería Firmata.h permite la comunicación con aplicaciones informáticas usando un protocolo serie estándar. La librería Firmata implementa el protocolo Firmata para comunicarse con el software en una computadora host. Esto le permite escribir firmware personalizado sin tener que crear su propio protocolo y objetos para el entorno de programación que está usando. Para saber mas de Firmata.

Windows 10 implementa el protocolo Firmata de forma nativa.

  1. Cargue librería Firmata en su Arduino
  2. Crea un proyecto o usa un proyecto de muestra
  3. Elige un método de conexión serie: USB, Bluetooth, Ethernet o WiFi.
  4. Verifique en package.appxmanifest que su Windows 10 contiene las capacidades necesarias del dispositivo.
  5. Empiza a escribir tu código de Arduino remoto.

7. Remote wiring

La librería ???.h esta librería permite controlar un Arduino (Uno, Leonard o Mega) mediante una conexion: USB, bluetooth, ethernet o WiFi. Esta librería se apoya en el protocolo Firmata. Existe una aplicación llamada Universal Windows Arduino (UWA) que permite explorar las funcionalidades GPIO, analog y PWM desde cualquier dispositivo ejecutando Windows 10.

8. PID

Un controlador Proporcional Integral Derivativo PID calcula un valor de 'error' como la diferencia entre una entrada [Input] medida y un punto de referencia [setPoint] deseado. El controlador intenta minimizar el error ajustando la salida [Output]. La librería PID_v1.h requiere de tres paramentos kp, ki y kd.

Existe una libreria PID Autotune que te puede ayudar a elegir los parámetros de ganancia: kp (proporcional), ki (integral) y kd (derivada).

PID(&Input, &Output, &Setpoint, Kp, Ki, Kd, Direction);

Aunque un controlador PID está diseñado para funcionar con una salida analógica, es posible conectarlo a una salida didital, como un relé. En este caso se debe definir un ciclo de trabajo y lo que hace el PID en establecer la proporcion entre HIGH y LOW mediante los metodos: SetSampleTime(ciclo) y SetAoutputLimits(min,max)

Métodos PID
MétodoDescripción
Computer()Calcula una nueva salida cada ciclo. Responde verdadero si se calculo.
SetMode(modo)Especifica si PID esta AUTOMATIC o MANUAL
SetOutputLimits(min,max)Especifica el rango de salida
SetSampleTime(ciclo)Determina el ciclo, predetreminado es 200 ms
SetTunings(kp,ki,kd)Permite reajustar los parámetros iniciales de reaccion del PID
SetControlDirection(dirección)Especifica si la salida es DIRECT o REVERSE.

8.1 Ejemplo basico PID

Lectura de entrada analogica A0 para controlar salida analogica PWM D3

#include <PID_v1.h>
float Input, Output, Setpoint;
PID miPID(&Input, &Output, &Setpoint, 2, 5, 1, DIRECT);

void setup(){
   Setpoint = 100;
   miPID.SetMode(AUTOMATIC);
}

void loop(){
   Input = analogRead(0);
   miPID.Compute();
   //Señal PWM
   analogWrite(3,Output);
}

8.2 Salida de rele PID

Lectura de entrada analogica A0 para controlar salida digital D6 con un ciclo de trabajo de 5 segundos. Por eso se establece la salida del PID entre 0 y 5 segundos de modo que el PID ajustara el % de tiempo que el rele esta activado durante cada ciclo.

#include <PID_v1.h>

float Input, Output, Setpoint;
PID miPID(&Input, &Output, &Setpoint, 2, 5, 1, DIRECT);
int ciclo = 5000;
unsigned long StartTime, now;

void setup(){
   pinMode(6, OUTPUT);
   Setpoint = 100;
   miPID.SetOutputLimits(0, ciclo);
   miPID.SetMode(AUTOMATIC);
   StartTime = millis();
}

void loop(){
   now = millis();
   if (now - StartTime > ciclo){
      StartTime += ciclo;
   }
   Input = analogRead(0);
   miPID.Compute();
   if (Output > now - StartTime){
      digitalWrite(6, HIGH);
	}else{
  	   digitalWrite(6, LOW);
	}
}

8.3 Seteo adaptable

Uno de los beneficios de la esta libreria es que se puedes cambiar los parámetros de ajuste (kp, ki, kd) en cualquier momento. Esto puede ser útil si queremos que el PID sea agresivo algunas veces y conservador en otros.

#include <PID_v1.h>

float Input, Output, Setpoint;
float aggKp=4, aggKi=0.2, aggKd=1;  //PID agresivo
float consKp=1, consKi=0.05, consKd=0.25;  //PID conservador
PID miPID(&Input, &Output, &Setpoint, consKp, consKi, consKd, DIRECT);

void setup(){
   pinMode(3, OUTPUT);
   Setpoint = 100;
   miPID.SetMode(AUTOMATIC);
}

void loop(){
   Input = analogRead(0);
   double gap = abs(Setpoint-Input);
   if (gap<10){
      miPID.SetTunings(consKp, consKi, consKd);
   }else{
      miPID.SetTunings(aggKp, aggKi, aggKd);
   }
   miPID.Compute();
   //Señal PWM
   analogWrite(3,Output);
}

8.4 Proporcional a la medida

Configurar el PID para usar P_ON_M hacer que la salida se mueva más suavemente cuando el punto de ajuste (Setpoint) está cambiado. Además, puede eliminar el sobrepico en ciertos procesos. Las opciones son: P_ON_M (Proportional ON Measurement) y P-ON_E (Proportional ON Err).

#include <PID_v1.h>

float Input, Output, Setpoint;
PID miPID(&Input, &Output, &Setpoint, 2, 5, 1, P_ON_M, DIRECT);

void setup(){
   pinMode(3, OUTPUT);
   Setpoint = 100;
   miPID.SetMode(AUTOMATIC);
}

void loop(){
   Input = analogRead(0);
   miPID.Compute();
   //Señal PWM
   analogWrite(3, Output);
}