Características
Almacenamiento de datos
Una cola puede almacenar un número infinito de datos o un número fijo.
El número máximo de datos se llama "length".
La longitud y el tamaño de cada dato se define al crear la cola.
Normalmente, se realizan las colas con memoriras FIFO.
Escribir en la cola provoca una copia byte a byte y, al leer, la copia del dato que se elimina.
Acceso a múltiples tareas
Las colas son objetos independientes, no están asignadas a ninguna tarea.
Cualquier tarea puede leer y escribir en las colas aunque, lo normal, es que muchas tareas lean un cola y una escriba.
Bloqueo de lectura
Se puede bloquear la lectura de una cola para que las tareas no puedan leerla durante un periodo de tiempo. Este es el periodo en el que la tarea debe de estar en estado Blocked, hasta que la cola vuelva a estar vacía.
En cuanto que una tarea manda un dato a la cola, la tarea que estaba en estado Blocked pasa a Running.
Como las colas pueden tener múltiples usuarios, pueden mantener varias tareas en Blocked hasta que se escriba un dato.
Bloqueo de escritura
Como en la lectura, se puede bloquear la escritura en un periodo de tiempo. En este caso, el tiempo máximo que la tarea va a tener que esperar es el que tarde la cola en tener espacio libre y será hasta que se vuelva a llenar.
Al igual que en la lectura, las colas pueden tener varios usuarios, por lo que pueden mantener varias tareas bloqueadas.
Uso de Colas
Función xQueueCreate()
Las colas se tienen que crear antes de poder usarse.
Las colas se identifican por el tipo de variable xQueueHandle. xQueueCreate() se usa para creat la cola y devuelve la referencia a xQueueHandle.
FreeRTOS aloja en la RAM de la pila del mismo. En la RAM se almacena todo, la estructura y los datos.
xQueueCreate() devuelve un NULL si no tiene suficiente RAM.
xQueueHandle xQueueCreate( usigned portBASE_TYPE uxQueueLength, unsigned portBASE_TYPE uxItemSize);
- uxQueueLength el número máximo de datos que la cola puede almacenar
- uxItemSize el tamaño en bytes de cada item de la cola
- return Value si es Null la cola no se ha creado. Un valor distinto de Null indica que se ha creado la cola.
Las funciones xQueueSendToBack() y xQueueSendToFront()
xQueueSendToBack() se usa para mandar el dato al final de la cola y xQueueSendToFront para mandarlo al principio de la cola.
xQueueSend() es lo mimos que xQueueSendToBack().
Hay que tener en cuenta que estas funciones no sirven para interrupciones.
portBASE_TYPE xQueueSendToFront ( xQueueHandle xQueue, const void * pvItemToQueue, portTickType xTicksToWait);
portBASE_TYPE xQueueSendToBack ( xQueueHandle xQueue, const void * pvItemToQueue, portTickType xTicksToWait);
- xQueue el enlace de la cola. Es el valor que devuelve xQueueCreate().
- pvItemToQueue puntero al dato que vamos a copiar.
- xTicksToWait el número de tiempo máximo que la tarea tiene que estar en estado Blocked para que la cola esté disponible.
Ambas funciones devuelven un 0 si la cola está llena.
el tiempo se da en ticks, si se quiere en ms hay que dividir por portTICK_RATE_MS.
Si igualamos xTicksToWait a portMAX_DELAY provocamos que la tarea espere eternamente, para ello tenemos que activar INCLUDE_vTaskSuspend en FreeRTOSConfig.h.
return Value:
- pdPASS. Si el dato se ha mandado satisfactoriamente a la cola.
Puede ocurrir que si se ha seleccionado un tiempo de bloqueo (xTicksToWait es disinto de cero), los datos se hayan almacenado antes de que termine el temporizador. - errQUEUE_FULL. Si el dato no se ha podido almacenar porque la cola está llena.
Puede ocurrir que si se ha seleccionado un tiempo de bloqueo (xTicksToWait es disinto de cero), los datos se hayan almacenado antes de que termine el temporizador.
Funciones xQueueRecieve() and xQueuePeek()
xQueueRecieve() se usa para recibir un item de una cola, se elimina una vez recibido.
xQueuePeek() se usa para recibir un item de una cola sin eliminarse.
No se pueden usar estas funciones para trabajar con interrupciones.
portBASE_TYPE xQueueRecieve( xQueueHandle xQueue, const void * pvBuffer, portTickType xTicksToWait);
portBASE_TYPE xQueuePeek( xQueueHandle xQueue, const void * pvBuffer, portTickType xTicksToWait);
- xQueue el enlace de la cola. Es el valor que devuelve xQueueCreate().
- pvBuffer puntero a la memoria donde se va a copiar el dato.
- xTicksToWait el número de tiempo máximo que la tarea tiene que estar en estado Blocked para que la cola esté disponible.
ambas funciones devuelven un 0 si la cola está llena.
Si es cero, hay un retorno inmediato.
el tiempo se da en ticks, si se quiere en ms hay que dividir por portTICK_RATE_MS.
return Value:
- pdPASS. Si el dato se ha leído satisfactoriamente el dato.
Puede ocurrir que si se ha seleccionado un tiempo de bloqueo (xTicksToWait es disinto de cero), los datos se hayan almacenado antes de que termine el temporizador. - errQUEUE_FULL. Si el dato no se ha podido leer porque la cola está vacía.
Puede ocurrir que si se ha seleccionado un tiempo de bloqueo (xTicksToWait es disinto de cero), los datos se hayan almacenado antes de que termine el temporizador.
Función uxQueueMessagesWaiting()
uxQueueMessagesWaiting() se usa para averiguar el número de datos que tiene una cola.
No usar esta función para trabajar con interrupciones.
unsigned portBASE_TYPE uxQueueMessagesWaiting( xQueueHandle xQueue);
- xQueue el enlace de la cola. Es el valor que devuelve xQueueCreate().
- pvBuffer puntero a la memoria donde se va a copiar el dato.
- return Value: el número de datos que contiene la cola.
Trabajando con datos grandes
Si el tamaño de los datos es muy grande, es mejor trabajar con punteros almacenados en la cola.
Al trabajar con punteros en las colas hay que tener en cuenta:
- Definir bien el propietario de la RAM para que otra tarea no modifique datos.
- Que el puntero sea válido y no se vaya a excepción.