2021-05-11 FREERTOS 队列

FreeRTOS 队列使用
对FreeRTOS来说,队列是一种很基本数据结构,其中计数信号量,二值信号量等都是利用队列来做的;在FreeRTOS中,队列用于任务与任务之间,任务与中断服务子程序之间的数据传输,其作用类似于裸机编程时使用的全局变量,与全局变量不同的是,队列有阻塞超时时间;任务之间使用队列要遵循FIFO的特性

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

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

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

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

普通任务队列的初始化

#define  MESSAGE_Q_NUM   4   //队列项目数
#define  Queue_BUF_SIZE  4  //每个队列项目的大小
QueueHandle_t Message_Queue;	//串口信息队列句柄

#define  QUE_TASK_NUM   10   //队列深度
QueueHandle_t Task_Queue;	//串口信息队列句柄

创建队列在start_task里面

QueueHandle_t xQueueCreate(UBaseType_t uxQueueLength, UBaseType_t uxItemSize);
void start_task(void *pvParameters)
{
    taskENTER_CRITICAL();           //进入临界区
	  Message_Queue=xQueueCreate(MESSAGE_Q_NUM,Queue_BUF_SIZE); //创建一个消息队列
	  Task_Queue=xQueueCreate(QUE_TASK_NUM,sizeof(u8)); //创建一个任务队列  队列的深度为10  每个深度的大小为u8的大小,为32位的无符号整形数。
    xTaskCreate((TaskFunction_t ) led_task,  			 //任务函数
                (const char*    )"led_task", 			 //任务名称
                (uint16_t       )LED_STK_SIZE,		 //任务堆栈大小
                (void*          )NULL,						       //传递给任务函数的参数
                (UBaseType_t    )LED_TASK_PRIO,		 //任务优先级
                (TaskHandle_t*  )&LEDTask_Handler);//任务句柄

普通任务队列入队

void led_task(void *pvParameters)
{
	u8 task_val=0;
	
    while(1)
    {
	   u8 i=0;
       LED0=~LED0;
       for(i=0;i<10;i++)
	  { 
 xQueueSend(Task_Queue,&task_val,0);//  入队 一次只能一个深度,循环入队到多个深度  即一次入队一个u8类型的数据,分10次入队,则队列满。
		 task_val++;
	  }
        vTaskDelay(400);
    }
}  

普通任务队列出队

void dcm250b_task(void *pvParameters)
 {
  u8 task_data[10]={0};
 	while(1)
 	{
		xQueueReceive(Task_Queue,task_data,portMAX_DELAY);// 将出队的数据保存在task_data 中,
		xQueueReceive(Task_Queue,task_data+1,portMAX_DELAY);
		USART2_data(task_data,2);	
	}
}

portMAX_DELAY为无限延时,即执行到该函数时队列无数据则无限期阻塞,以下的函数语句不会执行,该任务会处于无限期阻塞状态,直到队列有数据来。
xQueueReceive出队保存数据一次只能保存一个深度的数据,执行一次该函数只能保存该函数sizeof(u8)的最大长度。
即UBaseType_t uxItemSize的长度,长度为4则保存4个长度数据,即使队列只有3个数据,多余的数据为0.

portMAX_DELAY为0 则表示不阻塞,有数据则读取队列数据,无数据则返回。任务接收超时 如果在调用时队列为空,任务应等待等待接收项目的最长时间。 如果队列为空,则将xTicksToWait设置为0将导致该函数立即返回。

中断队列入队
在中断函数头文件声明队列信息句柄

extern QueueHandle_t Message_Queue;	//信息队列句柄 
void USART2_IRQHandler(void)                	//串口2中断服务程序
{
	BaseType_t xHigherPriorityTaskWoken;
	xHigherPriorityTaskWoken=pdFALSE;
  if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET)
  {
		RxBuffer2[RxCounter2++] = USART_ReceiveData(USART2);
		if(RxCounter2>7||RxBuffer2[7]==0xff)//判断结束标志 
		{
			if(Message_Queue!=NULL)
			{
			 xQueueSendFromISR(Message_Queue,RxBuffer2,&xHigherPriorityTaskWoken);  //执行一次该函数只能读取该队列的Queue_BUF_SIZE的长度,下一个深度则需要再次执行该语句,才能读取下一个深度的信息。
             xQueueSendFromISR(Message_Queue,&RxBuffer2[4],&xHigherPriorityTaskWoken);						
			 memset(RxBuffer2,0,8);//清除数据接收缓冲区USART_RX_BUF,用于下一次数据接收
			 portYIELD_FROM_ISR(xHigherPriorityTaskWoken);			  
		  }
			//USART2_data(RxBuffer2,8);
			memset(RxBuffer2,0,8);
			RxCounter2=0;
	 }
  }
}

BaseType_t xHigherPriorityTaskWoken; 定义该参数为pdFALSE,则表示用于保存是否有高优先级任务准备就绪。如果函数执行完毕后,此参数的数值是pdTRUE,说明有高优先级任务要执行,否则没有。

portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
如果pxHigherPriorityTaskWoken==pdFALSE 的话,不会执行portYIELD_FROM_ISR(),如果等于pdTRUE的话,在中断服务函数执行完之后,进行一次任务切换。
如果不调用portYIELD_FROM_ISR(pxHigherPriorityTaskWoken),那么要等到下一个系统节拍xPortSysTickHandler()中切换。

中断队列出队

void TIM3_IRQHandler(void)
{
	u8 *Que_data;
	BaseType_t xTaskWokenByReceive=pdFALSE;
	BaseType_t err;
	if(TIM_GetITStatus(TIM3,TIM_IT_Update)==SET) //溢出中断
	{
		if(Message_Queue!=NULL)
		{
		    Que_data=(u8*)malloc(10);
			memset(Que_data,0,10);
			err=xQueueReceiveFromISR(Message_Queue,Que_data,&xTaskWokenByReceive);  //同样需要读取两次才能读取8个字节的数据,一次只能读取4个长度的字节。
			err=xQueueReceiveFromISR(Message_Queue,Que_data+4,&xTaskWokenByReceive);//读取队列的下一个深度的信息。
			if(err==pdTRUE)//err为返回值,如果返回为pdTRUE则表示读取成功。
			{
			  USART2_data(Que_data,8);
			}
			free(Que_data);//记得释放内存
		}
		portYIELD_FROM_ISR(xTaskWokenByReceive);//如果需要的话进行一次任务切换	
	}
	TIM_ClearITPendingBit(TIM3,TIM_IT_Update);  //清除中断标志位
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值