FreeRTOS中任务通知的使用

0x01 任务通知介绍

简单举个例子:

例如任务一用于获取数据,任务二用于处理数据。

但这其中存在一个先后关系:必须等到任务一获取完了数据,任务二才能开始工作,你会如何选择何种实现方式呢?

未引入操作系统时,轮询系统会按照代码顺序执行,触发中断时,你可以通过设置一个获取原始数据的函数完成的全局变量作为标志位是否为1来判断是否完成,如果完成则开始执行数据处理任务,否则就等下一轮。
在这里插入图片描述

引入了操作系统后,可以通过二进制信号量的方式进行PV原子操作,这样一来便可以确保 任务一完成后,任务二才能执行

用两份伪代码的方式来描述一下:

任务1-获取数据:
	······
	······
while(数据没获取完)
	获取数据;

V(muttex)//数据获取完了,释放信号量
	······
	······
任务2-处理数据:
	······
	······
while(P(muttex))//获取不到信号量会被阻塞
	静静等待;

处理数据//得到信号量了跳出循环,可以开始工作
	······
	······

很通俗易懂,是一个比较简单的生产消费者模型。

这个和轮询系统的区别就是,引入操作系统可以提高系统的实时性。在轮询系统中,MCU需要不断的去检查标志位的值是否满足条件,这会导致浪费一些资源在这个步骤上。而通过PV操作来获取信号量消耗的资源较少,并且此时任务还是处在被挂起的状态,相比起来是不怎么耗费资源的。相比使用全局变量标志位的方式而言,使用二进制信号量所耗费的资源往往可以接受,并且在获取到信号量的瞬间任务便可以开始工作,而在轮询系统中还需要等到其他代码执行完轮到函数2了,才可以开始执行。

0x02 示例代码

下面使用示例代码说明,使用FreeRTOS的软件定时器来为其发送任务通知,促使LED闪烁。

在收到任务通知时,LED会闪烁一下随后继续等待任务通知到来,方可继续闪烁,否则将被阻塞进程。
main.c

#include "tasks.h"  
#include "stdio.h"  

// 等待任务通知的任务
void vHandlerTask( void *pvParameters )
{
	while(1)
	{
		if(ulTaskNotifyTake(pdTRUE, xMaxExpectedBlockTime));//未收到任务通知会被阻塞
			LED_Blink;
	}
}

// 软件定时器回调函数  
void vTimerCallback(TimerHandle_t xTimer) 
{  
    if (xHandlerTaskHandle != NULL) {  
    	// 发送任务通知到vHandlerTask  
        xTaskNotifyGive(xHandlerTaskHandle);  
    }  
}  
  
// 设置并启动软件定时器  
void vStartTimer(void) 
{  
    const TickType_t xTimerPeriod = pdMS_TO_TICKS(1000); // 定时器周期为1000ms(1秒)  
  
    // 创建定时器  
    TimerHandle_t xTimer = xTimerCreate("Timer",  
                                        xTimerPeriod,  
                                        pdTRUE,  
                                        (void *) 0,  
                                        vTimerCallback);  
}  

以上演示的是在"任务对任务"通知,是否可以在中断里面对通知任务,让其开始工作呢?答案当然是可以的

下面是一个任务,在等待串口发来信息将其唤醒,随后判断字符有效性

void TaskBoardSelect(void *Params)
{
	BaseType_t xReturn = pdTRUE;
	uint32_t GetBoard; 
	
	while(1)
	{
        //获取任务通知 ,没获取到则一直等待 
        xReturn=xTaskNotifyWait(0x0,0xFFFF,(uint32_t *)&GetBoard,portMAX_DELAY); //阻塞时间 
        if ( pdTRUE == xReturn ) 
        {
			char BoardID = ((char *)GetBoard)[0];
            printf("TaskBoardSelect 任务通知为 %s \n",GetBoard);
            
			if(BoardID >= '0' && BoardID <= '9')
			{
				OSstate++;// 系统状态机进入下一状态
			}
			else if(BoardID == 'q' || BoardID == 'Q')
			{
				OSstate--
			}
			else
			{
				printf("输入有误");
			}
        }
		vTaskDelay(50);
	}
}

那么在中断中应该如何唤醒这个任务呢?在串口中断中使用以下API即可

xTaskNotifyFromISR( TaskBoardSelect_Handle,
					(uint32_t)&USART0RecvPacket.RxData,
					eSetValueWithOverwrite);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

IoT_H2

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值