原文地址:http://www.cnblogs.com/god-of-death/p/6917837.htmlhtml
用于任务之间的同步,即一个任务 give token,另外一个任务 take token数组
特别提醒:函数
因为中断服务函数越短越好(处理时间越短越好),把关键处理放中断服务函数,其余放到外面,外面能够是一个任务(灵活性大,由于会用到二值信号量或计数信号量,须要为每一个信号量建立一个任务,耗用资源多),也能够是定时器守护任务的回调函数xTimerPendFunctionCallFromISR()(定时器守护任务使用到一个命令队列,只要向队列发送信号就能够执行相应代码,因此能够实现“中断推迟处理”功能;只用到定时器守护任务这一个任务,节省资源,但建议回调函数执行时间短一些,不然影响其余定时器回调函数的执行周期)spa
任务通知优势:更快、占用RAM少htm
任务通知缺点:数据不能从任务发送到ISR(也就是ISR中不能读取任务通知);接收处理任务通知只能在本任务中;任务通知只能经过32位无符号整数传递数据;当任务为“pending”,发送任务通知API不会等待任务变为“not-pending”而阻塞,也就是数据可能丢失blog
任务状态:接收到通知为处理为“pending”,读取通知值状态变为“not-pending”递归
xTaskNotifyGive() 是xTaskNotify() 的阉割版token
ulTaskNotifyTake() 是xTaskNotifyWait() 的阉割版
队列
调用发送函数产生的影响:事件
调用xTaskNotifyGive()后,通知值加一,ucNotifyState变为"pending"
调用xTaskNotify()后,通知值能够不变、指定位置1、加1、强制重写通知值或者ucNotifyState为"not-pending"状态时写通知值,ucNotifyState变为"pending"。第三个参数若是是eSetBits ,是使 notification value 的某一位置一,能够同时对notification value 的某几位置一,而后同时处理几件事情;若是第三个参数是eSetValueWithOverwrite ,是设置 notification value 为某个值。
接收函数如何判断是否接收到未读通知:
ulTaskNotifyTake()判断是否有未读通知是根据通知值ulNotifiedValue是否为零,该函数能够实现通知值减一或清零。相对来讲,该函数实现主要是针对信号量那种类型(xClearCountOnExit 为pdTRUE替代二值信号量;为pdFALSE替代计数信号量);
xTaskNotifyWait()判断是否有通知是依据通知状态ucNotifyState, 该函数能够实现清除指定位。这里,通知值才算真正承载了有用的通知内容。
使用互斥可能出现的问题:
一、互斥可能会致使高优先级任务等待低优先级任务,以下图:
二、也可能致使互锁,两个任务都各自持有对方想要的互斥信号,致使两个任务都没法进行,因此建议任务等待互斥信号的时间不要无限长,超时能够作一些处理,能够发现死锁状况
三、也可能致使自锁,好比某个函数对任务进行递归调用;能够经过递归互斥(recursive mutexes)解决
四、也可能某个任务一直没执行,以下图,可是能够经过调用taskYIELD() 解决
互斥量是为了保护“打印机”类型的事件不被破坏,看门人任务和队列或者计数信号量配合也能够实现这个功能,具体就是只有看门人任务能够直接使用“打印机”,看门人任务大多时间阻塞等待打印数据到来,任何其余任务想使用打印机只能向看门人任务发送打印数据
可使用的API以下:
一、taskDISABLE_INTERRUPTS() 和 taskENABLE_INTERRUPTS()
屏蔽可屏蔽中断,包括调度器也不能工做(即不能任务切换,由于调度器也是基于中断),保证某个代码段不被打断的执行;可是不支持嵌套(即若是调用了两个DISABLE,调用一个ENABLE也可使中断正常工做,嵌套的意思是一对DISABLE和ENABLE里面包含了其余对DISABLE和ENABLE);当调度器挂起,FreeRTOS API不能够被调用
二、taskENTER_CRITICAL() 和 taskEXIT_CRITICAL()
和1的区别就是支持嵌套,即调用了几个ENTER,就要调用几个EXIT才能使能中断;当调度器挂起,FreeRTOS API不能够被调用
三、vTaskSuspendAll() 和 xTaskResumeAll()
只是不能进行任务切换,可是没有屏蔽中断;1和2不只不能任务切换,还不能响应中断;当调度器挂起,FreeRTOS API不能够被调用
一、不一样于二值信号量和计数信号量,队列的原理是FIFO,能够存放数据
二、建立队列时队列的元素个数和元素的类型就已经肯定了,只能往队列存放规定的元素类型
三、能够建立队列集合,队列集合里面能够放队列、计数信号量或二值信号量,使用队列集合适用于多个任务向某个任务发送数据,而数据类型不相同,不一样数据类型的数据存放在不一样的队列集合成员里。
四、队列能够实现邮箱功能,即多个任务能够读取长度为1的队列里的数据,但不会清除数据,即便队列有数据但没有更新,调用xQueuePeek()也不会阻塞;任务往此队列写数据是覆盖里面的数据。适用于向多个任务发送数据,即一对多通讯,即广播。
事件组能够用于某个任务等待几个条件都知足或某个条件知足才解除阻塞的情景(多个发送,一个接收,即多对一通讯),或者几个任务互相等待条件知足才进一步执行任务,好比task A,B,C须要进一步执行各自的任务,须要task A,B,C都知足条件(多个发送,多个接收,即多对多通讯)。
调用这个函数xEventGroupSetBitsFromISR() ,实际是在定时器守护任务中执行,说有configUSE_TIMERS 和 INCLUDE_xTimerPendFunctionCall 须要置一
若是单片机的RAM比较小,分配给FreeRTOS的heap比较少,可使用内存动态申请pvPortMalloc定义大数组,从而减少分配给任务栈的大小