FreeRTOS队列使用
程序员文章站
2024-02-22 18:32:04
...
队列的基本特性
队列是任务间通信的主要形式。常被用于任务与任务、中断与任务之间的消息传递,通常是FIFO的形式。
队列阻塞任务
当一个任务读取空队列时,这个任务将进入阻塞态(不消耗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为真将进行任务切换
}
运行结果:
上一篇: EJB3.0之实体Bean的继承
下一篇: LwIP之ICMP协议