Una forma sencilla de realizar secuencias.

Una forma sencilla de realizar secuencias.

En el foro una de las dudas que mas abunda es como un realizar una secuencia basada en tiempo. Estás secuencias generalmente son del tipo: durante un tiempo enciende/apaga algo, luego durante otro tiempo apaga/encienda algo y así sucesivamente.

La primera solución que le viene a uno es el uso de delay, que en un principio funciona, pero cuando queremos interactuar con la secuencia, por ejemplo pararla, o cuando queremos hacer otra cosa mientras está actuando la secuencia no podemos. Recordar que delay es bloqueante y por lo tanto, si la secuencia es larga arduino no hará otra cosa.

Por eso conviene usar millis.

Recomiendo la lectura de mis tutoriales anteriores para una mejor comprensión de lo que vamos a ver en este tutorial:

El primer paso a tener en consideración es tener claro la secuencia, sus pasos y sus tiempos.

Voy a poner un ejemplo sencillo: el parpadeo de un led. Ya sé que en este caso está el ejemplo del IDE y es demasiado fácil, aunque hay gente que aun no sabe como funciona, así que a los tutoriales anteriores me remito.

En el caso de parpadeo la secuencia es: enciendo un led un segundo y lo apago durante otro segundo.

En este caso los pasos son dos:

paso 0: encender el led.
paso 1: apagar el led.

Y los tiempo son:

paso 0: 1000 ms.
paso 1: 1000 ms.

Asi que la idea es usar una variable "paso" para ver en que lugar de la secuencia estamos. Igualmente para cada paso tendrá que hacer algo, así que habrá que crear una funcion pasoX que haga lo que queremos. Y por ultimo en un array guardaremos el tiempo de cada paso.

/*
 * Ejemplo de secuencia de parpado de un led.
 * 
 * Sobre si 0 o 1. Dado que en programación el primer número es el 0, el paso cero será
 * el primer paso, no os confundais con la numeración, contar 0, 1, 2, 3...
 */
const int numPasos = 2;

int paso;
unsigned long tiempos[numPasos] = { 1000, 1000 }; // El array lo crearemos con tantos pasos como haya.
unsigned long t; // Esta será nuestra variable de tiempo.

// La función que hará en el primer paso.
void paso0() {
  digitalWrite(13, HIGH);
}
// La función que hará en el primer paso.
void paso1() {
  digitalWrite(13, LOW);
}

 void setup() {
   pinMode(13, OUTPUT); // Led de la placa.
   // Iniciamos la secuencia.
   paso=0;
   paso0();
 }

 void loop() {
   // Comprobamos si el temporizador actual ha sobrepasado el tiempo del paso actual.
   if ( millis() - t > tiempos[paso] ) {
     t = millis(); // Guardamos el tiempo.
     paso++; // Incrementamos el paso.
     if ( paso==numPasos ) paso = 0; // Cambiamos al primer paso.
     switch ( paso ) {
       case 0: paso0(); break;
       case 1: paso1(); break;
       default: break;
     }
   }
 }

¿Qué pasa si queremos más pasos? Primero cambiar la variable de numPasos al número de pasos. Tendremos que incrementar el tamañó del array de tiempos, añadiendo los nuevos tiempos de la secuencia. Crearemos las funciones pasoX necesarias. Por último en la sentencia switch añadiremos los case pertinentes.

Ahora que ya sabemos como realizar la secuencia vamos a controlarla.

Por ejemplo queremos que cuando apretemos un botón el led parpadee. Y que cuando lo volvamos a apretar se pare.

Como dije en el post anterior, me basaré en la libreria BotonSimple para leer el botón (no pretenderéis que explique una cosa encima de otra).

La idea consiste en utilizar una variable para ver si estamos ejecutando la secuencia o no. En este caso podemos utilizar la variable paso y ponerla a un valor distinto a los pasos, por ejemplo -1, y comprobamos que si la variable es distinta a ese valor podamos ejecutar la secuencia.

He aquí el código:

/*
 * Ejemplo de secuencia de parpado de un led controlada por botón.
 * 
 * Sobre si 0 o 1. Dado que en programación el primer número es el 0, el paso cero será
 * el primer paso, no os confundais con la numeración, contar 0, 1, 2, 3...
 */

#include <BotonSimple.h>
const int numPasos = 2;

int paso;
unsigned long tiempos[numPasos] = { 1000, 1000 }; // El array lo crearemos con tantos pasos como haya.
unsigned long t; // Esta será nuestra variable de tiempo.

BotonSimple boton(2); // Conecto un pulsador en el pin 2.

// La función que hará en el primer paso.
void paso0() {
  digitalWrite(13, HIGH);
}
// La función que hará en el primer paso.
void paso1() {
  digitalWrite(13, LOW);
}

void setup() {
  pinMode(13, OUTPUT); // Led de la placa.
  // Iniciamos la secuencia a -1 por lo que no hará comprobación de tiempos y no ejecutará la secuencia.
  paso = -1;
}

void loop() {
  // Para leer el botón hay que actualizar.
  boton.actualizar();
  // Comprobamos si el temporizador actual ha sobrepasado el tiempo del paso actual.
  if ( paso!=-1 ) {
    if ( millis() - t > tiempos[paso] ) {
      t = millis(); // Guardamos el tiempo.
      paso++; // Incrementamos el paso.
      if ( paso==numPasos ) paso = 0; // Cambiamos al primer paso.
      switch ( paso ) {
        case 0: paso0(); break;
        case 1: paso1(); break;
        default: break;
      }
    }
  }
// Comprobamos el boton.
  if ( boton.leer()==SOLTANDOLO ) {
    // Si paso valo -1 significa que está parada la secuencia. La iniciamos al paso que queramos
    // y ejecutamos su funcion pasoX.
    if ( paso==-1 ) {
      paso = 0;
      paso0();
    }
    // Si estamos en un paso y queremos pararma solo debemos poner la secuencia en -1 y se detendrá
    // la secuencia.
    else {
      paso=-1;
      // Como no sabemos en que estado se queda el led lo apagamos.
      digitalWrite(13, LOW);
    }
  }
}

Hasta aquí creo que es fácil de entender. Pronto haré una libreria al igual que hice con los botones, para que podais hacer secuencias de manera más comoda.

SimpleSequencer

SimpleSequencer es una librería para Arduino para generar secuencias simples, del tipo apagado/encendido durante un tiempo.

Forma parte del tutorial Una forma sencilla de realizar secuencias. del foro de Arduino es español.

Uso básico.

Crea un objeto de la clase SimpleSequencer indicando el número de pasos de la secuencia.

SimpleSequencer secuencia(numPasos);

Crear las funciones que se ejecutaran en cada paso. Deben ser del tipo void sin parametros:

void funcionPaso0() {

}

Añadir los pasos al objeto creado anteriormente indicando el número de paso, el tiempo, y la función que se ha de ejecutar en cada paso:

secuencia.setStep(paso0, tiempo0, funcion0);
secuencia.setStep(paso1, tiempo1, funcion1);
...
secuencia.setStep(pasoN, tiempoN, funcionN);

Iniciar la secuencia llamando a la función start. Podemos parar la secuencia llamando a la función stop.

Opcionalmente podemos realizar alguna acción al iniciar o parar la secuencia. Para ello contamos con las funciones setOnStart y setOnStop

Dejo la libreria como attachment.

Tambien podéis descargarla desde Github

Dentro de la libreria hay un par de ejemplos para su uso.
.

SimpleSequencer.zip (3.91 KB)