FreeRtos队列复习

一、基础概念

作用:队列是为了任务与任务、任务与中断之间的通信而准备的,可以在任务与任务、任务与中断之间传递消息,队列中可以存储有限的、大小固定的数据项目。

二、运行机制

在脑海中想像不同任务之间,其需要交互数据的时候,需要的一种通信机制,这种机制在该操作系统就是“消息队列”其特点是任何建立的任务都可以向队列中发送消息和取信息。

1、首先就是创建队列

  • 创建消息队列时 FreeRTOS 会先给消息队列分配一块内存空间,这块内存的大小等于消息队列控制块大小加上(单个消息空间大小与消息队列长度的乘积),接着再初始化消息队列,此时消息队列为空。
  • 初始化消息队列的时候同时会初始内存空间,用于保存消息队列的一些信息如消息的存储位置,头指针 pcHead、尾指针pcTail、消息大小 uxItemSize 以及队列长度 uxLength 等。同时每个消息队列都与消息空间在同一段连续的内存空间中(消息队列是消息空间的别名)。在创建成功的时候,这些内存就被占用了,只有删除了消息队列的时候,这段内存才会被释放掉。其消息队列发送拷贝的数据不能超过其创建时候设置的大小。

2、队列发送消息(入队机制)

- 分三种情况

  • 任务或者中断服务程序立即发送消息。

对应场景: 如果队列未满或者允许覆盖入队,FreeRTOS 会将消息拷贝到消息队列队尾

  • 由用户指定的阻塞超时时间进行阻塞

对应场景①:在设置的阻塞超时时间中,如果队列一直不允许入队,该任务将保持阻塞状态以等待队列允许入队。
对应场景①:当其它任务从其等待的队列中读取入了数据(队列未满),该任务将自动由阻塞态转移为就绪态。
也就是在等待过程中队列会一直按照设定时间入队,但是当队列中提前有消息被读走时候会提前入队。

-超过设置阻塞时间

即使队列中还不允许入队,任务也会自动从阻塞态转移为就绪态,此时发送消息的任务或者中断程序会收到一个错误码 errQUEUE_FULLAPI系统自动发出。

发送紧急消息的过程与发送消息几乎一样,唯一的不同是,当发送紧急消息时,发送的位置是消息队列队头而非队尾,这样,接收者就能够优先接收到紧急消息,从而及时进行消息处理。

3、队列接收消息(出队机制)

  • 读取消息时候,如果队列为空,该任务将保持阻塞状态以等待队列数据有效。
  • 当其它任务或中断服务程序往其等待的队列中写入了数据,该任务将自动由阻塞态转移为就绪态。任务程序继续执行下去。
  • 当等待的时间超过了指定的阻塞时间,即使队列中尚无有效数据,任务也会自动从阻塞态转移为就绪态。继续执行程序。

注意事项:

  • FreeRtos只有在任务中发送消息使用队列,才允许进行阻塞状态,而在中断中发送消息不允许带有阻塞机制的,需要调用在中断中发送消息的API 函数接口,因为发送消息的上下文环境是在中断中,不允许有阻塞的情况。
  • 假如有多个任务阻塞在一个消息队列中,那么这些阻塞的任务将按照任务优先级进行排序优先级高的任务将优先获得队列的访问权。

三、 API函数

使用队列模块的典型流程如下:

  • 创建消息队列
  • 写队列操作
  • 读队列操作
  • 删除队列
    API官网
    https://freertos.org/a00116.html
    send和recive实质上是拷贝消息队列。
    消息队列,发、收、排队的时候三种情况都是叫队列

四、实验代码分析

野火的很简单就任务间的收发,发采用立即发,收阻塞收没有实战使用价值

static void Send_Task(void* parameter)
{	 
  BaseType_t xReturn = pdPASS;/* 定义一个创建信息返回值,默认为pdPASS */
  uint32_t send_data1 = 1;
  uint32_t send_data2 = 2;
  while (1)
  {
    if( Key_Scan(KEY1_GPIO_PORT,KEY1_GPIO_PIN) == KEY_ON )
    {/* K1 被按下 */
      printf("发送消息send_data1!\n");
      xReturn = xQueueSend( Test_Queue, /* 消息队列的句柄 */
                            &send_data1,/* 发送的消息内容 */
                            0 );        /* 等待时间 0 */
      if(pdPASS == xReturn)
        printf("消息send_data1发送成功!\n\n");
    } 
    if( Key_Scan(KEY2_GPIO_PORT,KEY2_GPIO_PIN) == KEY_ON )
    {/* K2 被按下 */
      printf("发送消息send_data2!\n");
      xReturn = xQueueSend( Test_Queue, /* 消息队列的句柄 */
                            &send_data2,/* 发送的消息内容 */
                            0 );        /* 等待时间 0 */
      if(pdPASS == xReturn)
        printf("消息send_data2发送成功!\n\n");
    }
    vTaskDelay(20);/* 延时20个tick */
  }
}

static void Receive_Task(void* parameter)
{	
  BaseType_t xReturn = pdTRUE;/* 定义一个创建信息返回值,默认为pdTRUE */
  uint32_t r_queue;	/* 定义一个接收消息的变量 */
  while (1)
  {
    xReturn = xQueueReceive( Test_Queue,    /* 消息队列的句柄 */
                             &r_queue,      /* 发送的消息内容 */
                             portMAX_DELAY); /* 等待时间 一直等 */
    if(pdTRUE == xReturn)
      printf("本次接收到的数据是%d\n\n",r_queue);
    else
      printf("数据接收出错,错误代码0x%lx\n",xReturn);
  }
}

在这里插入图片描述
正点的
涉及了中断与任务,任务与任务。

任务与任务之间没什么好分析的就是阻塞时间为10的发送,与创建一个任务阻塞等待接收处理事件。定时器接收队列消息

void TIM2_IRQHandler(void)
{
	u8 *buffer;
	BaseType_t xTaskWokenByReceive=pdFALSE;
	BaseType_t err;
	
	if(TIM_GetITStatus(TIM2,TIM_IT_Update)==SET) //溢出中断
	{
		buffer=mymalloc(SRAMIN,USART_REC_LEN);
        if(Message_Queue!=NULL)
        {
			memset(buffer,0,USART_REC_LEN);	//清除缓冲区
			err=xQueueReceiveFromISR(Message_Queue,buffer,&xTaskWokenByReceive);//请求消息Message_Queue
            if(err==pdTRUE)			//接收到消息//其函数xQueueReceiveFromISR返回值为pdTRUE
            {
				disp_str(buffer);	//在LCD上显示接收到的消息
            }
        }
		myfree(SRAMIN,buffer);		//释放内存
		
		portYIELD_FROM_ISR(xTaskWokenByReceive);//如果需要的话进行一次任务切换
	}
	TIM_ClearITPendingBit(TIM2,TIM_IT_Update);  //清除中断标志位
}

队列接收中断函数解释
在这里插入图片描述

	if((USART_RX_STA&0x8000)&&(Message_Queue!=NULL))
	{
		xQueueSendFromISR(Message_Queue,USART_RX_BUF,&xHigherPriorityTaskWoken);//向队列中发送数据
		
		USART_RX_STA=0;	
		memset(USART_RX_BUF,0,USART_REC_LEN);//清除数据接收缓冲区USART_RX_BUF,用于下一次数据接收
	
		portYIELD_FROM_ISR(xHigherPriorityTaskWoken);//如果需要的话进行一次任务切换
	}

待验证:xHigherPriorityTaskWoken这个参数官方解释,估计是返回值的由来,设置好这个参数会自动返回函数值与执行任务切换的选择
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值