Fork me on GitHub

Cola circular en Arduino usando clases

August 2, 2015

Aquí va un sencillo ejemplo de implementación de una cola circular para Arduino usando clases al estilo C++. Para compilar y subir el código final usaremos inotool en lugar del IDE oficial de Arduino. Comenzamos entonces haciendo

$ ino init

Esto crea la siguiente estructura

$ tree
.
├── lib
└── src
    └── sketch.ino

sketch.ino es el sketch propio de Arduino, donde irán el setup() y el loop(). Dentro del directorio lib crearemos nuestra librería Queue que contendrá los archivos .h y .cpp correspondientes

$ tree
.
├── lib
│   └── Queue
│       ├── Queue.cpp
│       └── Queue.h
└── src
    └── sketch.ino

Para la cola usaremos un array de enteros sin signo de 8 bits (uint8_t). Definiremos la longitud del array en el setup. Veamos entonces Queue.h para tener un parnorama de los métodos y propiedades de nuestra clase

En los métodos públicos tenemos begin() que crea el array del tamaño especificado, para lo cual recibe un entero sin signo de 16 bits (uint16_t). Luego tenemos los clásicos put(), get(), isEmpty() e isFull().

En la parte privada tenemos un puntero al array queue, el tamaño del mismo, y los índices iPut e iGet que necesitamos para conocer el estado actual. El funcionamiento de los índices es el siguiente: iPut contiene la posición en la cual insertaremos el siguiente elemento, mientras que iGet contiene la posición del primer elemento ingresado, es decir el más viejo.

Suponiendo que creamos una cola de tamaño 3 luego de inicializarla el estado de los índices será

iPut = 0, iGet = -1  <--  empty (iGet == -1)

Agrego un elemento

iPut = 1, iGet = 0

Agrego otro

iPut = 2, iGet = 0

Agrego otro

iPut = 0, iGet = 0  <--  full (iPut == iGet)

Saco un elemento

iPut = 0, iGet = 1

Y así. El funcionamiento es bastante simple. Veamos ahora la implementación de cada método en Queue.cpp

En begin() inicializamos los índices y mediante malloc asignamos la memoria necesaria para la longitud del array.

También tenemos un método iNext() que nos servirá para obtener el valor del próximo índice: tengamos en cuenta que la cola es circular pero el array no lo es, por lo que para simular esto cuando llegamos al final tenemos que volver a empezar.

Finalmente veamos cómo queda sketch.ino

Nuestro sketch permite ingresar en la cola cualquier caracter ascii a excepción de g, que usaremos para get

Listo, ahora compilamos

$ ino build

Subimos el binario

$ ino upload

Y para probarlo entramos en la consola serial (necesitamos picocom instalado)

$ ino serial

Para la entrada A B C D E F g g g g g g la salida es

put: 65
put: 66
put: 67
put: 68
put: 69
Queue is full
get: 65
get: 66
get: 67
get: 68
get: 69
Queue is empty

Eso es todo, solo queda aclarar que el uso de isFull() es totalmente opcional, ya que una cola circular debe permitir seguir agregando elementos por el principio una vez alcanzado el final, por lo que nuestro sketch podría quedar así

if (data == 'g') {
    ...   
} else {
    Queue.put(data);
    Serial.print("put: ");
    Serial.println(data);
}

Arduino