五:信号量
使用已存在的队列结构来创建计数型信号量
头文件:semphr. H
xSemaphoreHandle xSemaphoreCreateCounting (
unsigned portBASE_TYPE uxMaxCount, 可以达到的最大计数值。
unsigned portBASE_TYPE uxInitialCount 信号量创建时分配的初始值
)
说明:两种典型应用
事件计数
在这种应用的情形下,事件处理程序会在每次事件发生时发送信号量(增加信号量计数值),而任务处理程序会在每次处理事件时请求信号量(减少信号量计数值)。因此计数值为事件发生与事件处理两者间的差值,在这种情况下计数值初始化为0 是合适的。
资源管理
在这种应用情形下,计数值指示出可用的资源数量。任务必须首先“请求”信号量来获得资源的控制权--减少信号量计数值。当计数值降为0 时表示没有空闲资源。任务使用完资源后“返还”信号量--增加信号量计数值。在这种情况下计数值初始化为与最大的计数值相一致是合适的,这指示出所有的空闲资源。
返回:已创建的信号量句柄,为xSemaphoreHandle 类型,如果信号量无法创建则为NULL。
使用已存在的队列结构来创建互斥锁信号量的宏
头文件:semphr. H
xSemaphoreHandle xSemaphoreCreateMutex ( void )
说明: 通过此宏创建的互斥锁可以使用xSemaphoreTake() 与 xSemaphoreGive() 宏来访问。不能使用
xSemaphoreTakeRecursive()与 xSemaphoreGiveRecursive()宏
二元信号量与互斥锁十分相像,不过两者间有细微的差别:互斥锁包含一个优先级继承机制,而信号量没有。这种差别使得二元信号量更适合于实现同步(任务之间或任务与中断之间),互斥锁更适合于实现简单的互斥。
当有另外一个具有更高优先级的任务试图获取同一个互斥锁时,已经获得互斥锁的任务的优先级会被提升。已经获得互斥锁的任务将继承试图获取同一互斥锁的任务的优先级。这意味着互斥锁必须总是要返还的,否则高优先级的任务将永远也不能获取互斥锁,而低优先级的任务将不会放弃优先级的继承。
二元信号量并不需要在得到后立即释放,因此任务同步可以通过一个任务/中断持续释放信号量而另外一个持续获得信号量来实现。
互斥锁与二元信号量均赋值为xSemaphoreHandle 类型,并且可以在任何此类型参数的API 函数中使用。
返回: 已创建的信号量句柄,需要为xSemaphoreHandle 类型。
使用已存在的队列结构来创建递归互斥锁的宏
头文件:semphr. H
xSemaphoreHandle xSemaphoreCreateRecursiveMutex ( void )
说明:通过此宏创建的互斥锁可以使用xSemaphoreTakeRecursive()与 xSemaphoreGiveRecursive()宏 来访问。
不能使用xSemaphoreTake()与 xSemaphoreGive()宏
一个递归的互斥锁可以重复地被其所有者“获取”。在其所有者为每次的成功“获取”请求调用xSemaphoreGiveRecursive()前,此互斥锁不会再次可用。例如,如果一个任务成功“获取”同一个互斥锁5 次,则在其“释放”互斥锁恰好为5 次后,其他任务才可以使用此互斥锁。
这种类型的信号量使用一个优先级继承机制,因此已取得信号量的任务“必须总是”在不再需要信号量时立刻“释放”。
互斥类型的信号量不能在中断服务程序中使用。
可以参考vSemaphoreCreateBinary()来获得一个二选一运行的实现方式,可以在中断服务程序中实现纯粹的同步(一个任务或中断总是“释放”信号量,而另一个总是“获取”信号量)。
返回: 已创建的信号量句柄,需要为xSemaphoreHandle 类型。
获取信号量的宏 头文件:semphr. H
xSemaphoreTake (
xSemaphoreHandle xSemaphore, 将被获得的信号量句柄,此信号量必须已经被创建
portTickType xBlockTime 等待信号量可用的时钟滴答次数
)
说明:当信号量不可用时,则等待xBlockTime 个时钟滴答,再看是否可用,当是为0 时如果不可用,则立即退出,因此为0 时可以达到对信号量轮询的作用。
返回:如果成功获取信号量则返回pdTRUE,如果xBlockTime 超时而信号量还未可用则返回pdFALSE。
递归获得互斥锁信号量的宏
头文件:semphr. H
xSemaphoreTakeRecursive (
xSemaphoreHandle xMutex, 将被获得的互斥锁句柄
portTickType xBlockTime 等待信号量可用的时钟滴答次数
)
说明:FreeRTOSConfig.h 中的configUSE_RECURSIVE_MUTEXES 必须设置为1 才可以使用此宏。一个递归型的互斥锁可以被其所有者重复地“获取”, 在其所有者为每次成功的“获取”请求调用xSemaphoreGiveRecursive()前,此互斥锁不会再次可用。
返回:如果成功获取信号量则返回pdTRUE,如果xBlockTime 超时而信号量还未可用则返回pdFALSE。
释放信号量的宏
头文件:semphr. H
xSemaphoreGive (
xSemaphoreHandle xSemaphore 即将释放的信号量的句柄,在信号量创建是返回
)
返回:如果信号量成功释放返回pdTRUE,如果发生错误则返回pdFALSE。信号量使用的是队列,因此如果队列没有位置用于发送消息就会发生一个错误——说明开始时没有正确获取信号量。
用于递归释放,或‘返还’,互斥锁信号量的宏
头文件:semphr. H
xSemaphoreGiveRecursive (
xSemaphoreHandle xMutex 将被释放或‘返还’的互斥锁的句柄
)
返回:如果信号量成功释放则为pdTRUE
从中断释放一个信号量的宏
头文件:semphr. H
xSemaphoreGiveFromISR (
xSemaphoreHandle xSemaphore, 将被释放的信号量的句柄
portBASE_TYPE *pxHigherPriorityTaskWoken 因空间数据问题被挂起的任务是否解锁
)
返回:如果信号量成功释放则返回pdTRUE,否则返回errQUEUE_FULL
六:联合函数
一个联合程序可以以下面的状态中的一种存在:
运行:当一个联合程序正在执行时它就是处于运行状态,它就占用了处理器。
就绪:就绪状态的联合程序是那些可以执行(没有被阻塞)但是还没有被执行的程序。一个联合程序可能处于就绪状态是因为另外一个相同或高优先级的联合程序正处于运行状态,或一个任务处于运行状态——这只会在系统同时使用了任务和联合程序时发生。
阻塞:如果一个联合程序正处于暂时等待或等待外部事件,它就是处于阻塞状态。例如,联合程序调用 crDELAY()它就会被阻塞(放入到阻塞状态)直到达到延时时间 - 一个临时事件。被阻塞的联合程序不会被调度。
有效的联合程序状态转换
联合程序属性:
每个联合程序被分配一个从 0 到 ( configMAX_CO_ROUTINE_PRIORITIES - 1 ) 的优先级。
configMAX_CO_ROUTINE_PRIORITIES 在 FreeRTOSConfig.h 中定义并在基本系统中设置。
configMAX_CO_ROUTINE_PRIORITIES 的数值越大 FreeRTOS 消耗的 RAM 越多。
低优先级联合程序使用小数值。
联合程序优先级只针对其他联合程序,任务的优先级总是高于联合程序
创建一个新的联合程序并且将其增加到联合程序的就绪列表中
头文件:croutine.h
portBASE_TYPE xCoRoutineCreate (
crCOROUTINE_CODE pxCoRoutineCode, 联合程序函数的指针
unsigned portBASE_TYPE uxPriority, 优先级
unsigned portBASE_TYPE uxIndex 当不同的联合程序使用同一个函数来运行时用于相互识别
);
返回:如果联合程序成功创建并增加到就绪列表中则返回pdPASS,否则返回ProjDefs.h 中定义的错误代码
把一个联合程序延时一个特定的时间
头文件:croutine.h
void crDELAY (
xCoRoutineHandle xHandle, 要延时的联合程序的句柄
portTickType xTicksToDelay 联合程序要延时的时间片数
)
联合程序向其他联合程序发送数据
头文件:croutine.h
crQUEUE_SEND (
xCoRoutineHandle xHandle, 调用的联合程序的句柄
xQueueHandle pxQueue, 数据将被发送到的队列的句柄
void *pvItemToQueue, 将被发送到队列的数据的指针
portTickType xTicksToWait, 如果此刻队列没有可用空间,此值为联合程序用于阻塞等待队列空间可用的时间片数。
portBASE_TYPE *pxResult 一个指向pxResult 变量的指针,如果数据成功发送到队列就会被设置为
pdPASS,否则设置为 ProjDefs.h 中定义的错误码。
)
联合程序接受其他联合程序发送的数据
头文件:croutine.h
void crQUEUE_RECEIVE(
xCoRoutineHandle xHandle,
xQueueHandle pxQueue,
void *pvBuffer,
portTickType xTicksToWait,
portBASE_TYPE *pxResult
)
说明:同上
中断处理程序向联合程序发送数据
头文件:croutine.h
portBASE_TYPE crQUEUE_SEND_FROM_ISR(
xQueueHandle pxQueue, 将发送到的队列的句柄
void *pvItemToQueue, 将被发送到队列的条目的指针
portBASE_TYPE xCoRoutinePreviouslyWoken
)
联合程序向中断处理程序发送数据
头文件:croutine.h
portBASE_TYPE crQUEUE_SEND_FROM_ISR(
xQueueHandle pxQueue,
void *pvBuffer,
portBASE_TYPE * pxCoRoutineWoken
)
运行一个联合程序
头文件:croutine.h
void vCoRoutineSchedule ( void );
说明:vCoRoutineSchedule() 与性具有最高优先级的就绪联合程序。此联合程序将运行,直到其阻塞,让出系统或被任务抢占。联合程序是合作式运行的,所以一个联合程序不会被另一个联合程序抢占,但是可以被任务抢占。
如果一个应用程序同时包含任务与联合程序,则vCoRoutineSchedule 应该在空闲任务中调用(在一个空闲任务钩子中)
评论
查看更多