一个任务从单个队列中接收来自多个发送源的数据是经常的事。通常接收方收到数据后,需要知道数据的来源,并根据数据的来源决定下一步如何处理。一个简单的方式就是利用队列传递结构体,结构体成员中就包含了数据信息和来源信息,下图对这一方案进行了展现。
从图中可以看出:
任务1、任务2优先级osPriorityLow(低)
任务3 优先级 osPriorityIdle(高)
写队列任务具有最高优先级,所以队列正常情况下一直是处于满状态。这是因为一旦读队列任务从队列中读走一个数据单元,某个写队列任务就会立即抢占读队列任务,把刚刚读走的位置重新写入,之后便又转入阻塞态以等待队列空间有效。
写队列任务指定了 100 毫秒的阻塞超时时间,以便在队列满时转入阻塞态以等待队列空间有效。进入阻塞态后,一旦队列空间有效,或是等待超过了 100 毫秒队列空间尚无效,其将解除阻塞。在本例中,将永远不会出现 100 毫秒超时的情况,因为读队列任务在不停地从队列中读出数据从而腾出队列数据空间。
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "FreeRTOS.h"
#include "task.h"
#include "main.h"
#include "cmsis_os.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "stdio.h"
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
#define mainSENDER_1 0x01
#define mainSENDER_2 0x02
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN Variables */
extern osEvent event;
typedef struct
{
unsigned char ucValue;
unsigned char ucSource;
} xData;
static const xData xStructsToSend[ 2 ] =
{
{ 100, mainSENDER_1 }, /* Used by Sender1. */
{ 200, mainSENDER_2 } /* Used by Sender2. */
};
/* USER CODE END Variables */
osThreadId myTask01Handle;
osThreadId myTask02Handle;
osThreadId myTask03Handle;
osMessageQId myQueue01Handle;
/* Private function prototypes -----------------------------------------------*/
/* USER CODE BEGIN FunctionPrototypes */
/* USER CODE END FunctionPrototypes */
void StartTask01(void const * argument);
void StartTask02(void const * argument);
void StartTask03(void const * argument);
void MX_FREERTOS_Init(void); /* (MISRA C 2004 rule 8.1) */
/**
* @brief FreeRTOS initialization
* @param None
* @retval None
*/
void MX_FREERTOS_Init(void) {
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* USER CODE BEGIN RTOS_MUTEX */
/* add mutexes, ... */
/* USER CODE END RTOS_MUTEX */
/* USER CODE BEGIN RTOS_SEMAPHORES */
/* add semaphores, ... */
/* USER CODE END RTOS_SEMAPHORES */
/* USER CODE BEGIN RTOS_TIMERS */
/* start timers, add new ones, ... */
/* USER CODE END RTOS_TIMERS */
/* Create the queue(s) */
/* definition and creation of myQueue01 */
osMessageQDef(myQueue01, 16, uint16_t);
myQueue01Handle = osMessageCreate(osMessageQ(myQueue01), NULL);
/* USER CODE BEGIN RTOS_QUEUES */
/* add queues, ... */
/* USER CODE END RTOS_QUEUES */
/* Create the thread(s) */
/* definition and creation of myTask01 */
osThreadDef(myTask01, StartTask01, osPriorityLow, 0, 128);
myTask01Handle = osThreadCreate(osThread(myTask01), NULL);
/* definition and creation of myTask02 */
osThreadDef(myTask02, StartTask02, osPriorityLow, 0, 128);
myTask02Handle = osThreadCreate(osThread(myTask02), NULL);
/* definition and creation of myTask03 */
osThreadDef(myTask03, StartTask03, osPriorityIdle, 0, 128);
myTask03Handle = osThreadCreate(osThread(myTask03), NULL);
/* USER CODE BEGIN RTOS_THREADS */
/* add threads, ... */
/* USER CODE END RTOS_THREADS */
}
/* USER CODE BEGIN Header_StartTask01 */
/**
* @brief Function implementing the myTask01 thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_StartTask01 */
void StartTask01(void const * argument)
{
/* USER CODE BEGIN StartTask01 */
/* Infinite loop */
portBASE_TYPE xStatus;
const portTickType xTicksToWait = 100/portTICK_RATE_MS;
for(;;)
{
xStatus = xQueueSendToBack( myQueue01Handle, &( xStructsToSend[0]), xTicksToWait );
if(xStatus != pdPASS)
{
printf("Could not send to the queue.\r\n");
}
taskYIELD();
}
/* USER CODE END StartTask01 */
}
/* USER CODE BEGIN Header_StartTask02 */
/**
* @brief Function implementing the myTask02 thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_StartTask02 */
void StartTask02(void const * argument)
{
/* USER CODE BEGIN StartTask02 */
/* Infinite loop */
portBASE_TYPE xStatus;
const portTickType xTicksToWait = 100/portTICK_RATE_MS;
for(;;)
{
xStatus = xQueueSendToBack( myQueue01Handle, &( xStructsToSend[1]), xTicksToWait);
if(xStatus != pdPASS)
{
printf("Could not send to the queue.\r\n");
}
taskYIELD();
}
/* USER CODE END StartTask02 */
}
/* USER CODE BEGIN Header_StartTask03 */
/**
* @brief Function implementing the myTask03 thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_StartTask03 */
void StartTask03(void const * argument)
{
/* USER CODE BEGIN StartTask03 */
/* Infinite loop */
xData xReceivedStructure;
portBASE_TYPE xStatus;
for(;;)
{
if( osMessageWaiting( myQueue01Handle ) != 16 )
{
printf( "Queue should have been empty!\r\n" );
}
xStatus = xQueueReceive( myQueue01Handle, &xReceivedStructure, 0 );
if(xStatus == pdPASS)
{
if(xReceivedStructure.ucSource == mainSENDER_1)
{
printf("From Sender 1 = %d\r\n",xReceivedStructure.ucValue);
}
else if(xReceivedStructure.ucSource == mainSENDER_2)
{
printf("From Sender 2 = %d\r\n",xReceivedStructure.ucValue);
}
}
else
{
printf( "Could not receive from the queue.\r\n" );
}
}
/* USER CODE END StartTask03 */
}
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_USART1_UART_Init();
/* USER CODE BEGIN 2 */
/* USER CODE END 2 */
/* Call init function for freertos objects (in freertos.c) */
MX_FREERTOS_Init();
/* Start scheduler */
osKernelStart();
/* We should never get here as control is now taken by the scheduler */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}