首页 > 其他分享 >FreeRTOS--信号量

FreeRTOS--信号量

时间:2023-12-02 18:56:15浏览次数:39  
标签:FreeRTOS -- pxQueue else 信号量 队列 uxInitialCount xSemaphore

示例源码基于FreeRTOS V9.0.0

信号量

1. 概述

消息队列用于传输多个数据,但是有时候只需要传递状态,这个状态值需要用一个数值表示,在这种情况下我们只需要维护一个数值,使用信号量效率更高、更节省内存。

信号量用来表示资源的个数,它是特殊的队列实现,队列数据项为空。

对于二值信号量,队列深度为1,对于计数型信号量,队列深度非0。队列的大小uxMessagesWaiting即表示了信号量值,也就是资源个数。

生成或释放资源时,采用give操作,资源数加1,申请资源时,采用take操作,资源数减1。

2. 接口API

2.1 创建二值信号量

// 定义在semphr.h 中
#define semSEMAPHORE_QUEUE_ITEM_LENGTH		( ( uint8_t ) 0U )

#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
	#define vSemaphoreCreateBinary( xSemaphore )																							\
		{																																	\
			( xSemaphore ) = xQueueGenericCreate( ( UBaseType_t ) 1, semSEMAPHORE_QUEUE_ITEM_LENGTH, queueQUEUE_TYPE_BINARY_SEMAPHORE );	\
			if( ( xSemaphore ) != NULL )																									\
			{																																\
				( void ) xSemaphoreGive( ( xSemaphore ) );																					\
			}																																\
		}
#endif

#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
	#define xSemaphoreCreateBinary() xQueueGenericCreate( ( UBaseType_t ) 1, semSEMAPHORE_QUEUE_ITEM_LENGTH, queueQUEUE_TYPE_BINARY_SEMAPHORE )
#endif

#if( configSUPPORT_STATIC_ALLOCATION == 1 )
	#define xSemaphoreCreateBinaryStatic( pxStaticSemaphore ) xQueueGenericCreateStatic( ( UBaseType_t ) 1, semSEMAPHORE_QUEUE_ITEM_LENGTH, NULL, pxStaticSemaphore, queueQUEUE_TYPE_BINARY_SEMAPHORE )
#endif
  • vSemaphoreCreateBinary是旧版的创建信号量的接口,创建信号量后计数值初始为1;
  • xSemaphoreCreateBinary是新版的创建信号量的接口,创建信号量后计数值初始为0;
  • xSemaphoreCreateBinaryStatic是静态创建信号量的接口,创建信号量后计数值初始为0;

创建信号量的本质就是创建队列,二值信号量队列的深度是1,数据项大小为0。

队列的创建见 队列

2.2 创建计数型信号量

// 定义在semphr.h 中
#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
	#define xSemaphoreCreateCounting( uxMaxCount, uxInitialCount ) xQueueCreateCountingSemaphore( ( uxMaxCount ), ( uxInitialCount ) )
#endif

#if( configSUPPORT_STATIC_ALLOCATION == 1 )
	#define xSemaphoreCreateCountingStatic( uxMaxCount, uxInitialCount, pxSemaphoreBuffer ) xQueueCreateCountingSemaphoreStatic( ( uxMaxCount ), ( uxInitialCount ), ( pxSemaphoreBuffer ) )
#endif /* configSUPPORT_STATIC_ALLOCATION */
  • xSemaphoreCreateCounting用于动态创建计数型信号量,资源总数为uxMaxCount,初始计数值为uxInitialCount;
  • xSemaphoreCreateCountingStatic用于静态创建计数型信号量,资源总数为uxMaxCount,初始计数值为uxInitialCount;

xSemaphoreCreateCounting实际调用的是xQueueCreateCountingSemaphore,实现如下:

// 定义在queue.c
#if( ( configUSE_COUNTING_SEMAPHORES == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) )

    QueueHandle_t xQueueCreateCountingSemaphore( const UBaseType_t uxMaxCount, const UBaseType_t uxInitialCount )
    {
    QueueHandle_t xHandle;

        configASSERT( uxMaxCount != 0 );
        configASSERT( uxInitialCount <= uxMaxCount );

        xHandle = xQueueGenericCreate( uxMaxCount, queueSEMAPHORE_QUEUE_ITEM_LENGTH, queueQUEUE_TYPE_COUNTING_SEMAPHORE );

        if( xHandle != NULL )
        {
            ( ( Queue_t * ) xHandle )->uxMessagesWaiting = uxInitialCount;

            traceCREATE_COUNTING_SEMAPHORE();
        }
        else
        {
            traceCREATE_COUNTING_SEMAPHORE_FAILED();
        }

        return xHandle;
    }

#endif /* ( ( configUSE_COUNTING_SEMAPHORES == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) ) */

xQueueCreateCountingSemaphore也是调用的xQueueGenericCreate用于创建队列,队列深度uxMaxCount即为资源总数,数据项大小为0,队列大小uxMessagesWaiting即为资源计数,初始计数为uxInitialCount;

xSemaphoreCreateCountingStatic实际调用的是xQueueCreateCountingSemaphoreStatic,实现如下:

// 定义在queue.c
#if( ( configUSE_COUNTING_SEMAPHORES == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 1 ) )

    QueueHandle_t xQueueCreateCountingSemaphoreStatic( const UBaseType_t uxMaxCount, const UBaseType_t uxInitialCount, StaticQueue_t *pxStaticQueue )
    {
    QueueHandle_t xHandle;

        configASSERT( uxMaxCount != 0 );
        configASSERT( uxInitialCount <= uxMaxCount );

        xHandle = xQueueGenericCreateStatic( uxMaxCount, queueSEMAPHORE_QUEUE_ITEM_LENGTH, NULL, pxStaticQueue, queueQUEUE_TYPE_COUNTING_SEMAPHORE );

        if( xHandle != NULL )
        {
            ( ( Queue_t * ) xHandle )->uxMessagesWaiting = uxInitialCount;

            traceCREATE_COUNTING_SEMAPHORE();
        }
        else
        {
            traceCREATE_COUNTING_SEMAPHORE_FAILED();
        }

        return xHandle;
    }

#endif /* ( ( configUSE_COUNTING_SEMAPHORES == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) ) */

xSemaphoreCreateCountingStatic也是调用的xQueueGenericCreateStatic用于创建队列,队列深度uxMaxCount即为资源总数,数据项大小为0,队列大小uxMessagesWaiting即为资源计数,初始计数为uxInitialCount;

2.3 删除信号量

对于动态创建的信号量,二值信号量和计数型信号量均使用同一个接口vSemaphoreDelete来删除信号量。

// 定义在semphr.h 中
#define vSemaphoreDelete( xSemaphore ) vQueueDelete( ( QueueHandle_t ) ( xSemaphore ) )

实质也是删除队列。

2.4 获取信号量

获取信号量,即take操作,二值信号量和计数型信号量均使用同一个接口xSemaphoreTake来获取信号量。

// 定义在semphr.h 中
#define xSemaphoreTake( xSemaphore, xBlockTime )		xQueueGenericReceive( ( QueueHandle_t ) ( xSemaphore ), NULL, ( xBlockTime ), pdFALSE )
#define xSemaphoreTakeFromISR( xSemaphore, pxHigherPriorityTaskWoken )	xQueueReceiveFromISR( ( QueueHandle_t ) ( xSemaphore ), NULL, ( pxHigherPriorityTaskWoken ) )

xSemaphoreTake实质是调用队列的接收接口xQueueGenericReceive,传入的pvBuffer为NULL。

xSemaphoreTakeFromISR是xSemaphoreTake的中断版本。

2.5 释放信号量

释放信号量,即give操作,二值信号量和计数型信号量均使用同一个接口xSemaphoreGive来获取信号量。

// 定义在semphr.h 中
#define xSemaphoreGive( xSemaphore )		xQueueGenericSend( ( QueueHandle_t ) ( xSemaphore ), NULL, semGIVE_BLOCK_TIME, queueSEND_TO_BACK )
#define xSemaphoreGiveFromISR( xSemaphore, pxHigherPriorityTaskWoken )	xQueueGiveFromISR( ( QueueHandle_t ) ( xSemaphore ), ( pxHigherPriorityTaskWoken ) )

xSemaphoreGive实质是调用队列的发送接口xQueueGenericSend,传入的数据项指针pvItemToQueue为NULL。

xSemaphoreGiveFromISR是xSemaphoreGive的中断版本,调用xQueueGiveFromISR实现,其实现基本雷同xQueueGenericSendFromISR。

BaseType_t xQueueGiveFromISR( QueueHandle_t xQueue, BaseType_t * const pxHigherPriorityTaskWoken )
{
BaseType_t xReturn;
UBaseType_t uxSavedInterruptStatus;
Queue_t * const pxQueue = ( Queue_t * ) xQueue;

    /* Similar to xQueueGenericSendFromISR() but used with semaphores where the
    item size is 0.  Don't directly wake a task that was blocked on a queue
    read, instead return a flag to say whether a context switch is required or
    not (i.e. has a task with a higher priority than us been woken by this
    post). */

    configASSERT( pxQueue );

    /* xQueueGenericSendFromISR() should be used instead of xQueueGiveFromISR()
    if the item size is not 0. */
    configASSERT( pxQueue->uxItemSize == 0 );

    /* Normally a mutex would not be given from an interrupt, especially if
    there is a mutex holder, as priority inheritance makes no sense for an
    interrupts, only tasks. */
    configASSERT( !( ( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX ) && ( pxQueue->pxMutexHolder != NULL ) ) );

    /* RTOS ports that support interrupt nesting have the concept of a maximum
    system call (or maximum API call) interrupt priority.  Interrupts that are
    above the maximum system call priority are kept permanently enabled, even
    when the RTOS kernel is in a critical section, but cannot make any calls to
    FreeRTOS API functions.  If configASSERT() is defined in FreeRTOSConfig.h
    then portASSERT_IF_INTERRUPT_PRIORITY_INVALID() will result in an assertion
    failure if a FreeRTOS API function is called from an interrupt that has been
    assigned a priority above the configured maximum system call priority.
    Only FreeRTOS functions that end in FromISR can be called from interrupts
    that have been assigned a priority at or (logically) below the maximum
    system call	interrupt priority.  FreeRTOS maintains a separate interrupt
    safe API to ensure interrupt entry is as fast and as simple as possible.
    More information (albeit Cortex-M specific) is provided on the following
    link: http://www.freertos.org/RTOS-Cortex-M3-M4.html */
    portASSERT_IF_INTERRUPT_PRIORITY_INVALID();

    uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();
    {
        const UBaseType_t uxMessagesWaiting = pxQueue->uxMessagesWaiting;

        /* When the queue is used to implement a semaphore no data is ever
        moved through the queue but it is still valid to see if the queue 'has
        space'. */
        if( uxMessagesWaiting < pxQueue->uxLength )
        {
            const int8_t cTxLock = pxQueue->cTxLock;

            traceQUEUE_SEND_FROM_ISR( pxQueue );

            /* A task can only have an inherited priority if it is a mutex
            holder - and if there is a mutex holder then the mutex cannot be
            given from an ISR.  As this is the ISR version of the function it
            can be assumed there is no mutex holder and no need to determine if
            priority disinheritance is needed.  Simply increase the count of
            messages (semaphores) available. */
            pxQueue->uxMessagesWaiting = uxMessagesWaiting + 1;

            /* The event list is not altered if the queue is locked.  This will
            be done when the queue is unlocked later. */
            if( cTxLock == queueUNLOCKED )
            {
                #if ( configUSE_QUEUE_SETS == 1 )
                {
                    if( pxQueue->pxQueueSetContainer != NULL )
                    {
                        if( prvNotifyQueueSetContainer( pxQueue, queueSEND_TO_BACK ) != pdFALSE )
                        {
                            /* The semaphore is a member of a queue set, and
                            posting	to the queue set caused a higher priority
                            task to	unblock.  A context switch is required. */
                            if( pxHigherPriorityTaskWoken != NULL )
                            {
                                *pxHigherPriorityTaskWoken = pdTRUE;
                            }
                            else
                            {
                                mtCOVERAGE_TEST_MARKER();
                            }
                        }
                        else
                        {
                            mtCOVERAGE_TEST_MARKER();
                        }
                    }
                    else
                    {
                        if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE )
                        {
                            if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )
                            {
                                /* The task waiting has a higher priority so
                                record that a context switch is required. */
                                if( pxHigherPriorityTaskWoken != NULL )
                                {
                                    *pxHigherPriorityTaskWoken = pdTRUE;
                                }
                                else
                                {
                                    mtCOVERAGE_TEST_MARKER();
                                }
                            }
                            else
                            {
                                mtCOVERAGE_TEST_MARKER();
                            }
                        }
                        else
                        {
                            mtCOVERAGE_TEST_MARKER();
                        }
                    }
                }
                #else /* configUSE_QUEUE_SETS */
                {
                    if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE )
                    {
                        if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )
                        {
                            /* The task waiting has a higher priority so record that a
                            context	switch is required. */
                            if( pxHigherPriorityTaskWoken != NULL )
                            {
                                *pxHigherPriorityTaskWoken = pdTRUE;
                            }
                            else
                            {
                                mtCOVERAGE_TEST_MARKER();
                            }
                        }
                        else
                        {
                            mtCOVERAGE_TEST_MARKER();
                        }
                    }
                    else
                    {
                        mtCOVERAGE_TEST_MARKER();
                    }
                }
                #endif /* configUSE_QUEUE_SETS */
            }
            else
            {
                /* Increment the lock count so the task that unlocks the queue
                knows that data was posted while it was locked. */
                pxQueue->cTxLock = ( int8_t ) ( cTxLock + 1 );
            }

            xReturn = pdPASS;
        }
        else
        {
            traceQUEUE_SEND_FROM_ISR_FAILED( pxQueue );
            xReturn = errQUEUE_FULL;
        }
    }
    portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus );

    return xReturn;
}

2.6 关于prvCopyDataToQueue和prvCopyDataFromQueue的说明

申请和释放信号量,调用的是队列的Send和Receive系列函数,涉及到入队和出队的操作,即prvCopyDataToQueue和prvCopyDataFromQueue。

由于信号量的uxItemSize=0,所以,

  • 对于入队prvCopyDataToQueue,仅将uxMessagesWaiting加1;
  • 对于出队prvCopyDataFromQueue,不处理;

3. 总结

二值信号量 计数型信号量
动态创建 xSemaphoreCreateBinary 计数值初始值为0 xSemaphoreCreateCounting
vSemaphoreCreateBinary(过时了) 计数值初始值为1
静态创建 xSemaphoreCreateBinaryStatic xSemaphoreCreateCountingStatic
在任务中使用 在ISR中使用
give xSemaphoreGive xSemaphoreGiveFromISR
take xSemaphoreTake xSemaphoreTakeFromISR

参考链接

百问网 FreeRTOS入门与工程实践-基于STM32F103 第12章信号量(semaphore)

标签:FreeRTOS,--,pxQueue,else,信号量,队列,uxInitialCount,xSemaphore
From: https://www.cnblogs.com/hjx168/p/17872024.html

相关文章

  • python第四次笔记
    循环和字符串循环for循环forxinrange(x,y)forxinrange(1,10,2):print(int(x))表示遍历1到9之间的数,步长为2即打印13579while循环while(条件):执行行为whileTrue:print("nihao")这个代码会一直打印nihaocontinuebreakpasscontinue用于跳出本......
  • 何为魔怔
    魔怔于我而言,是一种坚定信念、抒发感情的活动。而文学于我而言,是一种更精彩的文字对现实的展现。魔怔什么时候是文学?它某种意义上是魔幻现实主义的一种素材,在我眼里它是一种零散的,比日记还要微小的一种文章碎片,它不完整,更确切的说是某些瞬间从大脑飘过去的灵感,一些思绪揉成的团......
  • 第二章 链表part01
    第二章链表part01203.移除链表元素  Code:/***Definitionforsingly-linkedlist.*structListNode{*  intval;*  ListNode*next;*  ListNode():val(0),next(nullptr){}*  ListNode(intx):val(x),next(nullptr){}*  L......
  • 解析几何笔记:仿射坐标系
    目录仿射坐标系不共面向量基向量仿射标架(仿射坐标系)直角标架(直角坐标系)向量共线(共面)两向量共线三向量共面应用仿射标架下的三点共线条件线段的定比分点空间直线和平面仿射坐标系中的平面两平面的位置关系三平面交于一点参考仿射坐标系不共面向量定理1空间中任意给定三个不共......
  • 引用类型变量
     1.基本概念:存放对象的引用,而不是存放对象本身。通过引用可以找到该对象。(可以为空null)Personp1=newPerson();p1.name="Fiona";p1.age=22;Personp2=newPerson();p2.name="Lip";p2.age=18;//其中p1,p2为引用类型变量 2.使......
  • 如何解决Redis缓存雪崩、缓存穿透、缓存并发等5大难题
    缓存雪崩数据末加载到缓存中,或者缓存同一时间大面积的失效,从而导致所有请求都去查数据库,导致数据库CPU和内存负载过高,甚至宕机。比如一个雪崩的简单过程1、redis集群大面积故障2、缓存失效,但依然大量请求访问缓存服务redis3、redis大量失效后,大量请求转向到mysql数据库4、mysql的......
  • 软件设计9
    [实验任务一]:两个维度的桥接模式用桥接模式实现在路上开车这个问题,其中,车可以是car或bus,路可以是水泥路或沥青路。实验要求:1. 画出对应的类图;  2. 提交源代码;//Road.javapackageshiyan9; publicabstractclassRoad{    protectedVehiclevehicle;  ......
  • AgglomerativeClustering
    AgglomerativeClustering 层次聚类fromsklearn.clusterimportAgglomerativeClusteringAgglomerativeClustering ←官方网页的函数说明一、参数说明classsklearn.cluster.AgglomerativeClustering(n_clusters=2,*,affinity='deprecated',metric=......
  • SAP ABAP 系统里事务码 SMICM 的作用
    "SMICM"是SAP系统中的一个事务码,用于管理和监控SAP系统的通信管理。这个事务码的全名是"ICMMonitor",其中"ICM"代表"InternetCommunicationManager"。SMICM提供了一系列功能,帮助管理员监视和维护SAP系统的通信基础设施。SMICM的主要作用:监控服务和端口:SMICM......
  • SAP ABAP 系统里的事务码 SMICM keep Alive 参数的作用
    SMICM截图如下:SAPABAP系统中的事务码SMICM是用来访问InternetCommunicationManager(ICM)的监视。ICM是SAP系统中负责HTTP、SMTP、或者HTTPS通信的组件。在SMICM事务中,你可以看到关于ICM的各种信息,例如线程信息、服务信息、连接信息和缓存信息等。在服务列......