作为一个轻量级的操作系统,FreeRTOS 提供的功能包括:任务管理、时间管理、信号量、消息队列、内存管理、记录功能等,可基本满足较小系统的需要。FreeRTOS 内核支持优先级调度算法,每个任务可根据重要程度的不同被赋予一定的优先级,CPU 总是让处于就绪态的、优先级最高的任务先运行。FreeRT0S 内核同时支持轮换调度算法,系统允许不同的任务使用相同的优先级,在没有更高优先级任务就绪的情况下,同一优先级的任务共享CPU的使用时间。
FreeRTOS 的内核可根据用户需要设置为可剥夺型内核或不可剥夺型内核。当FreeRTOS 被设置为可剥夺型内核时,处于就绪态的高优先级任务能剥夺低优先级任务的CPU使用权,这样可保证系统满足实时性的要求;当FreeRTOS 被设置为不可剥夺型内核时,处于就绪态的高优先级任
务只有等当前运行任务主动释放CPU 的使用权后才能获得运行,这样可提高CPU 的运行效率,FreeRTOS对系统任务的数量没有限制。
#define portCHAR char
#define portFLOAT float
#define portDOUBLE double
#define portLONG long
#define portSHORT short
#define portSTACK_TYPE unsigned portLONG
#define portBASE_TYPE long
portBASE_TYPE xTaskCreate(
pdTASK_CODE pvTaskCode,
//指向任务的实现函数的指针。效果上仅仅是函数名
const portCHAR * const pcNane,
//具有描述性的任务名。FreeRTOS 不会使用它。
unsigned portSHORT usStackDepth,
//指定任务堆栈的大小
void *pvParameters,
//指针用于作为一个参数传向创建的任务
unsigned portBASE_TYPE uxPriority,
//任务运行时的优先级
xTaskHandle *pvCreatedTask
//用于传递任务的句柄,可以引用从而对任务进行其他操作。
)
说明:
返回:
void vTaskDelete(
xTaskHandle pxTask
//处理要删除的任务。传递 NULL将删除自己
)
说明:
使用提示:
void vTaskDelay(
portTickType xTicksToDelay
//时间数量,调用任务应该锁住的时间片周期
)
说明:
提示:
void vTaskDelayUntil(
portTickType *pxPreviousWakeTime,
//指定一个变量来掌握任务最后开启的时间, 第一次使用时必须使用
//当前时间来初始化, 在vTaskDelayUntil 中,这个变量是自动修改的
portTickType xTimeIncrement
//循环周期时间
)
说明:
注意:
使用提示:
unsigned portBASE_TYPE uxTaskPriorityGet(
xTaskHandle pxTask
//需要处理的任务. 当传递 NULL 时,将返回调用该任务的优先级
)
说明:
返回:
void vTaskPrioritySet(
xTaskHandle pxTask ,
//需要设置优先级的任务。当传递NULL,将设置调用任务的优先级
unsigned portBASE_TYPE uxNewPriority
//任务需要设置的优先级
)
说明:
void vTaskSuspend(
xTaskHandle pxTaskToSuspend
//处理需要挂起的任务。传递 NULL 将挂起调用此函数的任务
)
说明:
void vTaskResume(
xTaskHandle pxTaskToResume
//就绪任务的句柄
)
说明:
portBase_TYPE xTakResumeFromISR(
xTaskHandle pxTaskToResum
//就绪任务的句柄
)
说明:
返回:
void vTaskSetApplicationTaskTag(
xTaskHandle xTask ,
//将分配给标签值的任务。传递 NULL 将分配标签给调用的任务。
pdTASK_HOOK_CODE pxTagValue
//分配给任务的标签值 类型为 pdTASK_HOOK_CODE 允许一
//个函数指针赋值给标签,因此实际上任何值都可以分配
)
说明:
void vTaskStartScheduler( void );
说明:
void vTaskEndScheduler( void );
说明:
void vTaskSuspendAll( void );
说明:
队列是内部通信的主要形式。它可以用于在任务和任务之间以及任务和中断之间发送消息。在大多数情况下使用线程安全 FIFO(先进先出)缓存,新数据放在队列的最后,虽然数据也可以放在前面。
队列可以包含固定大小的 ‘项目’ - 每个项目的大小和队列可以保存项目的最大数量在创建队列时就已经定义了。
项目以复制而不是引用的方式放入队列,因此最好使放入队列项目的大小成为最小。以复制的方式放入队列可以使你的系统设计极大的简化,因为两个任务不会同时访问数据。队列帮助你管理所有的互斥问题。
如果你希望在队列中使用大的项目,可能最好用插入队列指针 - 但是这样做必须注意要确保你的系统明确定义任务和/或中断是数据的"所有者"。
队列 API 函数可以指定阻塞的时间。阻塞时间代表任务进入阻塞状态或者等待队列中数据时(当任务读取队列但是队列是空的时候)的最大’节拍’数,或者等待队列空间变为可以使用(当任务需要写数据到队列,但是队列已满时)。当一个以上任务在同一个队列中被阻塞时,高优先级的任务先解除阻塞。
头文件:queue.h
xQueueHandle xQueueCreate(
unsigned portBASE_TYPE uxQueueLength,
//队列中包含最大项目数量
unsigned portBASE_TYPE uxItemSize
//队列中每个项目所需的字节数
);
说明:
注意:
返回:
头文件:queue.h
portBASE_TYPE xQueueSend(
xQueueHandle xQueue,
//将项目传进的队列
const void * pvItemToQueue,
//项目的指针【源数据】
portTickType xTicksToWait
//等待的最大时间量【时间使用滴答周期】
);
说明:
注意:
2. 当队列满时,肯定传递不成功,则等待xTicksToWait 个滴答周期后再传递,但如果xTicksToWait 设置为0,调用将立即返回。
返回:
头文件:queue.h
portBASE_TYPE xQueueSendToBack(
xQueueHandle xQueue,
//将项目传进的队列
const void * pvItemToQueue,
//项目的指针【源数据】
portTickType xTicksToWait
//等待的最大时间量
);
说明:这个与xQueueSend 是一样的,参照xQueueSend 的用法
文件:queue.c
portBASE_TYPE xQueueReceive(
xQueueHandle xQueue,
//发送项目的队列句柄
void *pvBuffer,
//指向缓冲区的指针,将接收的项目被复制进去
portTickType xTicksToWait 任务中断并等待队列中可用空间的最大时间
);
说明:
返回:
头文件:queue.h
portBASE_TYPE xQueueSendFromISR(
xQueueHandle pxQueue,
//将项目传进的队列
const void *pvItemToQueue,
//项目的指针【源数据】
portBASE_TYPE *pxHigherPriorityTaskWoken
//因空间数据问题被挂起的任务是否解锁
);
说明:
返回:
头文件:queue.h
portBASE_TYPE xQueueSendToBackFromISR(
xQueueHandle pxQueue,
//将项目传进的队列
const void *pvItemToQueue,
//项目的指针【源数据】
portBASE_TYPE *pxHigherPriorityTaskWoken
//因空间数据问题被挂起的任务是否解锁
);
说明:参照xQueueSendFromISR
头文件:queue.h
portBASE_TYPE xQueueSendToFrontFromISR(
xQueueHandle pxQueue,
//将项目传进的队列
const void *pvItemToQueue,
//项目的指针【源数据】
portBASE_TYPE *pxHigherPriorityTaskWoken
//因空间数据问题被挂起的任务是否解锁
);
说明:参照xQueueSendFromISR
文件:queue.c
portBASE_TYPE xQueueReceiveFromISR(
xQueueHandle pxQueue,
//发送项目的队列句柄
void *pvBuffer,
//指向缓冲区的指针,将接收的项目被复制进去
portBASE_TYPE *pxTaskWoken
//任务将锁住,等待队列中的可用空间
);
说明:
返回:
文件:queue.c
void vQueueAddToRegistry(
xQueueHandle xQueue,
//将要添加登记的队列句柄
signed portCHAR *pcQueueName
//为指定的队列命名。 仅仅是文本串,方便调试。
)
说明:
文件:queue.c
void vQueueUnregisterQueue(
xQueueHandle xQueue
//从登记管理处中移出的队列句柄
);
说明:
头文件:semphr.h
xSemaphoreHandle xSemaphoreCreateCounting(
unsigned portBASE_TYPE uxMaxCount,
//可以达到的最大计数值。
unsigned portBASE_TYPE uxInitialCount
//信号量创建时分配的初始值
)
说明:两种典型应用
事件计数
在这种应用的情形下,事件处理程序会在每次事件发生时发送信号量(增加信号量计数值),而任务处理程序会在每次处理事件时请求信号量(减少信号量计数值)。因此计数值为事件发生与事件处理两者间的差值,在这种情况下计数值初始化为0 是合适的。
资源管理
在这种应用情形下,计数值指示出可用的资源数量。任务必须首先“请求”信号量来获得资源的控制权–减少信号量计数值。当计数值降为0 时表示没有空闲资源。任务使用完资源后“返还”信号量–增加信号量计数值。在这种情况下计数值初始化为与最大的计数值相一致是合适的,这指示出所有的空 闲资源。
返回:
头文件:semphr.h
xSemaphoreHandle xSemaphoreCreateMutex( void )
说明:
通过此宏创建的互斥锁可以使用xSemaphoreTake() 与 xSemaphoreGive() 宏来访问。不能使用xSemaphoreTakeRecursive()与 xSemaphoreGiveRecursive()宏
二元信号量与互斥锁十分相像,不过两者间有细微的差别:互斥锁包含一个优先级继承机制,而信号量没有。这种差别使得二元信号量更适合于实现同步(任务之间或任务与中断之间),互斥锁更适合于实现简单的互斥。
当有另外一个具有更高优先级的任务试图获取同一个互斥锁时,已经获得互斥锁的任务的优先级会被提升。已经获得互斥锁的任务将继承试图获取同一互斥锁的任务的优先级。这意味着互斥锁必须总是要返还的,否则高优先级的任务将永远也不能获取互斥锁,而低优先级的任务将不会放弃优先级的继承。
二元信号量并不需要在得到后立即释放,因此任务同步可以通过一个任务/中断持续释放信号量而另外一个持续获得信号量来实现。
互斥锁与二元信号量均赋值为xSemaphoreHandle 类型,并且可以在任何此类型参数的API 函数中使用。
返回:
xSemaphoreHandle xSemaphoreCreateRecursiveMutex( void )
说明:
通过此宏创建的互斥锁可以使用xSemaphoreTakeRecursive()与 xSemaphoreGiveRecursive()宏 来访问。
不能使用xSemaphoreTake()与 xSemaphoreGive()宏
一个递归的互斥锁可以重复地被其所有者“获取”。在其所有者为每次的成功“获取”请求调用xSemaphoreGiveRecursive()前, 此互斥锁不会再次可用。例如,如果一个任务成功“获取”同一个互斥锁5 次,则在其“释放”互斥锁恰好为5 次后,其他任务才可以使用此互斥锁。
这种类型的信号量使用一个优先级继承机制,因此已取得信号量的任务“必须总是”在不再需要信号量时立刻“释放”。
互斥类型的信号量不能在中断服务程序中使用。
可以参考vSemaphoreCreateBinary()来获得一个二选一运行的实现方式,可以在中断服务程序中实现纯粹的同步(一个任务或中断总是“释放”信号量,而另一个总是“获取”信号量)。
返回:
头文件:semphr.h
xSemaphoreTake(
xSemaphoreHandle xSemaphore,
//将被获得的信号量句柄,此信号量必须已经被创建
portTickType xBlockTime
//等待信号量可用的时钟滴答次数
)
说明:
返回:
xSemaphoreTakeRecursive(
xSemaphoreHandle xMutex,
//将被获得的互斥锁句柄
portTickType xBlockTime
//等待信号量可用的时钟滴答次数
)
说明:
返回:
头文件:semphr.h
xSemaphoreGive(
xSemaphoreHandle xSemaphore
//即将释放的信号量的句柄,在信号量创建是返回
)
返回:
xSemaphoreGiveRecursive(
xSemaphoreHandle xMutex
//将被释放或‘返还’的互斥锁的句柄
)
返回:
头文件:semphr.h
xSemaphoreGiveFromISR(
xSemaphoreHandle xSemaphore,
//将被释放的信号量的句柄
portBASE_TYPE *pxHigherPriorityTaskWoken
//因空间数据问题被挂起的任务是否解锁
)
返回: