ESP32 FreeRTOS-Semaphore(8)

Tip: A good memory is not as good as a bad pen. This blog is used as a study note, if there is a mistake, I hope to correct it

Foreword:

  References: FreeRTOS API
  Reference Semaphores are also very important in freeRTOS. We have to use global variables for some resources. At this time, multiple tasks will access this variable. In this case, we can use mutex semaphores. In addition We can also use semaphores to achieve task-to-task synchronization.

1. Binary semaphore

1.1、xSemaphoreCreateBinary()

API prototype:

SemaphoreHandle_t xSemaphoreCreateBinary(void);

Tip: In many usage scenarios, using direct task notifications is faster and more memory-efficient than using secondary entry numbers.

  Creates a binary semaphore and returns a handle that can refer to the semaphore. configSUPPORT_DYNAMIC_ALLOCATION must be set to 1 in FreeRTOSConfig.h, or left undefined (in which case it will default to 1) for this RTOS API function to be available.
  Each binary semaphore requires a small amount of RAM to hold the state of the semaphore. If a binary semaphore is created using xSemaphoreCreateBinary(), the required RAM is automatically allocated from the FreeRTOS heap. RAM is provided by the application writer if the binary semaphore is created using xSemaphoreCreateBinaryStatic(), which requires an additional parameter but allows static allocation of RAM at compile time. See the Static vs. Dynamic Allocation page for details.
  A semaphore is created in an "empty" state, which means that the semaphore must first be given using the xSemaphoreGive() API function before it can be taken (taken) using the xSemaphoreTake() function.
  Binary semaphores and mutexes are very similar, with some minor differences: mutexes include a priority inheritance mechanism, binary semaphores do not. This makes binary semaphores a better choice for implementing synchronization (either between tasks or between tasks and interrupts), and mutexes a better choice for implementing simple mutual exclusion.
  A binary semaphore does not need to be returned once acquired, so task synchronization can be achieved by one task/interrupt continuously "giving" the semaphore while the other continuously "acquires" the semaphore. The sample code on the xSemaphoreGiveFromISR() documentation page demonstrates this. Note that the same functionality can often be achieved in a more efficient manner using direct task notifications.
  If another higher priority task tries to acquire the same mutex, the priority of the task that "acquired" the mutex may be increased. A task that owns a mutex "inherits" the priority of a task that tries to "acquire" the same mutex. This means that the mutex must always be "returned" - otherwise higher priority tasks will never be able to acquire the mutex, and lower priority tasks will never "deprive" the priority. An example of a mutex used to implement mutual exclusion is available on the xSemaphoreTake() documentation page.
  Both mutexes and binary semaphores are referenced by variables of type SemaphoreHandle_t and can be used in any task-level API function that takes an argument of that type. Unlike mutexes, binary semaphores can be used in interrupt service routines.
Return Value:
void Could not create the semaphore because not enough FreeRTOS heap is available.
Any other value The semaphore was created successfully. The return value is a handle that can refer to the semaphore.
Usage example:

SemaphoreHandle_t xSemaphore;
void vATask(void * pvParameters)
{
    
    
    /* 尝试创建一个信号量。*/
    xSemaphore = xSemaphoreCreateBinary();

    if(xSemaphore == NULL{
    
    
        /* 没有足够的 FreeRTOS 堆可供信号量使用
        创建成功。*/
    }
   	else
    {
    
    
        /* 现在可以使用信号量了。它的句柄存储在
        x信号量变量。在此处的信号量上调用 xSemaphoreTake()
        将失败,直到第一次给出信号量。*/
    }
}

1.2、xSemaphoreCreateBinaryStatic()

API prototype:

SemaphoreHandle_t xSemaphoreCreateBinaryStatic(StaticSemaphore_t *pxSemaphoreBuffer);

  Creates a binary semaphore and returns a handle that can refer to the semaphore. configSUPPORT_STATIC_ALLOCATION must be set to 1 in FreeRTOSConfig.h for this RTOS API function to be available.
  Each binary semaphore requires a small amount of RAM to hold the state of the semaphore. If a binary semaphore is created using xSemaphoreCreateBinary(), the required RAM is automatically allocated from the FreeRTOS heap. RAM is provided by the application writer if the binary semaphore is created using xSemaphoreCreateBinaryStatic(), which requires an additional parameter but allows static allocation of RAM at compile time. See the Static vs. Dynamic Allocation page for details.
  A semaphore is created in an "empty" state, which means that the semaphore must first be given using the xSemaphoreGive() API function before it can be taken (taken) using the xSemaphoreTake() function.
  Binary semaphores and mutexes are very similar, with some minor differences: mutexes include a priority inheritance mechanism, binary semaphores do not. This makes binary semaphores a better choice for implementing synchronization (either between tasks or between tasks and interrupts), and mutexes a better choice for implementing simple mutual exclusion.
  A binary semaphore does not need to be returned once acquired, so task synchronization can be achieved by one task/interrupt continuously "giving" the semaphore while the other continuously "acquires" the semaphore. The sample code on the xSemaphoreGiveFromISR() documentation page demonstrates this. Note that the same functionality can often be achieved in a more efficient manner using direct task notifications.
  If another higher priority task tries to acquire the same mutex, the priority of the task that "acquired" the mutex may be increased. A task that owns a mutex "inherits" the priority of a task that tries to "acquire" the same mutex. This means that the mutex must always be "returned" - otherwise higher priority tasks will never be able to acquire the mutex, and lower priority tasks will never "deprive" the priority. An example of a mutex used to implement mutual exclusion is available on the xSemaphoreTake() documentation page.
  Both mutexes and binary semaphores are referenced by variables of type SemaphoreHandle_t and can be used in any task-level API function that takes an argument of that type. Unlike mutexes, binary semaphores can be used in interrupt service routines.
Parameters:
  pxSemaphoreBuffer must point to a variable of type StaticSemaphore_t, which will be used to save the state of the semaphore.
Return value:
  NULL The semaphore cannot be created because pxSemaphoreBuffer is NULL.
  Any other value The semaphore was successfully created. The return value is a handle by which the semaphore can be referenced.
Usage example:

SemaphoreHandle_t xSemaphore = NULL;
StaticSemaphore_t xSemaphoreBuffer;

 void vATask(void * pvParameters)
 {
    
    
    /* 创建一个二进制信号量而不使用任何动态内存
    分配。信号量的数据结构将被保存到
    xSemaphoreBuffer 变量。*/
    xSemaphore = xSemaphoreCreateBinaryStatic( &xSemaphoreBuffer );

    /* pxSemaphoreBuffer 不是 NULL,所以预计
    句柄不会为 NULL。*/ 
    configASSERT ( xSemaphore );

    /* 其余的任务代码放在这里。*/
 }

1.3、vSemaphoreCreateBinary()

API prototype:

vSemaphoreCreateBinary( SemaphoreHandle_t xSemaphore )

  注意:vSemaphoreCreateBinary() 宏保留在源代码中, 以确保后向兼容,但不应在新设计中使用。 新设计中应使用 xSemaphoreCreateBinary() 函数。
  此外,在许多情况下,使用 直达任务通知 代替二进制信号量速度更快,更节省内存。
  Macro to create a semaphore using the existing queuing mechanism. The queue length is 1 because this is a binary semaphore. The data size is 0 because we won't actually store any data, just want to know if the queue is empty or full.
  Binary semaphores and mutexes are very similar, with a few minor differences: Mutexes include a priority inheritance mechanism, while binary semaphores do not. Therefore, binary semaphores are better suited for synchronization (between tasks or between tasks and interrupts), whereas mutexes are better suited for simple mutual exclusion.
  Once the binary semaphore is acquired, there is no need to return, so task synchronization can be achieved by one task/interrupt continuously "giving" the semaphore while another task/interrupt continuously "acquires" the semaphore. This can be demonstrated with the sample code on the xSemaphoreGiveFromISR() documentation page.
  The priority of the task that "acquired" the mutex may be raised if another higher priority task tries to acquire the same mutex. A task that owns a mutex "inherits" the priority of a task that tries to "acquire" the same mutex, which means that the mutex must always be "returned", otherwise a higher priority task will never be able to acquire the mutex, And tasks with lower priority will never be able to "uninherit" priority. The mutex instance used to implement mutual exclusion, see xSemaphoreTake() documentation page for details.
  Both mutexes and binary semaphores are assigned to variables of type SemaphoreHandle_t, which can be used in any API function that takes a parameter of this type.
Parameters:
  xSemaphore The handle of the created semaphore, which should be of type SemaphoreHandle_t.
Usage example:

 SemaphoreHandle_t xSemaphore;
 void vATask( void * pvParameters )
 {
    
    
    // Semaphore不能在调用vSemaphoreCreateBinary()之前使用。
    // 这是一个宏,所以直接传入变量。
    vSemaphoreCreateBinary( xSemaphore );
    if( xSemaphore != NULL )
    {
    
    
        // 该semaphore被成功创建。
        // 现在可以使用该信号灯了。
    }
 }

2. Counting semaphore

2.1、xSemaphoreCreateCounting()

API prototype:

SemaphoreHandle_t xSemaphoreCreateCounting( UBaseType_t uxMaxCount,
                                            UBaseType_t uxInitialCount);

Tip: In many cases, "task notifications" can provide a lightweight alternative to technical semaphores

  Creates a counting semaphore and returns a handle by which the newly created semaphore can be referenced. configSUPPORT_DYNAMIC_ALLOCATION must be set to 1 in FreeRTOSConfig.h, or left undefined (in which case it defaults to 1 by default) to use this RTOS API function.

  Each counting semaphore requires a small amount of RAM to maintain the state of the semaphore. If the counting semaphore is created using xSemaphoreCreateCounting() it will be automatically allocated from the heap as needed. RAM FreeRTOS RAM is provided by the application writer if the counting semaphore is created using xSemaphoreCreateCountingStatic(), which requires additional but allows static allocation of RAM at compile time. See the Static Allocation vs. Dynamic Allocation page for more information.

  Counting semaphores are typically used in two situations:

  1. Inventory events
    In this usage scenario, the event handler "gives" the semaphore each time an event occurs (incrementing the semaphore count value), and the handler task "acquires" the semaphore (decrementing the semaphore count value) each time it processes an event. count value). Therefore, the count value is the difference between the number of events that have occurred and the number that have been processed. In this case, the initial count value is preferably zero.
    Note that the same functionality can often be achieved more efficiently using direct-to-task notifications.
  2. Resource Management
    In this usage scenario, the count value represents the number of resources available. To gain control of a resource, a task must first acquire the semaphore - decrementing the semaphore count value. When the count reaches zero, there are no resources available. When the task finishes using the resource, it "returns" the semaphore - incrementing the semaphore count value. In this case, the initial count value is preferably equal to the maximum count value, indicating that all resources are available.

Parameters:
  uxMaxCount The maximum count value that can be reached. When a semaphore reaches this value, it can no longer be "given".
  uxInitialCount The count value assigned to the semaphore when the semaphore was created.
Return Value:
  If the semaphore was successfully created, a handle to the semaphore will be returned. Returns NULL if the semaphore could not be created because the RAM required to hold the semaphore could not be allocated.
Usage example:

void vATask( void * pvParameters )
{
    
    
	SemaphoreHandle_t xSemaphore;
    /* 创建一个最大计数为10,初始计数为0的计数信号灯。
    初始计数为0。*/
    xSemaphore = xSemaphoreCreateCounting( 10, 0 );
    if( xSemaphore != NULL )
    {
    
    
        /* 该semaphore被成功创建。*/
    }
}

2.2、xSemaphoreCreateCountingStatic()

API prototype:

SemaphoreHandle_t xSemaphoreCreateCountingStatic(
                                 UBaseType_t uxMaxCount,
                                 UBaseType_t uxInitialCount
                                 StaticSemaphore_t *pxSemaphoreBuffer );

  Creates a counting semaphore and returns a handle by which the newly created semaphore can be referenced. configSUPPORT_DYNAMIC_ALLOCATION must be set to 1 in FreeRTOSConfig.h, or left undefined (in which case it defaults to 1 by default) to use this RTOS API function.
  Each counting semaphore requires a small amount of RAM to maintain the state of the semaphore. If the counting semaphore is created using xSemaphoreCreateCounting() it will be automatically allocated from the heap as needed. RAM FreeRTOS RAM is provided by the application writer if the counting semaphore is created using xSemaphoreCreateCountingStatic(), which requires additional but allows static allocation of RAM at compile time. See the Static Allocation vs. Dynamic Allocation page for more information.
  Counting semaphores are typically used in two situations:

  1. Inventory events
    In this usage scenario, the event handler "gives" the semaphore each time an event occurs (incrementing the semaphore count value), and the handler task "acquires" the semaphore (decrementing the semaphore count value) each time it processes an event. count value). Therefore, the count value is the difference between the number of events that have occurred and the number that have been processed. In this case, the initial count value is preferably zero.
    Note that the same functionality can often be achieved more efficiently using direct-to-task notifications.
  2. Resource Management
    In this usage scenario, the count value represents the number of resources available. To gain control of a resource, a task must first acquire the semaphore - decrementing the semaphore count value. When the count reaches zero, there are no resources available. When the task finishes using the resource, it "returns" the semaphore - incrementing the semaphore count value. In this case, the initial count value is preferably equal to the maximum count value, indicating that all resources are available.

Parameters:
  uxMaxCount The maximum count value that can be reached. When a semaphore reaches this value, it can no longer be "given".
  uxInitialCount The count value assigned to the semaphore when the semaphore was created.
  pxSemaphoreBuffer must point to a variable of type StaticSemaphore_t, which is then used to hold the semaphore's data structure.
Return Value:
  If the semaphore was successfully created, a handle to the semaphore will be returned. Returns NULL if the semaphore could not be created because the RAM required to hold the semaphore could not be allocated.
Usage example:

static StaticSemaphore_t xSemaphoreBuffer;

void vATask( void * pvParameters )
{
    
    
SemaphoreHandle_t xSemaphore;

    /*创建一个计数信号,最大计数为10,初始计数为0。
    该信号的数据结构被存储在xSemaphoreBuffer变量中。
    xSemaphoreBuffer变量中 - 不进行动态内存分配。*/
    xSemaphore = xSemaphoreCreateCountingStatic( 10, 0, &xSemaphoreBuffer );

    /* pxSemaphoreBuffer不是NULL,所以预计该信号将被创建。将被创建。*/
    configASSERT( xSemaphore );
}

3. Mutual exclusion semaphore

3.1、xSemaphoreCreateMutex()

API prototype:

SemaphoreHandle_t xSemaphoreCreateMutex( void )

  Creates a mutex and returns a handle to which the mutex can be referenced. In interrupt service routines, mutexes cannot be used.
  configSUPPORT_DYNAMIC_ALLOCATION and configUSE_MUTEXES must both be set to 1 in FreeRTOSConfig.h for xSemaphoreCreateMutex() to work. (ConfigSUPPORT_DYNAMIC_ALOGRATION may not be defined, in which case it will default to 1.)
  Each mutex requires a small amount of RAM to maintain the state of the mutex. If a mutex is created using xSemaphoreCreateMutex() it will be automatically allocated from the RAM heap FreeRTOS needs. If a mutex is created using xSemaphoreCreateMutexStatic(), RAM should be provided by the application writer, but static allocation of RAM at compile time is allowed. See the Static Allocation vs. Dynamic Allocation page for more information.
  Acquire the mutex using xSemaphoreTake(), and give the mutex using xSemaphoreGive(). xSemaphoreTakeRecursive() and xSemaphoreGiveRecursive() are only available for mutexes created with xSemaphoreCreateRecursiveMutex().
  Mutexes and binary semaphores are very similar, but there are some subtle differences: Mutexes have a priority inheritance mechanism, but binary semaphores do not. Therefore, binary semaphores are a better choice for implementing synchronization (between tasks or between tasks and interrupts), and for implementing simple mutual exclusion.
  If another higher-priority task tries to acquire the same mutex, the priority of the task that "acquired" the mutex will be temporarily raised. A task that owns a mutex "inherits" the priority of a task that tries to "acquire" the same mutex. This means that the mutex must always be "returned", otherwise higher-priority tasks will never be able to acquire the mutex, and lower-priority tasks will never be able to "uninherit" priority.
  The mutex instance used to implement mutual exclusion, see the xSemaphoreTake() documentation page for details.
  Once the binary semaphore is acquired, there is no need to return. Thus, task synchronization can be achieved by one task/interrupt continuously releasing the semaphore while the other continuously acquires the semaphore. See the sample code on the xSemaphoreGiveFromISR() documentation page for a demonstration. Note that the same functionality can be achieved in a more efficient manner using direct task notifications.
  Handles to mutexes and binary semaphores are assigned to variables of type SemaphoreHandle_t and can be used in any task-level (as opposed to interrupt-safe) API function that accepts an argument of that type.
Return Value:
  If the mutex type semaphore is successfully created, returns the handle of the created mutex. Returns NULL if the mutex was created recursively.
Usage example:

SemaphoreHandle_t xSemaphore;
void vATask( void * pvParameters )
{
    
    
   /* 创建一个mutex类型的semaphore。*/
   xSemaphore = xSemaphoreCreateMutex();
   if( xSemaphore != NULL )
   {
    
    
       /* 该信号灯已成功创建,可以使用。*/
   }
}

3.2、xSemaphoreCreateMutexStatic()

API prototype:

SemaphoreHandle_t xSemaphoreCreateMutexStatic(
                            StaticSemaphore_t *pxMutexBuffer );

  Creates a mutex and returns a handle to which the mutex can be referenced. In interrupt service routines, mutexes cannot be used.
  configSUPPORT_STATIC_ALLOCATION and configUSE_mutexes must both be set to 1 in FreeRTOSConfig.h for xSemaphoreCreateMutexStatic() to work.
  Each mutex requires a small amount of RAM to maintain the state of the mutex. If a mutex is created using xSemaphoreCreateMutex() it will be automatically allocated from the RAM heap FreeRTOS needs. RAM is provided by the application writer if the mutex is created using xSemaphoreCreateMutexStatic(), which takes an additional parameter, but allows static allocation of RAM at compile time. See the Static Allocation vs. Dynamic Allocation page for more information.
  Acquire the mutex using xSemaphoreTake(), and give the mutex using xSemaphoreGive(). xSemaphoreTakeRecursive() and xSemaphoreGiveRecursive() are only available for mutexes created with xSemaphoreCreateResursiveMutex().
  Mutexes and binary semaphores are very similar, but there are some subtle differences: Mutexes have a priority inheritance mechanism, but binary semaphores do not. Therefore, binary semaphores are a better choice for implementing synchronization (between tasks or between tasks and interrupts), and for implementing simple mutual exclusion.
  If another higher-priority task tries to acquire the same mutex, the priority of the task that "acquired" the mutex will be temporarily increased. A task that owns a mutex "inherits" the priority of a task that tries to "acquire" the same mutex. This means that the mutex must always be "returned", otherwise higher-priority tasks will never be able to acquire the mutex, and lower-priority tasks will never be able to "uninherit" priority.
  The mutex instance used to implement mutual exclusion, see the xSemaphoreTake() documentation page for details.
  Once the binary semaphore is acquired, there is no need to return. Thus, task synchronization can be achieved by one task/interrupt continuously releasing the semaphore while the other continuously acquires the semaphore. See the sample code on the xSemaphoreGiveFromISR() documentation page for a demonstration. Note that the same functionality can be achieved in a more efficient manner using direct task notifications.
  Handles to mutexes and binary semaphores are assigned to variables of type SemaphoreHandle_t and can be used in any task-level (as opposed to interrupt-safe) API function that accepts an argument of that type.
Parameters:
  pxMutexBuffer must point to a variable of type StaticSemaphore_t, which will be used to save the state of the mutex semaphore.
Return Value:
  If the mutex type semaphore is successfully created, returns the handle of the created mutex. Returns NULL if the mutex was not created because pxMutexBuffer is NULL.
Usage example:

SemaphoreHandle_t xSemaphore = NULL;
StaticSemaphore_t xMutexBuffer;

void vATask( void * pvParameters )
{
    
    
	/* 创建一个mutex semaphore,不使用任何动态内存分配。
	分配。 mutex的数据结构将被保存到xMutexBuffer变量。*/
	xSemaphore = xSemaphoreCreateMutexStatic( &xMutexBuffer );
	
	/* pxMutexBuffer不是NULL,所以预计句柄不会是NULL。句柄不会是NULL。*/
	configASSERT( xSemaphore );
}

4. Recursive semaphore

4.1、xSemaphoreCreateRecursiveMutex()

API prototype:

SemaphoreHandle_t xSemaphoreCreateRecursiveMutex( void )

  Creates a recursive mutex and returns a mutex handle. Recursive mutexes cannot be used in interrupt service routines. Both configSUPPORT_DYNAMIC_ALLOCATION and configUSE_RECURSIVE_mutexes must be defined as 1 in FreeRTOSConfig.h in order to use the xSemaphoreCreateRecursiveMutex() function (configSUPPORT_DYNAMIC_ALOUTION can also be undefined, in which case it will be defined as 1 by default).
  Each recursive mutex requires a small amount of RAM for maintaining the state of the recursive mutex. If a mutex is created using xSemaphoreCreateRecursiveMutex(), the required one is automatically allocated from the RAM heap FreeRTOS stack. If a recursive mutex is created using xSemaphoreCreateRecursiveMutexStatic(), then RAM is provided by the application writer, which takes an additional parameter, but allows static allocation of RAM at compile time. See the Static Allocation vs. Dynamic Allocation page for more information.
  Use xSemaphoreTakeRecursive() to acquire (hold), and xSemaphoreGiveRecursive() API functions to release. xSemaphoreTake() and xSemaphoreGive() must not be used.
  xSemaphoreCreateMutex() and xSemaphoreCreateMutexStatic() are used to create non-recursive mutexes. A non-recursive mutex can only be acquired once by a task. If the same task tries to acquire it again, it will fail, because when the task releases the mutex for the first time, the mutex has been released.
  Contrary to non-recursive mutexes, recursive mutexes can be acquired many times by the same task, and need to be released as many times as acquired, and then the recursive mutexes will be returned.
  Like non-recursive mutexes, recursive mutexes use a priority inheritance algorithm. If another higher priority task tries to acquire the same mutex, the priority of the task that "acquired" the mutex will be temporarily raised. A task that owns a mutex "inherits" the priority of a task that tries to "acquire" the same mutex. This means that the mutex must always be "returned", otherwise higher priority tasks will never be able to acquire the mutex, and lower priority tasks will never be able to "uninherit" the priority.
Return value:
If the recursive mutex is successfully created, the handle of the created mutex will be returned. Returns NULL if the recursive mutex was not created because the memory required to hold the mutex could not be allocated.
Usage example:

SemaphoreHandle_t xMutex;

void vATask( void * pvParameters )
{
    
    
	// 创建一个递归的mutex。
	xMutex = xSemaphoreCreateRecursiveMutex();
	
	if( xMutex != NULL )
	{
    
    
		/* 递归突发事件已成功创建,现在可以使用。
		现在可以使用了。*/
	}
}

4.2、xSemaphoreCreateRecursiveMutexStatic()

API prototype:

SemaphoreHandle_t xSemaphoreCreateRecursiveMutexStatic(
                              StaticSemaphore_t *pxMutexBuffer )

  Creates a recursive mutex and returns a mutex handle. Recursive mutexes cannot be used in interrupt service routines. Both configUSE_RECURSIVE_MUTEXES and configSUPPORT_STATIC_ALLOCATION must be set to 1 in FreeRTOSConfig.h for xSemaphoreCreateRecursiveMutexStatic() to be available.
  Each recursive mutex requires a small amount of RAM for the state of the recursive mutex. If a mutex is created using xSemaphoreCreateRecursiveMutex(), the required one is automatically allocated from the RAM heap FreeRTOS stack. If a recursive mutex is created using xSemaphoreCreateRecursiveMutexStatic(), then RAM is provided by the application writer, which takes an additional parameter, but allows static allocation of RAM at compile time. See the Static Allocation vs. Dynamic Allocation page for more information.
  Use xSemaphoreTakeRecursive() to acquire (hold), and xSemaphoreGiveRecursive() API functions to release. xSemaphoreTake() and xSemaphoreGive() must not be used.
  xSemaphoreCreateMutex() and xSemaphoreCreateMutexStatic() are used to create non-recursive mutexes. A non-recursive mutex can only be acquired once by a task. If the same task tries to acquire it again, it will fail, because when the task releases the mutex for the first time, the mutex has been released.
  Contrary to non-recursive mutexes, recursive mutexes can be acquired many times by the same task, and need to be released as many times as acquired, and then the recursive mutexes will be returned.
  Like non-recursive mutexes, recursive mutexes use a priority inheritance algorithm. If another higher priority task tries to acquire the same mutex, the priority of the task that "acquired" the mutex will be temporarily raised. A task that owns a mutex "inherits" the priority of a task that tries to "acquire" the same mutex. This means that the mutex must always be "returned", otherwise higher-priority tasks will never be able to acquire the mutex, and lower-priority tasks will never be able to "uninherit" priority.
Parameters:
  pxMutexBuffer must point to a variable of type StaticSemaphore_t, which will be used to save the state of the mutex semaphore.
Return Value:
  If the recursive mutex was successfully created, returns the handle to the created mutex. Returns NULL if the recursive mutex was not created because pxMutexBuffer was NULL.
Usage example:

SemaphoreHandle_t xSemaphore = NULL;
StaticSemaphore_t xMutexBuffer;

void vATask( void * pvParameters )
{
    
    
	/* 创建一个递归的mutex信号,不使用任何动态内存分配。
	内存分配。 该mutex的数据结构将被保存到
	xMutexBuffer变量。*/
	xSemaphore = xSemaphoreCreateRecursiveMutexStatic( &xMutexBuffer );
	
	/* pxMutexBuffer不是NULL,所以预计该句柄不会是NULL。
	句柄不会是NULL。*/
	configASSERT( xSemaphore );
	
	/* 其余的任务代码都在这里。*/
}

Five, delete the semaphore vSemaphoreDelete()

API prototype:

void vSemaphoreDelete( SemaphoreHandle_t xSemaphore )

  Delete semaphores, including mutex-type semaphores and recursive semaphores.
  Do not delete a signal on which a task is blocked (a task in a blocked state, waiting for a signal to become available).
Parameters:
xSemaphore The handle of the semaphore to be deleted.

6. Get the mutex holder xSemaphoreGetMutexHolder()

API prototype:

TaskHandle_t xSemaphoreGetMutexHolder( SemaphoreHandle_t xMutex )

  INCLUDE_xSemaphoreGetMutexHolder must be set to 1 in FreeRTOSConfig.h for this function to be available.
  Returns the handle to the task (if any) holding the MUTEX specified by the function parameter.
  xSemaphoreGetMutexHolder() can be used reliably to determine whether the calling task is the mutex holder, but xSemaphoreGetMutexHolder() cannot be used reliably if the mutex is held by a task other than the calling task. This is because the MUTEX bracket may change between the calling task that called the function and the test for the function's return value.
  configUSE_MUTEXES in FreeRTOSConfig.h must be set to 1 to use xSemaphoreGetMutexHolder().
Parameters:
  xMutex The handle to the mutex being queried.
Return value:
  the handle of the task that holds the MUTEX specified by the xMutex parameter. Returns NULL if the semaphore passed in the xMutex parameter is not a semaphore of type MUTEX, or is not held by any task if a MUTEX is available.

Seven, get the semaphore count uxSemaphoreGetCount()

API prototype:

UBaseType_t uxSemaphoreGetCount( SemaphoreHandle_t xSemaphore );

  Returns the semaphore count.
Parameters:
  xSemaphore Handle to the semaphore being queried.
Return Value:
  If the semaphore is a counting semaphore, returns the current count value of the semaphore. If the semaphore is a binary semaphore, 1 is returned when the semaphore is available, and 0 is returned when the semaphore is not available.

8. Get the semaphore xSemaphoreTake()

API prototype:

BaseType_t xSemaphoreTake( SemaphoreHandle_t xSemaphore,TickType_t xTicksToWait );

  Macro for acquiring a semaphore. Semaphores must previously be created by calling xSemaphoreCreateBinary(), xSemaphoreCreateMutex(), or xSemaphoreCreateCounting().
  ISR calls calls Macromeie uses use use for use and use, uses, uses and uses uses and uses the use
parameter:
  Xsemaphore's handle that is obtained by the number of signals — it is obtained when creating the number of signals.
  xTicksToWait The time in ticks to wait for the semaphore to become available. The macro port TICK_PERIOD_MS can be used to convert it to real time.
  If INCLUDE_vTaskSuspend is set to "1", specifying a delay time of portMAX_DELAY causes the task to be delayed indefinitely (without a timeout).
Return value:
  If the number of signals is obtained, pdTRUE is returned; if xTicksToWait expires and the number of signals is unavailable, pdFALSE is returned.
Usage example:

SemaphoreHandle_t xSemaphore = NULL;
/* 一个创建semaphore的任务。*/
void vATask( void * pvParameters )
{
    
    
    /* 创建semaphore来保护一个共享资源。 由于我们在使用
    我们创建了一个互斥的信号灯,而不是一个二进制信号灯。
    而不是一个二进制信号。*/
    xSemaphore = xSemaphoreCreateMutex();
}
/* 一个使用semaphore的任务。*/
void vAnotherTask( void * pvParameters )
{
    
    
    /* ... 做其他事情。*/
    if( xSemaphore != NULL )
    {
    
    
        /* 看看我们是否能获得信号机。 如果semaphore不在
        可用,则等待10次,看它是否变得自由。*/
        if( xSemaphoreTake( xSemaphore, ( TickType_t ) 10 ) == pdTRUE )
        {
    
    
            /* 我们能够获得信号链,现在可以访问共享资源。
            共享资源。*/

            /* ... */

            /* 我们已经完成了对共享资源的访问。 释放
            semaphore。*/
            xSemaphoreGive( xSemaphore );
        }
        else
        {
    
    
            /* 我们无法获得信号,因此无法安全访问
            共享资源的安全。*/
        }
    }
}

Nine, get the semaphore xSemaphoreTakeFromISR() in the interrupt

API prototype:

BaseType_t xSemaphoreTakeFromISR(
        SemaphoreHandle_t xSemaphore,
        signed BaseType_t *pxHigherPriorityTaskWoken)

  Version of xSemaphoreTake() callable from an ISR. Unlike xSemaphoreTake(), xSemaphoreTakeFromISR() does not allow specifying a blocking time.
Parameters:
  xSemaphore The semaphore to be "acquired". Semaphores are referenced by variables of type SemaphoreHandle_t and must be explicitly created before use.
  The pxHigherPriorityTaskWoken semaphore may (although unlikely, and depends on the semaphore type) block one or more tasks waiting for the semaphore to be given. Calling xSemaphoreTakeFromISR() will cause the blocked task to wait for the semaphore to leave the blocked state. Internally, the API function sets *pxHigherPriorityTaskWoken to pdTRUE if calling an API function causes the task to leave the blocked state, and the unblocked task has a priority equal to or higher than the currently executing task (the interrupted task).
  If xSemaphoreTakeFromISR() sets *pxHigherPriorityTaskWoken to pdTRUE, the context switch shall be performed before exiting the interrupt. This will ensure that interrupts return directly to the highest priority ready state task. The mechanism is the same as that used in the xQueueReceiveFromISR() function, and the reader can refer to the xQueueReceiveFromISR() documentation for further explanation.
  Starting with FreeRTOS V7.3.0, pxHigherPriorityTaskWoken is an optional parameter that can be set to NULL.
Return Value:
  pdTRUE if the semaphore was successfully acquired. Returns pdFALSE if the semaphore was not successfully acquired because it is not available.

10. Obtain the mutex semaphore xSemaphoreTakeRecursive()

API prototype:

xSemaphoreTakeRecursive( SemaphoreHandle_t xMutex,
                         TickType_t xTicksToWait );

  Macro to recursively acquire or "acquire" a mutex-type semaphore. This mutex must have been previously created by calling xSemaphoreCreateRecursiveMutex();
  configUSE_RECURSIVE_MUTEXES must be set to 1 in FreeRTOSConfig.h for this macro to be available.
  This macro must not be used on a mutex created with xSemaphoreCreateMutex().
  The owner can repeatedly "acquire" the mutex for recursive use. The mutex will not become available again until the owner calls xSemaphoreGiveRecursive() for each successful "get" request. For example, if a task successfully "acquires" the same mutex 5 times, then no other task can use the mutex until the task also "gives" the mutex back exactly 5 times.
Parameters:
  xMutex The handle to the mutex being acquired. This is the handle returned by xSemaphoreCreateRecursiveMutex().
  xTicksToWait The time in ticks to wait for the semaphore to become available. The macro portTICK_PERIOD_MS can be used to convert it to real time. A semaphore can be polled with a zero block time. If the task already has a semaphore, xSemaphoreTakeRecursive() will return immediately, regardless of the value of xTicksToWait.
Return Value:
  pdTRUE if the semaphore is acquired. If xTicksToWait expires and the semaphore is not available, pdFALSE is returned.
Usage example:

 SemaphoreHandle_t xMutex = NULL;

 // 一个创建mutex的任务。
 void vATask( void * pvParameters )
 {
    
    
    // 创建mutex来保护一个共享资源。
    xMutex = xSemaphoreCreateRecursiveMutex();
 }

 // 一个使用该mutex的任务。
 void vAnotherTask( void * pvParameters )
 {
    
    
    // ... 做其他事情。

    if( xMutex != NULL )
    {
    
    
        // 看看我们是否能获得这个mutex。 如果mutex不可用
        // 等待10次,看它是否变得自由。   
        if( xSemaphoreTakeRecursive( xMutex, ( TickType_t ) 10 ) == pdTRUE )
        {
    
    
            // 我们能够获得mutex,现在可以访问
            // 共享资源。

            // ...
            // 由于某些原因,代码的性质决定了进一步调用 
            // xSemaphoreTakeRecursive()是在同一个mutex上进行的。 在真正的
            // 代码中,这些调用不会是连续的,因为这将使
            //没有意义。 相反,这些调用可能会被埋在
            // 一个更复杂的调用结构。
            xSemaphoreTakeRecursive( xMutex, ( TickType_t ) 10 );
            xSemaphoreTakeRecursive( xMutex, ( TickType_t ) 10 );

            // 该mutex现在已经被 "拿 "了三次,所以不会被 
            // 所以直到它被送回给另一个任务时,才可以使用。
            // 三次。 同样的,真正的代码也不可能有
            // 这些调用的顺序,而是埋在一个更复杂的
            // 呼叫结构中。 这只是为了说明问题。
            xSemaphoreGiveRecursive( xMutex );
            xSemaphoreGiveRecursive( xMutex );
            xSemaphoreGiveRecursive( xMutex );

            // 现在这个mutex可以被其他任务占用了。
        }
        else
        {
    
    
            // 我们无法获得mutex,因此无法安全访问
            // 共享资源的安全。
        }
    }
 }

11. Release the semaphore xSemaphoreGive()

API prototype:

xSemaphoreGive( SemaphoreHandle_t xSemaphore );

  Macro to release a semaphore. The semaphore must have previously been created by calling xSemaphoreCreateBinary(), xSemaphoreCreateMutex(), or xSemaphoreCreateCounting().
  This macro must not be used in an ISR. See xSemaphoreGiveFromISR() for an alternative that can be used from an ISR.
  This macro must not be used on semaphores created by xSemaphoreCreateRecursiveMutex().
Parameters:
  xSemaphore Handle to the semaphore to release. This is the handle returned when the semaphore was created.
Return value:
  pdTRUE if the semaphore release is successful; pdFALSE if an error occurs. The implementation of semaphores is based on queues. When publishing a message, if there is no room on the queue, an error may occur, indicating that the semaphore was not acquired correctly initially.
Usage example:

 SemaphoreHandle_t xSemaphore = NULL;
 void vATask( void * pvParameters )
 {
    
    
    // 创建semaphore来保护一个共享资源。 由于我们在使用
    // 用于互斥的信号,我们创建一个互斥信号。
    // 而不是一个二进制信号。
    xSemaphore = xSemaphoreCreateMutex();

    if( xSemaphore != NULL )
    {
    
    
        if( xSemaphoreGive( xSemaphore ) != pdTRUE )
        {
    
    
            // 我们希望这个调用会失败,因为我们不能在没有先 "给 "的情况下给
            // 一个semaphore而不先 "接受 "它!
        
        // 获取信号灯--如果信号灯不是立即可用的,则不要阻塞。
        // 立即可用。
        if( xSemaphoreTake( xSemaphore, ( TickType_t ) 0 ) )
        {
    
    
            // 我们现在有了semaphore,可以访问共享资源了。
            // ...
            // 我们已经完成了对共享资源的访问,所以可以释放这个
            // semaphore。
            if( xSemaphoreGive( xSemaphore ) != pdTRUE )
            {
    
    
                // 我们不会指望这个调用会失败,因为我们必须已经
                //获得了semaphore才会到这里。
            }
        }
    }
 }

12. Release the mutex semaphore xSemaphoreGiveRecursive()

API prototype:

xSemaphoreGiveRecursive( SemaphoreHandle_t xMutex )

  Macro to recursively release or "give" a mutex-type semaphore. This mutex must have been previously created by calling xSemaphoreCreateRecursiveMutex();
  configUSE_RECURSIVE_MUTEXES must be set to 1 in FreeRTOSConfig.h for this macro to be available.
  This macro must not be used on a mutex created with xSemaphoreCreateMutex().
  The owner can repeatedly "acquire" the mutex for recursive use. The mutex will not become available again until the owner calls xSemaphoreGiveRecursive() for each successful "get" request. For example, if a task successfully "acquires" the same mutex 5 times, then no other task can use the mutex until the task also "gives" the mutex back exactly 5 times.
Parameters:
  xMutex The handle to the mutex being released or "given". This is the handle returned by xSemaphoreCreateRecursiveMutex().
Return Value:
  pdTRUE if the semaphore is given successfully.

13. Release the semaphore xSemaphoreGiveFromISR() during the interrupt

API prototype:

xSemaphoreGiveFromISR(
				        SemaphoreHandle_t xSemaphore,
				        signed BaseType_t *pxHigherPriorityTaskWoken)

  Macro to release a semaphore. The semaphore must have been created by calling xSemaphoreCreateBinary() or xSemaphoreCreateCounting() before being freed.
  Mutex-type semaphores (those created by calling xSemaphoreCreateMutex()) must not be used with this macro.
  This macro can be used in ISR.
Parameters:
  xSemaphore Handle to the semaphore to release. This is the handle returned when the semaphore was created.
  pxHigherPriorityTaskWoken xSemaphoreGiveFromISR() sets *pxHigherPriorityTaskWoken to pdTRUE if releasing the semaphore causes a task to unblock, and the unblocked task has a higher priority than the currently running task. If xSemaphoreGiveFromISR() sets this value to pdTRUE, a context switch shall be requested before exiting the interrupt.
  Starting from FreeRTOSV7.3.0, pxHigherPriorityTaskWoken is an optional parameter that can be set to NULL.
Return value:
  pdTRUE if the semaphore is given successfully, otherwise errQUEUE_FULL.
Example usage:
  Note that it is often more efficient to implement the functionality shown below using direct task notifications instead of semaphores.

#define LONG_TIME 0xffff
#define TICKS_TO_WAIT 10

SemaphoreHandle_t xSemaphore = NULL;

/* 重复性任务。*/
void vATask( void * pvParameters )
{
    
    
    /* 我们使用semaphore进行同步,所以我们创建一个二进制的
    semaphore,而不是一个mutex。 我们必须确保中断
    在它被创建之前不要试图使用该信号! */
    xSemaphore = xSemaphoreCreateBinary();

    for( ; ; )
    {
    
    
        /* 我们希望这个任务每隔10个定时器的时间就运行一次。 这个semaphore
        是在这个任务开始之前创建的。

        阻塞等待信号灯的可用。*/
        if( xSemaphoreTake( xSemaphore, LONG_TIME ) == pdTRUE )
        {
    
    
            /* 是时候执行了。*/

            ...

            /* 我们已经完成了我们的任务。 返回到循环的顶部,在那里
            返回到循环的顶部,在那里我们将封锁信号,直到再次执行的时间
            再次执行。 注意当使用信号灯与一个
            ISR时,没有必要将信号灯 "送 "回去。
            归还。*/
        }
    }
}

/* 定时器ISR */
void vTimerISR( void * pvParameters )
{
    
    
	static unsigned char ucLocalTickCount = 0;
	static signed BaseType_t xHigherPriorityTaskWoken;

    /* 发生了一个定时器刻度。*/

    ... 做其他的时间功能。

    /* 现在是vATask()运行的时间吗?*/
    xHigherPriorityTaskWoken = pdFALSE;
    ucLocalTickCount++;
    if( ucLocalTickCount >= TICKS_TO_WAIT )
    {
    
    
        /* 通过释放信号来解除对任务的封锁。*/
        xSemaphoreGiveFromISR( xSemaphore, &xHigherPriorityTaskWoken );

        /* 重置计数,以便我们在10个刻度的时间内再次释放semaphore。
        时间。*/
        ucLocalTickCount = 0;
    }

    /* 如果xHigherPriorityTaskWoken被设置为 "true",我们就应该屈服。
    我们应该屈服。 这里实际使用的宏是
    端口特定的。*/
    portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
}

14. Example of use

binary semaphore

/**
 * @file 12_BinarySemaphore.c
 * @author WSP
 * @brief 二值信号量一般用作任务与任务的同步或者任务与中断的同步
 * @version 0.1
 * @date 2022-10-18
 * @note 
 * @copyright Copyright (c) 2022
 *
 */
#include "FreeRTOS_Include.h"

const static char *TAG = "APP_BinarySemaphore";

// #define USER_TASK_SEMAPHORE_SYNCHRONIZATION
/**
 * @brief   Task_One 使用任务信号量同步
 * @param   arg
 * @return  NULL
*/
#ifdef USER_TASK_SEMAPHORE_SYNCHRONIZATION
void Task_One(void *arg)
{
    
    
    SemaphoreHandle_t SemaphoreHandle = (SemaphoreHandle_t)arg;
    while (1){
    
    
        vTaskDelay(5000/portTICK_PERIOD_MS);
        ESP_LOGI(TAG,"Task_One Semaphore Give");
        xSemaphoreGive(SemaphoreHandle);        // 给信号量 释放信号量
    }
}
#else
static void timer_Transfer_Semaphore_callback(void* arg)
{
    
    
    SemaphoreHandle_t SemaphoreHandle = (SemaphoreHandle_t)arg;
    xSemaphoreGiveFromISR(SemaphoreHandle,NULL);
    ESP_LOGI(TAG,"Timer Transfer Semaphore Give");
}
#endif
/**
 * @brief   Task_Two
 * @param   arg
 * @return  NULL
*/
void Task_Two(void *arg)
{
    
    
    SemaphoreHandle_t SemaphoreHandle = (SemaphoreHandle_t)arg;
    // 延时等待这个时候任务二创建就被挂起,任务一先进行,任务一一旦获取信号量以后,
    // 就一直占用信号量直到释放信号量,导致优先级反转,二值信号量就会出现优先级反转这种情况。
    vTaskDelay(2000/portTICK_PERIOD_MS);   
    bool LED_State = 0; 
    BaseType_t SemaphoreState;   
    while (1){
    
    
        SemaphoreState = xSemaphoreTake(SemaphoreHandle,portMAX_DELAY);   // 拿到信号量 获取信号量
        if(SemaphoreState == pdTRUE){
    
    
            ESP_LOGI(TAG,"Task_Two Take %s",LED_State == false ? "LED OFF" :  "LED ON");
            LED_State = !LED_State;
        }else{
    
    
            ESP_LOGI(TAG,"Task_Two Take Semaphore fail");
        }
    }
}
/**
 * @brief   创建函数初始化
 * @param   NULL
 * @return  NULL
 */
void BinarySemaphore_Init(void)
{
    
    
    SemaphoreHandle_t SemaphoreHandle = NULL;
    SemaphoreHandle = xSemaphoreCreateBinary(); // 创建信号量
    xSemaphoreGive(SemaphoreHandle);            // 创建以后是空的状态,在获取之前要释放信号量
#ifdef USER_TASK_SEMAPHORE_SYNCHRONIZATION
    // 创建任务一
    xTaskCreate(Task_One,                       // 任务函数
                "Task_One",                     // 任务名
                2048,                           // 任务堆载
                (void *)SemaphoreHandle,        // 任务参数
                1,                              // 任务优先级
                NULL);                          // 任务句柄
#else
    const esp_timer_create_args_t Semaphore_timer_args = {
    
    
            .callback = &timer_Transfer_Semaphore_callback, // 定时器回调函数
            .name = "Transfer Timer",                       // 定时器名称
            .arg = (void *)SemaphoreHandle,                 // 定时器传入参数
    };
    esp_timer_handle_t Semaphore_timer;                     // 创建一个定时器变量
    //创建一个定时器
    ESP_ERROR_CHECK(esp_timer_create(&Semaphore_timer_args, &Semaphore_timer)); // 创建定时器
    esp_timer_start_periodic(Semaphore_timer,5000000);      // 开始定时器
#endif
    // 创建任务二
    xTaskCreate(Task_Two,                       // 任务函数       
                "Task_Two",                     // 任务名       
                2048,                           // 任务堆载       
                (void *)SemaphoreHandle,        // 任务参数       
                2,                              // 任务优先级
                NULL);                          // 任务句柄
}

count semaphore

/**
 * @file 13_CountSemaphore.c
 * @author WSP
 * @brief 计数型信号量,计数型信号量一般使用汽车位来描述会更好理解些
 * @version 0.1
 * @date 2022-10-18
 * @copyright Copyright (c) 2022
 */
#include "FreeRTOS_Include.h"

const static char *TAG = "APP_CountSemaphore";
int PublicData_Count = 0;
SemaphoreHandle_t SemaphoreHandle;
/**
 * @brief   Task_Count_Car_Value
 * @param   arg
 * @return  NULL
*/
void Task_Count_Car_Value(void *arg)
{
    
    
    int SemaphoreCountValue = 0;
    BaseType_t Result;
    while (1){
    
    
        SemaphoreCountValue = uxSemaphoreGetCount(SemaphoreHandle);     // 获取计数型信号量
        Result = xSemaphoreTake(SemaphoreHandle,0);                     // 获取信号量 来了一辆汽车(占用汽车位)
        if (Result == pdPASS)
            ESP_LOGI(TAG,"Current parking value: %d",SemaphoreCountValue);  // 当前停车位数量,6s离开一辆汽车,3秒来一辆汽车
        vTaskDelay(3000/portTICK_PERIOD_MS);
    }
}
/**
 * @brief   Task_Count_Car_Left
 * @param   arg
 * @return  NULL
*/
void Task_Count_Car_Left(void *arg)
{
    
    
    while (1){
    
    
        vTaskDelay(6000/portTICK_PERIOD_MS);
        xSemaphoreGive(SemaphoreHandle);                                // 释放信号量(让出停车位)  汽车离开停车场
        ESP_LOGI(TAG,"Car left the parking");
    }
}
/**
 * @brief   创建函数初始化
 * @param   NULL
 * @return  NULL
 */
void CountSemaphore_Init(void)
{
    
    
    SemaphoreHandle = xSemaphoreCreateCounting(100,99);  // 创建信号量 计数值最大100 默认值99(停车场目前最大容纳100辆车目前已经停了99辆了)
    // 创建任务一
    xTaskCreate(Task_Count_Car_Value,   // 任务函数
                "CountCarValue",        // 任务名
                2048,                   // 任务堆载
                NULL,                   // 任务参数
                1,                      // 任务优先级
                NULL);                  // 任务句柄
    // 创建任务二
    xTaskCreate(Task_Count_Car_Left,    // 任务函数
                "CarLeft",              // 任务名
                2048,                   // 任务堆载
                NULL,                   // 任务参数
                2,                      // 任务优先级
                NULL);                  // 任务句柄
}

Mutex semaphore

/**
 * @file 14_MutexesSemaphore.c
 * @author WSP
 * @brief 互斥信号量 使用互斥信号量对共同访问资源保护 
 * @version 0.1
 * @date 2022-10-19
 *
 * @copyright Copyright (c) 2022
 *
 */
#include "FreeRTOS_Include.h"

const static char *TAG = "APP_MutexesSemaphore";
int PublicData_Count = 0;
QueueHandle_t SemaphoreMutexHandle = NULL;
/**
 * @brief   Task_One
 * @param   arg
 * @return  NULL
*/
void Task_One(void *arg)
{
    
    
    BaseType_t QueueResult;
    while (1){
    
    
        QueueResult = xSemaphoreTake(SemaphoreMutexHandle,portMAX_DELAY);
        if(QueueResult == pdPASS){
    
    
            for (int i = 0; i < 5; i++)
            {
    
    
                vTaskDelay(1000/portTICK_PERIOD_MS);
                ESP_LOGI(TAG," Task_One xSemaphoreTake PublicData_Count value:%d",PublicData_Count);
                PublicData_Count = i;
            }
            PublicData_Count = 0;
        }
        xSemaphoreGive(SemaphoreMutexHandle);
        vTaskDelay(1000/portTICK_PERIOD_MS);
    }
}
/**
 * @brief   Task_One
 * @param   arg
 * @return  NULL
*/
void Task_Two(void *arg)
{
    
    
    BaseType_t QueueResult;
    while (1){
    
    
        QueueResult = xSemaphoreTake(SemaphoreMutexHandle,portMAX_DELAY);
        if(QueueResult == pdPASS){
    
    
            for (int i = 0; i < 5; i++)
            {
    
    
                vTaskDelay(1000/portTICK_PERIOD_MS);
                ESP_LOGI(TAG," Task_Two xSemaphoreTake PublicData_Count value:%d",PublicData_Count);
                PublicData_Count = i;
            }
            PublicData_Count = 0;
        }
        xSemaphoreGive(SemaphoreMutexHandle);
        vTaskDelay(1000/portTICK_PERIOD_MS);
    }
}
/**
 * @brief   创建函数初始化
 * @param   NULL
 * @return  NULL
 */
void MutexesSemaphore_Init(void)
{
    
    
    SemaphoreMutexHandle = xSemaphoreCreateMutex();  // 创建信号量
    if(SemaphoreMutexHandle != NULL){
    
    
        // 创建任务一
        xTaskCreate(Task_One,
                    "Task_One",
                    2048,
                    NULL,
                    1,
                    NULL);
        // 创建任务二
        xTaskCreate(Task_Two,
                    "Task_Two",
                    2048,
                    NULL,
                    2,
                    NULL);
    }
}

recursive semaphore

/**
 * @file 15_RecursiveMutexesSemaphore.c
 * @author WSP
 * @brief 互斥递归信号量 两把钥匙锁一个箱子
 * @version 0.1
 * @date 2022-10-20
 *
 * @copyright Copyright (c) 2022
 *
 */
#include "FreeRTOS_Include.h"

const static char *TAG = "APP_RecursiveMutexesSemaphore";
int PublicData_Count = 0;
/**
 * @brief   Task_One
 * @param   arg
 * @return  NULL
*/
void Task_One(void *arg)
{
    
    
    BaseType_t QueueResult;
    QueueHandle_t SemaphoreRecursiveMutexHandle = (QueueHandle_t)arg;
    while (1){
    
    
        QueueResult = xSemaphoreTakeRecursive(SemaphoreRecursiveMutexHandle,portMAX_DELAY);
        if(QueueResult == pdPASS){
    
    
            vTaskDelay(1000/portTICK_PERIOD_MS);
            PublicData_Count ++;
            ESP_LOGI(TAG," Task_One xSemaphoreTake First:%d",PublicData_Count);
            QueueResult = xSemaphoreTakeRecursive(SemaphoreRecursiveMutexHandle,portMAX_DELAY);
            if(QueueResult == pdPASS){
    
    
                vTaskDelay(1000/portTICK_PERIOD_MS);
                PublicData_Count ++;
                ESP_LOGI(TAG," Task_One xSemaphoreTake Three:%d",PublicData_Count);
            }
            xSemaphoreGiveRecursive(SemaphoreRecursiveMutexHandle);
        }
        xSemaphoreGiveRecursive(SemaphoreRecursiveMutexHandle);
        vTaskDelay(1000/portTICK_PERIOD_MS);
    }
}
/**
 * @brief   Task_One
 * @param   arg
 * @return  NULL
*/
void Task_Two(void *arg)
{
    
    
    BaseType_t QueueResult; 
    QueueHandle_t SemaphoreRecursiveMutexHandle = (QueueHandle_t)arg;
    while (1){
    
    
        QueueResult = xSemaphoreTakeRecursive(SemaphoreRecursiveMutexHandle,portMAX_DELAY);
        if(QueueResult == pdPASS){
    
    
            vTaskDelay(1000/portTICK_PERIOD_MS);
            PublicData_Count ++;
            ESP_LOGI(TAG," Task_Two xSemaphoreTake PublicData_Count value:%d",PublicData_Count);
            PublicData_Count  = 0;
        }
        xSemaphoreGiveRecursive(SemaphoreRecursiveMutexHandle);
        vTaskDelay(1000/portTICK_PERIOD_MS);
    }
}
/**
 * @brief   创建函数初始化
 * @param   NULL
 * @return  NULL
 */
void RecursiveMutexesSemaphore_Init(void)
{
    
    
    QueueHandle_t SemaphoreRecursiveMutexHandle = NULL;
    SemaphoreRecursiveMutexHandle = xSemaphoreCreateRecursiveMutex();  // 创建信号量
    if(SemaphoreRecursiveMutexHandle != NULL){
    
    
        // 创建任务一
        xTaskCreate(Task_One,
                    "Task_One",
                    2048,
                    (void *)SemaphoreRecursiveMutexHandle,
                    1,
                    NULL);
        // 创建任务二
        xTaskCreate(Task_Two,
                    "Task_Two",
                    2048,
                    (void *)SemaphoreRecursiveMutexHandle,
                    2,
                    NULL);
    }
}

Guess you like

Origin blog.csdn.net/believe666/article/details/127205600