一、任务通知的基本概念
任务控制块有一个32位的成员变量用作通知值,有些情况下可以取代信号量(二值信号量、计数信号量)、事件组、以及长队为1的消息队列。
任务通知的优势:
(1)不需要额外创建通讯资源,如信号量、消息队列、事件组这些都是需要通过创建后才能够使用,
(2)解除阻塞速度比其他通讯方式快45%,
(3)不需要额外占用RAM空间
任务通知的缺点:
(1)只能一个任务接收任务通知消息
(2)只有等待通知的任务被进入阻塞状态,发送通知的任务不会因发送失败进入阻塞状态
二、任务通知的运作机制
每个任务有一个32位的通知值ulNotifiedValue,任务在等到的通知暂时无效时,任务会根据用户指定的阻塞超时事件进入阻塞状态,阻塞时间超时或者有任务通知被发送,阻塞的任务会从阻塞状态恢复为就绪状态。
另外等待任务通知只可以在任务中,不允许在中断中进行,但是发送通知可以在任务或者中断中进行
三、任务通知的数据结构
任务控制块结构体里的两个成员变量,一个是32位通知值ulNotifiedValue另一个是8位的通知状态ucNotifyState
四、任务通知函数
1.发送任务通知函数,
发送任务通知有3中操作,每个操作具有两个版本:带中断保护和不带中断保护
(1)xTaskNotifyGive和xTaskNotifyGiveFromISR
可做二值信号量和计数信号量的一种轻量型实现,任务通知值只做加1操作,
(2)xTaskNotify和xTaskNotifyFromISR
发送任务通知时指定通知值,任务通知值会更新,并且更新的方式由参数决定
(3)xTaskNotifyAndQuery和xTaskNotifyAndQueryFromISR
用于发送新通知值的通知回收上一次的任务通知值:任务通知值会更新,更新方式由参数决定,同时根据最后参数选择是否回传原的任务通知值
注:以上3组在任务中的发送通知函数(即不带FromISR),会调用一个通用的任务通知发送函数,经过封装后,传入的参数有些不一样
2.通用的任务通知发送函数xTaskGenericNotify
该函数有4个参数:目标任务句柄(即被通知的任务句柄,或者接收该通知的任务句柄)、任务通知值、通知值的更新方式(四种更新方式:按位或、自加、覆盖、条件覆盖)、任务原通知值(可以通过该参数回传原来任务的通知值)
通知发送的设计思路:
(1)根据参数判断是否需要回传原任务通知值,如果要回传,则赋值到第四个参数中
(2)保留通知目标任务的任务状态,同时更新目标任务通知状态为接收通知状态
(3)根据任务值更新方式,对目标任务的通知值进行更新,更新方式有4种:
------eSetBits:任务通知值按位或上新任务通知
------eIncrement:任务通知值自加
------eSetValueWithOverWrite:无条件更新任务通知值
------eSetValueWithoutOverwrite:如果上一次任务通知值没有被取走,则不做覆盖,只有被取走后,才对任务通知值进行更新
------eNoAction:只发送通知,不更新任务通知值,可以理解为催促目标任务赶紧把任务通知取走
(4)判断目标任务是否由于等待任务通知而进入阻塞状态,如果是,则将目标任务从阻塞延时列表中移除,添加到任务就绪列表中,使得任务进入就绪状态,下一次任务切换时可以被切换
(5)完成目标任务进入就绪状态后,判断目标任务优先级是否比当前任务优先级高,如果是,则进行任务抢占式切换
3.任务通知值加1方式的发送通知xTaskNotifyGive()
类似于释放一个信号量的操作,任务通知值的更新方式为加1方式,通用任务通知发送函数封装后,参数只有目标任务句柄,
4.中断版本的加1方式发送通知xTaskNotifyGiveFromISR
设计思路与通用的任务通知发送函数类似,只是将任务切换的动作放在退出中断前,而不是在发送任务通知函数里进行任务切换
5.xTaskNotify()
发送任务通知的时候指定一个通知值,参数指定目标任务,任务通知值,任务通知值的更新方式
6.带中断版本任务通知值的发送xTaskNotifyFromISR,不返回原任务通知值
最终调用的是带中断版本的通用的任务通知发送函数xTaskGenericNotifyFromISR该函数与任务版本的通用任务通知发送函数类似,只是将任务切换的动作挪到发送函数外,退出中断之前执行,而任务版本的任务通知发送函数的任务切换是在发送消息后,调用抢占式的任务发送
7.发送任务通知并返回原任务通知值xTaskNotifyAndQuery
相比上一个发送任务通知的函数xTaskNotify,该函数多了一个返回原任务通知值的一个操作
8.带中断版本的发送任务通知并返回原通知值函数xTaskNotifyAndQueryFromISR
核心函数还是xTaskGenericNotifyFromISR
9.获取任务通知函数
获取任务通知函数智能出现在任务中,不能够出现在中断函数里,有两个API函数:ulTaskNotifyTake和xTaskNotifyWait,
(1)ulTaskNotifyTake
获取的是xTaskNotifyGive和xTaskNotifyGiveFromISR这两个发送函数发送的来的任务通知,类似于信号量的获取函数,当任务通知值大于0时,该获取函数才能有效,否则任务将会进入阻塞等待状态,
函数设计思路:先判断任务通知值是否为0,任务值是0进入阻塞状态,任务值不为0,将任务值返回,并且根据参数xClearCountOnExit,是否对任务值进行清0操作,否则只进行普通的减1操作
(2)全功能版本等待任务通知函数xTaskNotifyWait
该等待函数可以等待任务任务通知发送函数发送来的通知
函数有四个参数:处理任务通知前需要置位指定位,退出函数时需要清除置定位,原任务通知值返回,无通知时等待的时长
设计思路,同样是在没有任务通知值的时候,将根据通知值置位参数,对任务通知值先做清除指定位的操作,然后将任务进行阻塞等待,当任务在次被唤醒时,根据退出函数通知值置位参数,对通知值进行处理,然后改变任务通知的状态
学习心得:
1.理解到任务通知其实是任务控制块里添加的两个成员变量,一个是任务通知值,一个是任务通知状态
2.任务通知的发送:6个发送函数(3个任务版本,3个中断版本)
(1)第一类是类似与信号量的释放,任务通知值进行加1处理xTaskNotifyGive和xTaskNotifyGiveFromISR
(2)第二类是发送任务通知值xTaskNotify()和xTaskNotifyFromISR,这个函数指定通知值,以及值的更新方式,总共有5中更新方式:按位或、自加、无条件覆盖、有条件覆盖、不更新
(3)第三类是发送任务通知值并查询原任务通知值,与第二类差不多,只是比第二类的函数多了一个保存原任务通知值的阐述
(4)理解任务通知发送的机制:保存原值-----更新状态-----根据任务通知值更新方式修改任务通知值------唤醒阻塞状态的任务-----根据被唤醒的任务优先级高低切换任务(中断版本是退出发送函数后,进行任务切换)
3.任务通知的获取:
(1)分两个类型,一类是单纯地获取任务通知值后,通知值进行有条件的减1操作;另一类是先对任务通知值进行有条件的置位操作,再获取任务通知值,在退出接收函数前对任务通知值进行有条件的置位操作
(2)理解接收的机制:改变任务通知状态-----有条件地对任务通知值进行处理-----任务进入阻塞等待状态----任务切换------任务唤醒-----保留原任务通知值------有条地修改任务通知值----返回