FreeRTOSメッセージキューアプリケーション

エンジニアリングリンク

キューの読み取り中のブロック

キューにメッセージを送信するタスクの優先度は、キューからメッセージを受信するタスクの優先度よりも低くなります。つまり、キューアイテム数が1を超えることはありません。データがキューに送信されると、メッセージを受信したタスクはロックが解除され、プリエンプトされますタスクを送信してから、キュー内のメッセージを削除し、キューの内容を再び空にします。

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(;;);
    
}

ここに画像の説明を挿入

  • 優先度が高いため、受信タスクが最初に実行を開始しますが、キューが空でブロック状態になるため、キューからのメッセージの読み取りに失敗します。送信タスクは、受信タスクがブロック状態に入ると実行を開始します。
  • sender2はタスクを送信してメッセージをキューに送信し、受信タスクは送信者2をプリエンプトしてCPUを占有する優先度が高いため、受信タスクはブロッキング状態を終了します。
  • 受信タスクはメッセージキューを空にし、再びブロック状態になります。この時点で、送信者1が実行する番です。
  • sender1はメッセージをキューに送信するため、受信タスクはブロッキング状態を終了し、sender1をプリエンプトして、メッセージキューをクリアし、繰り返します。

キュー配信構造(複数の送信ソース)

受信者は、複数のソースからキューに送信されたメッセージを受信すると、データのソースを判別する必要があります。使用方法:キューは構造を転送するために使用され、構造にはデータ値とデータソース情報が含まれます
ここに画像の説明を挿入

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

:メッセージを送信するタスクの優先度が高いため、キューがいっぱいになります。

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(;;);
    
}

ここに画像の説明を挿入

  • t1 sender1タスクの実行、3つのメッセージをキューに送信します

  • t2sender1タスクはキューがいっぱいであるためブロッキング状態になり、次のメッセージが送信されるのを待ちます。このとき、sender2タスクは優先度が最も高いため準備完了状態になります。

  • t3 sender2タスクは、キューがいっぱいであることを検出したため、ブロッキング状態に入り、最初のメッセージが送信されるのを待ちます。このとき、受信タスクが最優先タスクになり、準備完了状態になります。

  • t4で受信タスクよりも優先度が高いsender1とsender2の両方がキュー内の空き領域を待機しているため、受信タスクがキューからメッセージを削除すると、メッセージはプリエンプトされます。sender1とsender2の優先度は同じであるため、スケジューラーは最も長く待機しているタスクsender1を選択して準備完了状態にします。

  • t5 sender1は4番目のデータをキューに送信します。この時点で、キューはいっぱいになり、sender1タスクは再びブロッキング状態になります。受信タスクの優先度が最も高く、メッセージが削除されます。

    この時点で、sender1は4つのメッセージをキューに送信しており、sender2はまだ最初のメッセージをキューに送信するのを待っています。

  • 受信タスクよりも優先度の高いT6、sender1、sender2はキュー内の空き領域を待機しているため、受信タスクがキューからメッセージを削除すると、メッセージはプリエンプトされます。このとき、sender1とsender2は両方とも待機しており、sender2はsender1よりも長く待機しているため、スケジューラはsender2を選択して準備完了状態に入ります。

  • t7 sender2は最終的に最初のメッセージをキューに正常に送信し、キューはいっぱいになり、sender2は再びブロッキング状態になり、この時点で受信タスクが実行を開始し、メッセージが削除されます。

  • その後、sender1とsender2が繰り返されてメッセージが順番にキューに送信されるため、結果は次の図のようになり、sender1はsender2の最初のメッセージの前に4つのメッセージを送信します。

ここに画像の説明を挿入

データを渡すためのポインタ

  1. ポインタが指すメモリ空間の所有権は明確でなければなりません

共有メモリの内容は、ポインタがキューに送信される前に送信タスクによってのみアクセスできます。

共有メモリポインタがキューから読み取られた後、そのコンテンツへのアクセスは受信タスクによってのみ許可されます

  1. ポインタが指すメモリ空間は有効である必要があります

ポインタが指すメモリスペースは、動的に割り当てられるか、事前に割り当てられたバッファプールから取得されます。1つのタスクのみがメモリを解放する必要があります。このメモリスペースが解放されると、他のタスクは再び存在しなくなります。このスペースにアクセスしてください。

ポインタを使用して、タスクスタックスペースに割り当てられたデータにアクセスすることはできません。タスクスタックスペースの構造が変更されると、データは無効になります

/*声明一个队列句柄*/
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(;;);
    
}

ここに画像の説明を挿入

上記のFreeRTOSは公式文書からのものですFreeRTOS_Real_Time_Kernel
添付の公式リンクをダウンロードしてください

おすすめ

転載: blog.csdn.net/weixin_44333597/article/details/107725480