任务不能以任何方式实现函数返回,可以在任务的死循环外加上xTaskDelete( )
创建任务:xTaskCreate( )
滴答中断:一般调度器都是基于时间片的抢占系统
任务状态
阻塞延时:vTaskDelay和vTaskDelayUntil
空闲任务
任务优先级:设置任务优先级:vTaskPrioritySet,获取任务优先级:vTaskPriorityGet
**任务删除:**vTaskDelete
**线程本地存储:**vTaskSetThreadLocalStoragePointer和pvTaskGetThreadLocalStoragePointer,根据任务数组的索引设置和读取数据
调度算法*:***
FreeRTOS通过复制实现队列的方式,优点是可以直接发送栈变量到队列,不需要先分配缓冲区存放数据,发送和接收任务完全脱钩,复制实现队列不妨碍引用实现队列。
**多任务访问:**队列本身就是对象,可以被任意个任务或者ISR访问
队列读取、写入阻塞:
**队列创建:**xQueueCreate
**队尾插入:**xQueueSendToBack
**队首插入:**xQueueSendToFront
**队列接收:**xQueueReceive
**数据量查询:**uxQueueMessagesWaiting
从多个来源接收数据:
处理大数据和可变大小数据:最好使用队列传输数据的指针
**队列集:**能够从多个来源接收数据,但比结构体方法更繁琐效率更低
**队列集创建:**xQueueCreateSet
**队列添加队列集:**xQueueAddToSet
**队列集读取队列:**xQueueSelectFromSet
**队列集移除队列:**xQueueRemoveFromSet
***队列创建邮箱:***邮箱用来指长度为1的队列
**发送并覆盖邮箱数据:**xQueueOverwrite
**接收并不移除数据:**xQueuePeek
任务是软件功能,和运行的硬件无关。中断是硬件功能,最低优先级的中断可以抢断最高优先级任务,反之则不可以。
专门用于ISR的API函数,在名称后添加FromISR,不要在ISR中调用没有后缀的函数
**使用单独中断安全函数的缺点:**有需要在ISR中调用第三方函数,但第三方函数用了正常的FreeRTOS API函数
xHigherPriorityTaskWoken参数
中断结束时,会回到打断处继续执行,但如果中断期间,有了更高优先级任务就绪,就应该执行更高优先级任务,而不是返回原点继续执行。如果不管的话,更高优先级任务将保持就绪状态,直到不在中断时的下一次调度器运行。
示例代码如下:
void vTimerISR( void * pvParameters )
{
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
xHigherPriorityTaskWoken = pdFALSE;
xSemaphoreGiveFromISR( xSemaphore, &xHigherPriorityTaskWoken );
/* Yield if xHigherPriorityTaskWoken is true. The
actual macro used here is port specific. */
portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
}
推迟中断处理
二进制信号量:能够有效使任务和中断同步,可以认为使长度为1的队列
设置推迟任务的优先级确保,该任务可以抢占系统其他任务
在ISR实现中调用portYIELD_FROM_ISR,确保ISR返回到推迟中断处理任务
创建二值信号量: xSemaphoreCreateBinary
**释放信号量:**xSemaphoreGive
**获取信号量:**xSemaphoreTake
**计数信号量:**可用于资源管理,计数事件
**推迟工作到守护任务:**xTimerPendFunctionCallFromISR()
中断程序使用队列:
中断嵌套
资源访问导致数据损坏的例子:A任务打印hello,A打印到he,B任务抢占A,打印abort,最终结果就是heabortllo。这是不正确的。
**函数重入:**函数可以安全的在多个任务调用,或既可以从中断也可以在任务使用,那么函数就是重入,也称作线程安全。每个任务都维护自己的栈和硬件寄存器值,除了访问栈上的数据或保存至寄存器的数据外,不访问其他数据,就是重入函数。
**相互排斥:**任务之间共享的资源进行访问时,必须使用相互排斥进行管理。使资源不被共享,被单一程序访问。
**临界区:**taskENTER_CRITICAL和taskEXIT_CRITICAL成对使用。FROM_ISR版本的taskENTER_CRITICAL会有返回值,返回值要传递给taskEXIT_CRITICAL。
**暂停调度器:**如果临界区代码过长,可以使用暂停调度器,但恢复调度器操作较慢
**互斥量:**特殊的二进制信号量,获取后必须归还,归还后别的任务才能获取,否则可能死锁。
互斥量和优先级密切相关的概念
互斥量和任务调度
不同优先级任务获取同一互斥量,优先级高的任务先进入运行状态。
如果A,B任务优先级相同,A先获取了互斥量,等到时间片结束切换B,接着回A,释放互斥量,再等到时间片结束,B才能运行
推荐的更平等处理时间的例子
// 记录时间
Xtime = xTaskGetTickCount();
// 释放互斥量
xSemaphoreGive
// 滴答计数变化时,调用切换
if(xTaskGetTickCount() != Xtime)
{
taskYIELD();
}
守门人任务:指对任务拥有唯一所有权的任务,其他需要访问资源的任务只能通过守门人任务。
事件组的特性:
事件组标志是一个布尔值,每一位都代表一个事件是否发生
**事件组创建:**xEventGroupCreate
**事件组位设置:**xEventGroupSetBits
**读取事件组位:**xEventGroupWaitBits
**多任务事件组相互同步:**xEventGroupSync
任务通知允许任务之间交互,不要单独的通信对象。通过任务通知,任务或ISR可以直接向接收任务发送事件。
通常用来替代二值信号量
优势与劣势:
**发送任务通知:**xTaskNotify
**发送任务通知的简单版:**xTaskNotifyGive
**接收任务通知:**xTaskNotifyWait
**接收任务通知的简单版:**ulTaskNotifyTake