cubeMX+STM32+Freertos 向队列写结构体

使用队列传递复合数据类型

一个任务从单个队列中接收来自多个发送源的数据是经常的事。通常接收方收到数据后,需要知道数据的来源,并根据数据的来源决定下一步如何处理。一个简单的方式就是利用队列传递结构体,结构体成员中就包含了数据信息和来源信息,下图对这一方案进行了展现。
cubeMX+STM32+Freertos 向队列写结构体_第1张图片
从图中可以看出:

  1. 创建一个队列用于保存类型为 xData 的结构体数据单元。结构体成员包括了一个数据值和表示数据含义的编码,两者合为一个消息可以一次性发送到队列。
  2. 中央控制任务用于完成主要的系统功能。 其必须对队列中传来的输入和其它系统状态的改变作出响应。
  3. CAN 总线任务用于封装 CAN 总线的接口功能。当 CAN 总线任务收到并解码一个消息后,其将把解码后的消息放到 xData 结构体中发往控制任务。结构体的 iMeaning成员用于让中央控制任务知道这个数据是用来干什么的— 从图中的描述可以看出,这个数据表示电机速度。结构体的 iValue 成员可以让中央控制任务知道电机的实际速度值。
  4. 人机接口(HMI)任务用于对所有的人机接口功能进行封装。设备操作员可能通过各种方式进行命令输入和参数查询,人机接口任务需要对这些操作进行检测并解析。当接收到一个新的命令后,人机接口任务通过 xData 结构将命令发送到中央控制任务。结构体的 iMeaning 成员用于让中央控制任务知道这个数据是用来干什么的 — 从图中的描述可以看出,这个数据表示一个新的参数设置。结构体的 iValue 成员可以让中央控制任务知道具体的设置值。

本例内容:

任务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 */

}

任务1代码

/* 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 */
}

任务2代码

/* 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 */
}

任务3代码

/* 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 */
}

结果

写队列任务在每次循环中都主动进行任务切换,所以两个数据会被轮翻地写入到队列中。
cubeMX+STM32+Freertos 向队列写结构体_第2张图片
不足之处请指出,有点帮助请鼓励!

你可能感兴趣的:(cubeMX+STM32+Freertos 向队列写结构体)