文章目录
- 基础知识
- 创建信号量
- 获取信号量
- 释放信号量
- 信号量 内部实现框图
基础知识
[FreeRTOS 基础知识] 信号量 概念
创建信号量
#define queueQUEUE_TYPE_BINARY_SEMAPHORE ( ( uint8_t ) 3U )
#define semSEMAPHORE_QUEUE_ITEM_LENGTH ( ( uint8_t ) 0U )
#define xSemaphoreCreateBinary() xQueueGenericCreate( ( UBaseType_t ) 1, semSEMAPHORE_QUEUE_ITEM_LENGTH, queueQUEUE_TYPE_BINARY_SEMAPHORE )
根据上面的定义,可知创建信号量本质就是创建队列。长度(第一个参数)为1,大小(第二个参数)为0
QueueHandle_t xQueueGenericCreate( const UBaseType_t uxQueueLength, const UBaseType_t uxItemSize, const uint8_t ucQueueType )
-> if( uxItemSize == ( UBaseType_t ) 0 ) xQueueSizeInBytes = ( size_t ) 0;
-> pxNewQueue = ( Queue_t * ) pvPortMalloc( sizeof( Queue_t ) + xQueueSizeInBytes ); // 动态分配大小,只有一个Queue_t结构体大小
获取信号量
通过队列获取信号量
#define xSemaphoreTake( xSemaphore, xBlockTime ) xQueueSemaphoreTake( ( xSemaphore ), ( xBlockTime ) )
BaseType_t xQueueSemaphoreTake( QueueHandle_t xQueue, TickType_t xTicksToWait )
for( ;; )
{
taskENTER_CRITICAL(); // 关中断
{
const UBaseType_t uxSemaphoreCount = pxQueue->uxMessagesWaiting; // 获取当前信号量值
if( uxSemaphoreCount > ( UBaseType_t ) 0 ) // 信号量值大于0
{
traceQUEUE_RECEIVE( pxQueue );
pxQueue->uxMessagesWaiting = uxSemaphoreCount - ( UBaseType_t ) 1; // 信号量-1
// 检查是否有其他任务阻塞等待信号量。
if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE )
{
// 如果是,解除阻塞最高优先级的任务。
// 1、将最高阻塞任务从xTasksWaitingToSend链表中移除;
// 2、将最高阻塞任务从从DelayList移动到ReadyList链表
if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE )
{
queueYIELD_IF_USING_PREEMPTION(); // 让出CPU使用权
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
else
{
mtCOVERAGE_TEST_MARKER();
}
taskEXIT_CRITICAL(); //开中断
return pdPASS; // 返回成功
}
else
{
if( xTicksToWait == ( TickType_t ) 0 ) // 是否愿意等待
{
// 不愿意等待
taskEXIT_CRITICAL(); // 打开中断
traceQUEUE_RECEIVE_FAILED( pxQueue );
return errQUEUE_EMPTY; // 返回队列空失败
}
else if( xEntryTimeSet == pdFALSE )
{
// 信号量计数为0,阻塞时间被指定,所以配置超时结构准备阻塞。
vTaskInternalSetTimeOutState( &xTimeOut );
xEntryTimeSet = pdTRUE;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
}
taskEXIT_CRITICAL();
vTaskSuspendAll();
prvLockQueue( pxQueue );
if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE )
{
if( prvIsQueueEmpty( pxQueue ) != pdFALSE )
{
traceBLOCKING_ON_QUEUE_RECEIVE( pxQueue );
// 1、当前的任务加入到队列的xTasksWaitingToReceive链表中;
// 2、当前的任务从ReadyList移动到DelayList
vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait );
prvUnlockQueue( pxQueue );
if( xTaskResumeAll() == pdFALSE )
{
portYIELD_WITHIN_API();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
else
{
prvUnlockQueue( pxQueue );
( void ) xTaskResumeAll();
}
}
else
{
...
}
释放信号量
#define semGIVE_BLOCK_TIME ( ( TickType_t ) 0U )
#define xSemaphoreGive( xSemaphore ) xQueueGenericSend( ( QueueHandle_t ) ( xSemaphore ), NULL, semGIVE_BLOCK_TIME, queueSEND_TO_BACK )
BaseType_t xQueueGenericSend( QueueHandle_t xQueue, const void * const pvItemToQueue, TickType_t xTicksToWait, const BaseType_t xCopyPosition )
->
for( ;; )
{
taskENTER_CRITICAL(); // 关中断 portDISABLE_INTERRUPTS();
{
if( ( pxQueue->uxMessagesWaiting < pxQueue->uxLength ) || ( xCopyPosition == queueOVERWRITE ) ) // 判断当前信号量是否超过队列信号量长度
{
traceQUEUE_SEND( pxQueue );
xYieldRequired = prvCopyDataToQueue( pxQueue, pvItemToQueue, xCopyPosition );
// 不会写数据,但是会将 uxMessagesWaiting +1
if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE ) // 判断xTasksWaitingToReceive队列里是否有等待的任务
{
if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE ) // 1、将要写的任务从xTasksWaitingToReceive移除;2、将要写的任务从DelayList移动到ReadyList
{
queueYIELD_IF_USING_PREEMPTION(); //让出CPU使用权
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
else if( xYieldRequired != pdFALSE )
{
queueYIELD_IF_USING_PREEMPTION();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
taskEXIT_CRITICAL(); // 开中断
return pdPASS; // 返回成功
}
else
{
if( xTicksToWait == ( TickType_t ) 0 )
{
taskEXIT_CRITICAL();
traceQUEUE_SEND_FAILED( pxQueue );
return errQUEUE_FULL; // 返回队列已满
}
else if( xEntryTimeSet == pdFALSE )
{
vTaskInternalSetTimeOutState( &xTimeOut ); // 阻塞时间被指定,所以配置超时结构。
xEntryTimeSet = pdTRUE;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
}
taskEXIT_CRITICAL(); // 开中断
vTaskSuspendAll();
prvLockQueue( pxQueue );
if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE )
{
if( prvIsQueueFull( pxQueue ) != pdFALSE )
{
traceBLOCKING_ON_QUEUE_SEND( pxQueue );
// 1、当前的任务加入到队列的xTasksWaitingToSend链表中;
// 2、当前的任务从ReadyList移动到DelayList
vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToSend ), xTicksToWait );
prvUnlockQueue( pxQueue );
if( xTaskResumeAll() == pdFALSE )
{
portYIELD_WITHIN_API();
}
}
else
{
prvUnlockQueue( pxQueue );
( void ) xTaskResumeAll();
}
}
else
{
prvUnlockQueue( pxQueue );
( void ) xTaskResumeAll();
traceQUEUE_SEND_FAILED( pxQueue );
return errQUEUE_FULL;
}
}