FREERTOS学习四--队列Queue

一、什么是队列

        学习外国人的东西最好还是从字面意思去理解,外国的文化毕竟没有我们的文化深厚,没有那么深层次的意思。如果自己把那些名词想得太深奥,那就是给自己找麻烦。本人也很讨厌各种书本上翻译过来的高深词汇,搞得云里雾里。跑题了。

        队列就是队列,中小学做操、升国旗是排的那个队就是队列。

        人排的队,就是人的队列;牛排的队就是牛的队列,猪排的队,就是猪的队列......

        所以,队列里面的东西可以随便,随便什么数据格式。

        队列有长有短,那个长短指的是队列里面数据的个数,这个个数就是队列的长度length;

        RTOS的这个队列,不是按照高矮来排的,而是按照时间顺序来排的。谁先来谁就排在第一个,然后第一个离开,这就是所谓的先进先出FIFO,first in first out。

        当然了,这个社会怎么会有绝对的规则,绝对的公平,只要办了VIP你就可以插队了。在RTOS系统里面也是一样的。

        来看一个生活中的队列问题吧--去医院挂号

        看看这个流程:

        1、去取号机取个号,第一个就是1号、第2个就是2号、第3个就是3号......

        2、但是这个医院比较小,只能容纳20个病人,那最多只能20个病人来排队了。

        3、人少的时候也无所谓了,病人来了就进医院等医生叫号就诊;

        4、人多了,超过20个人了,就表示队列满了。那从第21个病人开始就只能在外面等着,等里面的病人诊完了,出来一个人,就进去一个人;其他的人就继续在外面等着;

        5、本来这是很和谐的场面,但是从第21个人开始,那些在外面的人不能进医院,就不能取号,该让谁先进去呢?简单,大家都是平等的,谁在外面等的最久谁就可以先进来。但是前面说了,这个社会不是绝对公平的,人也是分等级的,比如外面有个高级的人物,那就让这个高级的人物先进去。如果这个人物还有特权,他甚至可以进去直接插队,想插哪就插哪。

        

  二、创建队列

        创建队列函数,这里只说动态创建,静态创建用得少,有机会再说。

 xQueueCreate( uxQueueLength, uxItemSize )

        队列的要素:

                uxQueueLength,队列的长度,就是有多少个数据的意思

                 uxItemSize,每个数据的大小,以字节为单位

        

  //创建一个深度为5的队列,队列里面的数据格式是uint32_t
  xQueue = xQueueCreate(5, sizeof(uint32_t));

三、 队列的基本使用

                创建三个函数,两个函数分别往队列中读写数据,一个函数从队列中读数据

#include "FreeRTOS.h"
#include "task.h"
#include "main.h"
#include "gpio.h"
#include "usart.h"
#include "queue.h"


/*定义任务句柄*/
TaskHandle_t myTask01_Handle;
TaskHandle_t myTask02_Handle;
TaskHandle_t myTask03_Handle;

/*定义队列句柄*/
QueueHandle_t xQueue;

/*声明任务*/
void SendTask(void *argument);
void ReceiveTask(void *argument);


void FREERTOS_Init(void); 

/**
  * @brief  在FreeRTOS初始化的时候把任务函数创建了
  */
void FREERTOS_Init(void) {
  
  taskENTER_CRITICAL(); 
  
  //创建一个深度为5的队列,队列里面的数据格式是uint32_t
  xQueue = xQueueCreate(5, sizeof(uint32_t));
  if(xQueue != NULL)
  {
    xTaskCreate( SendTask,   "SendTask01", 1000, (void*)100,1,&myTask01_Handle );
    xTaskCreate( SendTask,   "SendTask02", 1000, (void*)200,1,&myTask02_Handle );
    xTaskCreate( ReceiveTask,   "ReceiveTask01", 1000, NULL, 2, &myTask03_Handle );
  }
  taskEXIT_CRITICAL();             
}

//SendTask函数主体
void SendTask(void *argument)
{
  uint32_t ldataToSend;
  BaseType_t xStatus;
  
  ldataToSend = (uint32_t)argument;
  /*大循环*/
  for(;;)
  {
    /*任务的具体内容*/
    RLED_TOGGLE();
    xStatus = xQueueSendToBack(xQueue,&ldataToSend, 0);
    if(xStatus !=pdPASS)
    {
      printf("can not send to the queue!!!");
    } 
    /*任务阻塞*/
    //vTaskDelay(1000);
  }
}


//ReceiveTask函数主体
void ReceiveTask(void *argument)
{
  uint32_t lReceiveData;
  BaseType_t xStatus;
  
  for(;;)
  {
    BLED_TOGGLE();
    xStatus = xQueueReceive(xQueue,&lReceiveData,100);
    
    if(xStatus == pdPASS)
    {
      printf("Receive data = %d\r\n", lReceiveData);
    }else{
      printf("can not receive from the queue!!!\r\n");
    }
  
    //vTaskDelay(1000);
  }
}

四、识别数据来源

        前面是两个任务都往队列里面写数据,一个任务从队列读数据,但是读出来的数据并不知道来自谁,这在控制系统中是不妥的。

        既然要识别数据来源,那就需要给数据加个ID,有几个任务往队列中写数据,就是几个ID

//数据来源
typedef enum {
 SendTask1,
 SendTask2
} ID_t;

        再把ID和数据绑在一起,那就是结构体了

//数据结构体
typedef struct{
  ID_t eDataId;
  uint32_t lDataValue;
} Data_t;

        格式定好了,那就定义数据吧,测试的时候就定个全局变量,当然在以后具体的任务中,可以在任务中定义拘捕变量。

//定义两个结构体
static const Data_t xStructToSend[2] = {
  {SendTask1, 100},
  {SendTask2, 200}
};

接下来就是创建任务往队列里读写数据了,两个任务去写数据,一个任务来读数据

xTaskCreate( SendTask,   "SendTask01", 1000, (void*)&xStructToSend[0],2,&myTask01_Handle );
xTaskCreate( SendTask,   "SendTask02", 1000, (void*)&xStructToSend[1],2,&myTask02_Handle );
xTaskCreate( ReceiveTask,   "ReceiveTask01", 1000, NULL, 1, &myTask03_Handle );

貌似写数据的任务优先级高,读数据的任务优先级低,自己也可以去调整下优先级看看效果。

具体的写队列任务函数和读队列任务函数

//SendTask函数主体
void SendTask(void *argument)
{
  //uint32_t ldataToSend;
  BaseType_t xStatus;
  
  //ldataToSend = (uint32_t)argument;
  /*大循环*/
  for(;;)
  {
    /*任务的具体内容*/
    RLED_TOGGLE();
    xStatus = xQueueSendToBack(xQueue,argument, 100);
    if(xStatus !=pdPASS)
    {
      printf("can not send to the queue!!!");
    } 
    /*任务阻塞*/
    //vTaskDelay(1000);
  }
}


//ReceiveTask函数主体
void ReceiveTask(void *argument)
{
  Data_t lReceiveData;
  BaseType_t xStatus;
  
  for(;;)
  {
    BLED_TOGGLE();
    xStatus = xQueueReceive(xQueue,&lReceiveData,0);
    
    if(xStatus == pdPASS)
    {
      if(lReceiveData.eDataId == SendTask1)
      {
        printf("from SendTask1, data = %d\r\n", lReceiveData.lDataValue);
      } else if(lReceiveData.eDataId == SendTask2){
        printf("from SendTask2, data = %d\r\n", lReceiveData.lDataValue);
      }
    }else{
      printf("can not receive from the queue!!!\r\n");
    }
    //vTaskDelay(1000);
  }
}

结果就不展示了,感兴趣的自己去调试吧。

队列相关的函数还有复位队列、删除队列、查询队列......

你可能感兴趣的:(FreeRTOS,学习,stm32,嵌入式硬件,物联网)