计数型信号量有以下两种典型用法
1.事件计数:每次事件发生,事件处理函数将释放信号量(信号量计数值加1),其他处理任务会获取信号量(信号量计数值减1)来处理事件。因此,计数值是事件发生的数量和事件处理的数量差值。计数信号量在创建时其值为0
2.资源管理:信号量表示有效的资源数目。任务必须先获取信号量才能获取资源控制权。当计数值减为零时表示没有的资源。当任务完成后,它会返还信号量(信号量计数值增加)。信号量创建时计数值应等于最大资源数目。
可以将计数型信号量具体应用在实际场景中:
假设有一家停车场,总共有10个空闲停车位,当一个车放置在停车位中,空闲停车位减少1,当一个车从停车位中开出,空闲停车位增加1,那么计数型信号量就可以理解为空闲停车位,也可以理解为有效地 可以用的资源的数目。

#include <stdio.h>
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "esp_spi_flash.h"
#include "freertos/queue.h"
#include "freertos/timers.h"
#include "freertos/semphr.h"

SemaphoreHandle_t semaphoreHandle;

void carInTask(void *pvParam) {
	int emptySpace = 0;
	BaseType_t iResult;
	while (1) {
		emptySpace = uxSemaphoreGetCount(semaphoreHandle);
		printf("emptySpace = %d\n", emptySpace);
		iResult = xSemaphoreTake(semaphoreHandle,0);
		if (iResult == pdPASS) {
			printf("one car in\n");
		} else {
			printf("No space\n");
		}
		vTaskDelay(pdMS_TO_TICKS(1000));
	}
}

void carOutTask(void *pvParam) {
	while (1) {
		vTaskDelay(pdMS_TO_TICKS(6000));
		xSemaphoreGive(semaphoreHandle);
		printf("one car out\n");
	}
}

void app_main(void) {
	semaphoreHandle = xSemaphoreCreateCounting(5, 5);
	xSemaphoreGive(semaphoreHandle);
	xTaskCreate(carInTask, "carInTask", 1024 * 5, NULL, 1, NULL);
	xTaskCreate(carOutTask, "carOutTask", 1024 * 5, NULL, 1, NULL);
}

计数型信号量首先要添加信号量头文件freertos/semphr.h。

调用xSemaphoreCreateCounting()函数创建一个计数信号量,并返回信号量可以使用的句柄

引用,调用xSemaphoreGive()函数去释放计数型信号量,调用xTaskCreate()去创建任务。

对于carOutTask()的函数,就去循环去调用xSemaphoreGive()函数去释放信号量,并打印输出。

对于carInTask()的函数,调用uxSemaphoreGetCount()函数获取到计数型信号量的数目,调用xSemaphoreTake()获取信号量。

计数型信号量_信号量