FreeRTOS message queue application

Engineering link

Blocking while reading the queue

The priority of the task that sends a message to the queue is lower than the priority of the task that receives the message from the queue , which means that the number of queue items will never exceed one . Once data is sent to the queue, the task that receives the message will be unlocked and preempted Send the task and then remove the message in the queue, making the queue content empty again.

QueueHandle_t xQueue;  //声明消息队列

//发送任务
static void vSenderTask(void *pvParameters)
{
    
    
    int valuetosend;
    BaseType_t xStatus;
    const TickType_t xTicksToWait=pdMS_TO_TICKS(0);
    
    valuetosend=(int)pvParameters;
    for(;;)
    {
    
    
        xStatus=xQueueSendToBack(xQueue,&valuetosend,xTicksToWait);
    	if(xStatus!=pdPASS)
        {
    
    
        	printf("Could not send to the queue.\r\n");
   	 	}
    }
}

//接收任务
static void vReceiverTask(void *pvParameters)
{
    
    
    int ReceivedValue;
    BaseType_t xStatus;
    const TickType_t xTicksToWait=pdMS_TO_TICKS(100);
    
    for(;;)
    {
    
    
        if(uxQueueMessagesWaiting( xQueue ) != 0)
        {
    
    
            printf("Queue should have been empty!\r\n");
        }
        xStatus = xQueueReceive( xQueue, &ReceivedValue, xTicksToWait );
        if( xStatus == pdPASS )
		{
    
    
		/* Data was successfully received from the queue, print out the received value. */
			printf( "Received =%d \r\n", ReceivedValue );
		}
		else
        {
    
    
			printf( "Could not receive from the queue.\r\n" );
		}
    }
}

int main()
{
    
    
    xQueue = xQueueCreate( 5, sizeof( int));  //创建一个消息队列
    
        if(xQueue!=NULL)
        {
    
    
         /*创建两个任务,具有相同的优先级,两个任务会依次发送消息至队列*/
            xTaskCreate( vSenderTask,  //任务函数名
                        "Sender1",      //任务名
                        1000,           //任务堆栈大小
                        ( void * ) 100, //传递给任务函数的参数
                        1,              //任务优先级
                        NULL );  		//暂无任务句柄
		   xTaskCreate( vSenderTask, "Sender2", 1000, ( void * ) 200, 1, NULL );
            /*接收任务*/
            xTaskCreate( vReceiverTask, "Receiver", 1000, NULL, 2, NULL );   
            vTaskStartScheduler();  //开启任务调度
        }
    	else
        {
    
    
              printf("The Queue could not be created!\r\n");
        }
    for(;;);
    
}

Insert picture description here

  • The receiving task starts to run first because of the higher priority, but fails to read the message from the queue because the queue is empty and enters the blocking state. The sender2 sending task starts to run after the receiving task enters the blocking state.
  • sender2 sends a task to send a message to the queue, the receiving task exits the blocking state, because the receiving task has a higher priority to preempt sender2 and occupy the CPU
  • The receiving task empties the message queue and enters the blocking state again. At this time, it is sender1's turn to execute
  • sender1 sends a message to the queue, so that the receiving task exits the blocking state, and preempts sender1, clears the message queue, and repeats. . . . . .

Queue delivery structure (multiple sending sources)

When the receiver receives a message sent from multiple sources to the queue, it needs to determine the source of the data. The method of use: the queue is used to transfer the structure, and the structure contains the data value and data source information .
Insert picture description here

typedef struct
{
    
    
    int  iValue;  //数据值
    int iMeaning; //数据来源信息
}xData;

Example : The task of sending a message has a higher priority, so the queue will be full!

typedef enum   
{
    
    
    esender1,
    esender2
}DataSource_t;  //定义枚举类型变量,限定源的范围

typedef struct
{
    
    
    uint8_t ucValue,
    DataSource_t eDataSource
}Data_t;       //定义存储至队列中的结构体类型Data_t

/* 声明两个Data_t类型的变量 */
static const Data_t xStructsToSend[2]=   
{
    
    
    {
    
    100,esender1},
    {
    
    200,esender2}
};

QueueHandle_t xQueue;  //声明消息队列

//发送任务
static void vSenderTask(void *pvParameters)
{
    
    
    BaseType_t xStatus;
    const TickType_t xTicksToWait=pdMS_TO_TICKS(100);
   
    for(;;)
    {
    
    
        xStatus=xQueueSendToBack(xQueue,pvParameters,xTicksToWait);  //发送消息
    	if(xStatus!=pdPASS)  //消息发送失败
        {
    
    
        	printf("Could not send to the queue.\r\n");
   	 	}
    }
}

//接收任务
static void vReceiverTask(void *pvParameters)
{
    
    
    Data_t xReceiveStructure;
    BaseType_t xStatus;
    const TickType_t xTicksToWait=pdMS_TO_TICKS(0);
    
    for(;;)
    {
    
    
        if(uxQueueMessagesWaiting( xQueue ) != 3)
        {
    
    
            printf("Queue should have been fill!\r\n");
        }
        xStatus = xQueueReceive( xQueue, &xReceiveStructure, xTicksToWait );
        if( xStatus == pdPASS )
		{
    
    
		/* Data was successfully received from the queue, print out the received value. */
            if(xReceiveStructure.eDataSource==esender1)
            {
    
    
                printf("From sender 1=%d \r\n",xReceiveStructure.ucValue);
            }
            else
            {
    
    
                printf( "From sender 2=%d \r\n",xReceiveStructure.ucValue);
            }
			
		}
		else
        {
    
    
			printf( "Could not receive from the queue.\r\n" );
		}
    }
}

int main()
{
    
    
    xQueue = xQueueCreate( 3, sizeof( Data_t));  //创建一个消息队列
    
        if(xQueue!=NULL)
        {
    
    
         /*创建两个任务,具有相同的优先级,两个任务会依次发送消息至队列*/
            xTaskCreate( vSenderTask,  //任务函数名
                        "Sender1",      //任务名
                        1000,           //任务堆栈大小
                       (void *)&( xStructsToSend[ 0 ] ), //传递给任务函数的参数
                        2,              //任务优先级
                        NULL );  		//暂无任务句柄
		   xTaskCreate( vSenderTask, "Sender2", 1000, (void *)&( xStructsToSend[ 1] ), 2, NULL );
     
            /*接收任务*/
            xTaskCreate( vReceiverTask, "Receiver", 1000, NULL, 1, NULL );   
            vTaskStartScheduler();  //开启任务调度
        }
    	else
        {
    
    
              printf("The Queue could not be created!\r\n");
        }
    for(;;);
    
}

Insert picture description here

  • t1 sender1 task execution, send 3 messages to the queue

  • t2 The sender1 task enters the blocking state because the queue is full, and waits for the next message to be sent. At this time, the sender2 task enters the ready state because it has the highest priority.

  • The t3 sender2 task finds that the queue is full, so it enters the blocking state and waits for the first message to be sent. At this time, the receiving task becomes the highest priority task and enters the ready state

  • Both sender1 and sender2, which have a higher priority than the receiving task at t4, are waiting for free space in the queue, so once the receiving task removes a message from the queue, it will be preempted. sender1 and sender2 have the same priority, so the scheduler selects the longest waiting task sender1 into the ready state

  • t5 sender1 sends the fourth data to the queue. At this time, the queue is full, and the sender1 task enters the blocking state again. The receiving task has the highest priority and a message is removed

    At this time, sender1 has sent 4 messages to the queue, and sender2 is still waiting to send the first message to the queue.

  • T6, sender1 and sender2, which have a higher priority than the receiving task, are waiting for free space in the queue, so once the receiving task removes a message from the queue, it will be preempted. At this time, sender1 and sender2 are both waiting, and sender2 waits longer than sender1, so the scheduler selects sender2 to enter the ready state

  • t7 sender2 finally successfully sends the first message to the queue , the queue becomes full, sender2 enters the blocking state again, and the receiving task starts to execute at this time, and a message is removed

  • After that, sender1 and sender2 will be repeated to send messages to the queue in turn, so the result is as shown in the following figure, sender1 sends 4 messages before the first message of sender2

Insert picture description here

Pointer to pass data

  1. The ownership of the memory space pointed to by the pointer must be clear

The contents of shared memory can only be accessed by the sending task before its pointer is sent to the queue;

After the shared memory pointer is read from the queue, its content is only allowed to be accessed by the receiving task

  1. The memory space pointed to by the pointer must be valid

The memory space pointed to by the pointer is dynamically allocated or obtained from a pre-allocated buffer pool. Only one task should release its memory. When this memory space is released, there should be no other tasks again. Visit this space.

The pointer cannot be used to access the data allocated on the task stack space. Once the task stack space structure is changed, the data will be invalid .

/*声明一个队列句柄*/
QueueHandle_t xPointerQueue;
/*创建一个队列项为5 的存储指针地址的队列*/
xPointerQueue = xQueueCreate( 5, sizeof( char * ) );

/*任务获取缓冲区,将字符串写入缓冲区中,然后发送缓冲区的地址至创建的队列中*/
void vStringSendingTask( void *pvParameters )
{
    
    
	char *pcStringToSend;   //声明一个char*类型指针
	const size_t xMaxStringLength = 50;  //限定分配内存空间大小
    const TickType_t xTicksToWait=pdMS_TO_TICKS(100);
	BaseType_t xStringNumber = 0;
	for( ;; )
	{
    
    
		pcStringToSend = ( char * ) pvPortMalloc( xMaxStringLength ); //动态分配缓存区
		/*写字符串至缓冲区中 */
		snprintf( pcStringToSend, xMaxStringLength, "String number %d\r\n", xStringNumber );
		/* 此任务的每次迭代中字符串不同 */
		xStringNumber++;
		/*发送缓冲区的地址至队列中*/
		xQueueSend( xPointerQueue, /* 队列句柄 */
					&pcStringToSend, /* 指向缓冲区指针的地址 */
					xTicksToWait );  /*阻塞等待时间*/
	} 
}

/*任务接收队列中缓冲区的地址,*/
void vStringReceivingTask( void *pvParameters )
{
    
    
	char *pcReceivedString;
    const TickType_t xTicksToWait=pdMS_TO_TICKS(100);
	for( ;; )
	{
    
    
		/* 接收缓冲区的地址 */
		xQueueReceive( xPointerQueue, 
					  &pcReceivedString, /* 在指针pcReceiveString中存储缓冲区的地址 */
					  xTicksToWait );
		/* The buffer holds a string, print it out. */
		printf("%s", pcReceivedString );
		/* 释放内存空间 */
		vPortFree( pcReceivedString );
	}
}

int main()
{
    
    
	
		uart_init(9600);
    /*创建一个队列项为5 的存储指针地址的队列*/
		xPointerQueue = xQueueCreate( 5, sizeof( char * ) );
    
        if(xPointerQueue!=NULL)
        {
    
    
         /*创建发送任务*/
            xTaskCreate( vStringSendingTask,  //任务函数名
                        "Sender1",      //任务名
                         1000,           //任务堆栈大小
					   NULL, //传递给任务函数的参数
                         2,              //任务优先级
                         NULL );  		//暂无任务句柄
				
            /*接收任务*/
            xTaskCreate( vStringReceivingTask,
                        "Receiver", 
                        1000,
                        NULL,
                        3,
                        NULL );   
            vTaskStartScheduler();  //开启任务调度
        }
    	else
        {
    
    
              printf("The Queue could not be created!\r\n");
        }
    for(;;);
    
}

Insert picture description here

FreeRTOS above are from official documents FreeRTOS_Real_Time_Kernel
attached download the official link

Guess you like

Origin blog.csdn.net/weixin_44333597/article/details/107725480