Similar to the last example, in this Queue example, we going to use multiple Queue to send different data to a central Task.

code example:

#include "bsp.h"
#include <math.h>

#define NUMBER_OF_LEDS  8   /* Indicate the number of LEDs */
#define NONE_MESSAGES   0   /* Indicate that No messages available */
#define RESET_VALUE     0   /* Default value to Restore a Variable */ 

static void Task_LED_Selector( void *parameters );      /* Task to select LED to be control */
static void Task_LED_Control( void *parameters );       /* Task to control LED status */
static void Task_Switch_State( void *parameters );      /* Task to switch the pin state (ON / OFF) */

QueueHandle_t QueueLEDpin;          /* Queue to trasnfer data of wich Pin led control in Task Control */
QueueHandle_t QueueLEDstatus;       /* Queue to transfer the status of LED to Task Control */

int main( void )
{
    HAL_Init( );
    /*enable RTT and system view*/
    SEGGER_SYSVIEW_Conf( );
    SEGGER_SYSVIEW_Start( );

    QueueLEDpin = xQueueCreate( 8, sizeof(uint16_t) );           /* Create the Queue to store a data of 16 bits */
    QueueLEDstatus = xQueueCreate( 8, sizeof(uint16_t) );           /* Create the Queue to store a data of 16 bits */

    xTaskCreate( Task_LED_Selector, "Task_Selector", 128u, NULL, 2u, NULL );   /* Register a Task */
    xTaskCreate( Task_Switch_State, "Task_Switch", 128u, NULL, 2u, NULL );     /* Register a Task */
    xTaskCreate( Task_LED_Control, "Task_Control", 128u, NULL, 1u, NULL );     /* Register a Task */

    vTaskStartScheduler( );                                         /* initilize the kernel */

    return 0u;
}

/* Task to send to other tasks Pin LED */
static void Task_LED_Selector( void *parameters )
{
    UNUSED( parameters );
    uint16_t Led_Pin[NUMBER_OF_LEDS] = { GPIO_PIN_0, GPIO_PIN_1, GPIO_PIN_2, GPIO_PIN_3, GPIO_PIN_4, GPIO_PIN_5, GPIO_PIN_6, GPIO_PIN_7 };
    static uint8_t i = 0;    /* Iter Value to send different messages */

    for( ;; )
    {
        while( uxQueueSpacesAvailable( QueueLEDpin ) > NONE_MESSAGES ) /* Check how many spaces the Queue has */
        {
            xQueueSend( QueueLEDpin, &Led_Pin[i], 0 );     /* Send the data to Queue */
            i++;                                              /* Increment to select another data from Array */
        }
        i = RESET_VALUE;                                      /* If Queue has no space, Reset the Value */

        vTaskDelay(2000 / portTICK_PERIOD_MS);               /* Periodicity of Task */
    }
}

/* Task to control LED state */
static void Task_LED_Control( void *parameters )
{
    UNUSED( parameters );
    uint16_t PinInfo;                                      /* Variable to receive data of Task_LED_Selector */
    uint16_t PinState;                                     /* Variable to receive data of Task_Switch_State */

    for( ;; )
    {
        while ( uxQueueMessagesWaiting( QueueLEDstatus ) > NONE_MESSAGES )
        {
            xQueueReceive( QueueLEDpin, &PinInfo, 0 );          /* receive data of Task_LED_Selector */
            xQueueReceive( QueueLEDstatus, &PinState, 0 );      /* receive data of Task_Switch_State */

            HAL_GPIO_WritePin( GPIOC, PinInfo, PinState );      /* Write on Pin the State received */
            vTaskDelay(200 / portTICK_PERIOD_MS); 
            
            uint32_t res = log2(PinInfo);

            SEGGER_SYSVIEW_PrintfHost( "LED %d", res );
            SEGGER_SYSVIEW_PrintfHost( "State %d", PinState );
        }

        vTaskDelay(200 / portTICK_PERIOD_MS);               /* Periodicity of Task */
    }
}

/* Task to control the LED State */
static void Task_Switch_State( void *parameters )
{
    uint16_t Pin_Number;                                        /* Variable to receive data of Task_LED_Selector */
    uint16_t Led_State[2] = { GPIO_PIN_SET, GPIO_PIN_RESET };   /* Array to iter between states */
    static uint8_t IterState = 0;                               /* Variable to iterate the state */

    for(;;)
    {
        if(IterState > 1 )  /* Restart Iter position */
        {
            IterState = 0;
        }

        while ( uxQueueSpacesAvailable( QueueLEDpin ) < NUMBER_OF_LEDS )
        {
            xQueuePeek( QueueLEDpin, &Pin_Number, 0 );              /* Just copy The element but not remove from Queue */
            xQueueSend( QueueLEDstatus, &Led_State[IterState], 0 ); /* send the state of the current Pin */
            vTaskDelay(200 / portTICK_PERIOD_MS); 
            if(Pin_Number == GPIO_PIN_7)    /* Only change the state when the last led is reached */
            {
                IterState++;
            }
        } 

        vTaskDelay(200 / portTICK_PERIOD_MS);               /* Periodicity of Task */
    }    
}

In this application, 3 tasks are used. The first task Task_LED_Selector when is executed sends a series of pins (Pin information of each LED pin), this info is received by the 2 other tasks, Task_Switch_State Read data from the Queue QueueLEDpin but just copies the element to be processed inside the task but without removing the element from the queue, the copy is used for compare pin read with the number max of pins to change the pin state. Finally, Task_LED_Control Read two queues to process each data to set the state in the pin received.

This example is for demonstrating how to use multiple Queues and can be more efficient if we send a struct element.

SystemView Output:

Document

The LEDs behavior must be equal to the last example, but now the LED state is controlled by another task.
Terminal Shows the number of prints to be processed and the state to be changed by task Task_Control.
Observe that the State is “1“ This means that LEDs must be Turned on.

After 2 seconds task changes the LED status.
Now the state changes to “0“, LEDs must be Turned off.

TimeLine:

Document

We can observe task behavior. After initialization, the first task Task_LED_Selector starts to work, sending the data of pins to the Queue buffer to be received by the other 2 tasks.

Next, Task_Switch reads data received in the queue buffer and sends the state of 1 to turn on the LED, after that Task_Control using data received from 2 tasks, changes the state of the Pin read.

When all messages are read and elapsed 2 seconds, Task_Selector executes again, sending the same data.

Now the difference is in Task_Switch which changes the state to 0. Now task Task_Control will turn off LEDs.