欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

FreeRTOS队列使用

程序员文章站 2024-02-22 18:32:04
...

 队列的基本特性

FreeRTOS队列使用

队列是任务间通信的主要形式。常被用于任务与任务、中断与任务之间的消息传递,通常是FIFO的形式。

队列阻塞任务

FreeRTOS队列使用

 当一个任务读取空队列时,这个任务将进入阻塞态(不消耗cpu,cpu会去运行其他任务),直到队列不为空或者阻塞时长超过设定的阻塞时间,将进入就绪态。

当一个任务向满队列写时,这个任务会进入阻塞态(不消耗cpu,cpu会去运行其他任务),直到队列不为满或者阻塞时长超过设定的阻塞时间,将进入就绪态。

如果有多个任务因为同一个队列而进入阻塞态,当队列满足条件的时候,优先级最高的任务先解除阻塞态,其他任务继续阻塞。

中断里面只能使用后缀带有“FromISR”的API。

 队列使用(部分API使用)

typedef void * QueueHandle_t; //队列句柄

QueueHandle_t xQueueCreate(UBaseType_t uxQueueLength,UBaseType_t uxItemSize );//创建队列

BaseType_t xQueueSend( QueueHandle_t xQueue,const void * pvItemToQueue,TickType_t xTicksToWait);//向队列写数据

BaseType_t xQueueReceive(QueueHandle_t xQueue,void *pvBuffer,TickType_t xTicksToWait);//从队列里面读取数据

BaseType_t xQueueSendFromISR(QueueHandle_t xQueue,const void   *pvItemToQueue,BaseType_t*pxHigherPriorityTaskWoken); 
//向队列里面写入数据,用在中断中

测试程序

总体设计:总共4个任务,2个队列

lcdtask:显示当前计数,并向队列TaskToTaskQueue里面写入当前计数;

testtask0:读取队列TaskToTaskQueue里面的数据,并串口打印;

testtask1:1s串口打印一次数据;

queuetask:读取队列TaskToIrqQueue的数据并打印出来;

串口中断:收到数据后往队列TaskToIrqQueue里面写入收到的数据。

创建任务和队列:

#define LCD_TASK_PRIO		        1   //任务优先级
#define LCD_TASK_STK_SIZE 		80  //任务堆栈大小
TaskHandle_t LCDTaskHandler;                //任务句柄
void LCDTaskFunc(void *pvParameters);       //任务函数

#define TEST_TASK0_PRIO		        2   //任务优先级
#define TEST_TASK0_STK_SIZE 		50  //任务堆栈大小
TaskHandle_t TestTask0Handler;              //任务句柄
void TestTask0Func(void *pvParameters);     //任务函数

#define TEST_TASK1_PRIO			3   //任务优先级
#define TEST_TASK1_STK_SIZE 		80  //任务堆栈大小
TaskHandle_t TestTask1Handler;              //任务句柄
void TestTask1Func(void *pvParameters);     //任务函数

#define QUEUE_TASK_PRIO		         4  //任务优先级
#define QUEUE_TASK_STK_SIZE 		80  //任务堆栈大小
TaskHandle_t QueueTaskHandler;              //任务句柄
void QueueTaskFunc(void *pvParameters);     //任务函数

QueueHandle_t TaskToIrqQueue;	//信息队列句柄
QueueHandle_t TaskToTaskQueue;	//信息队列句柄

void OtherTest(void )
{
    BaseType_t ret;
	
    BoardInitMcu();
    BoardInitPeriph();
	
    TaskToIrqQueue=xQueueCreate(1,255); //创建一个队列,队列有1项,每个项长为255byte。
    TaskToTaskQueue=xQueueCreate(5,2); //创建一个队列,队列有5项,每个项长为2byte
	
    ret=xTaskCreate((TaskFunction_t )LCDTaskFunc,     	
		    (const char*    )"lcdtask",   	
		    (uint16_t       )LCD_TASK_STK_SIZE, 
		    (void*          )NULL,				
		    (UBaseType_t    )LCD_TASK_PRIO,	
		    (TaskHandle_t*  )&LCDTaskHandler); 
	
    ret=xTaskCreate((TaskFunction_t )TestTask0Func,     	
		    (const char*    )"testtask0",   	
		    (uint16_t       )TEST_TASK0_STK_SIZE, 
		    (void*          )NULL,				
		    (UBaseType_t    )TEST_TASK0_PRIO,	
		    (TaskHandle_t*  )&TestTask0Handler);   
				
    ret=xTaskCreate((TaskFunction_t )TestTask1Func,     
		    (const char*    )"testtask1",   
		    (uint16_t       )TEST_TASK1_STK_SIZE, 
		    (void*          )NULL,
		    (UBaseType_t    )TEST_TASK1_PRIO,
		    (TaskHandle_t*  )&TestTask1Handler); 
	
    ret=xTaskCreate((TaskFunction_t )QueueTaskFunc,     
		    (const char*    )"queue task",   
		    (uint16_t       )QUEUE_TASK_STK_SIZE, 
		    (void*          )NULL,
		    (UBaseType_t    )QUEUE_TASK_PRIO,
		    (TaskHandle_t*  )&QueueTaskHandler); 
				
    vTaskStartScheduler(); 
}

各个任务函数:

//LCD显示任务当前计数,并把当前计数写入TaskToTaskQueue队列函数 
void  LCDTaskFunc(void *pvParameters)
{
    char  string[21] = {0};
    static uint8_t i=0;

    for(;;)
    {
        i++;
        sprintf(string, "%03d ", i);
        dis_string(1,0,(uint8_t *)string,1);
				
	xQueueSend(TaskToTaskQueue,&i,20);
		
	vTaskDelay(500);                 //延时500ms,也就是500个时钟节拍	
    }    
}

//Test0任务函数,读取 TaskToTaskQueue的数据并打印
void TestTask0Func(void *pvParameters)
{
    uint16_t i=0;
	
    while(1)
    {	
	if(TaskToTaskQueue!=NULL)	
	{			
	    xQueueReceive(TaskToTaskQueue,&i,portMAX_DELAY);
	    printf("current count:%d\r\n",i);
	}
    }
}   

//Test1任务函数
void TestTask1Func(void *pvParameters)
{
    while(1)
    {
        vTaskDelay(1000);
	printf("task1\r\n");
    }
}

//从队列读取串口收到的数据并打印任务函数
void QueueTaskFunc(void *pvParameters)
{
    for(;;)
    {
	if(TaskToIrqQueue!=NULL)
	{
	    if(xQueueReceive(TaskToIrqQueue,str,10))
	    {
	        printf("serial:%s\r\n",str);
	    }
	}
    }
}

串口中断函数中写数据到队列:

void USART1_IRQHandler( void )
{
    BaseType_t pxHigherPriorityTaskWoken=pdFALSE;
	
    ……//省略部分代码
		
    xQueueSendFromISR(TaskToIrqQueue,SerialFrame.Buff,&pxHigherPriorityTaskWoken);
    //向队列写入数据,如果写队列使某个任务就绪,并且这个任务是当前所有任务中优先级最高的,那么pxHigherPriorityTaskWoken将会被设置为pdTRUE
		
    portYIELD_FROM_ISR(pxHigherPriorityTaskWoken);
    //如果pxHigherPriorityTaskWoken为真将进行任务切换
}

 运行结果:

FreeRTOS队列使用

 

相关标签: FreeRTOS