1计数型信号量概念
1)计数型信号量相当于队列长度大于1 的队列,因此计数型信号量能够容纳多个资源
2)适用场景:
事件计数:
当每次事件发生后,在事件处理函数中释放计数型信号量(计数值+1),其他任务会获取计数型信号量(计数值-1) ,这种场合一般在创建时将初始计数值设置为 0。
资源管理:
信号量表示有效的资源数目。任务必须先获取信号量(信号量计数值-1 )才能获取资源控制权。当计数值减为零时表示没有的资源。当任务使用完资源后,必须释放信号量(信号量计数值+1)。信号量创建时计数值应等于最大资源数目。
2 计数型信号量相关API函数
使用计数型信号量的过程:创建计数型信号量->释放信号量 ->获取信号量
注意:
计数型信号量的获取与释放与二值信号量相同
1)计数型信号量的创建
#define xSemaphoreCreateCounting( uxMaxCount , uxInitialCount ) \ xQueueCreateCountingSemaphore( ( uxMaxCount ) , ( uxInitialCount ) )
形参: uxMaxCount 计数值的最大限定
uxInitialCount 计数值的初始值
返回值:NULL 创建失败
其他 创建成功返回计数型信号量的句柄
2)获取当前信号量的计数值
#define uxSemaphoreGetCount( xSemaphore ) \ uxQueueMessagesWaiting( ( QueueHandle_t ) ( xSemaphore ) )
形参: xSemaphore 信号量的句柄
返回值:整数 当前信号量的计数值的大小
3 计数型信号量实验
3.1 freertos_demo.c
#include "freertos_demo.h"
#include "./BSP/LCD/lcd.h"
#include "./BSP/KEY/key.h"
/*FreeRTOS*********************************************************************************************/
#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"
//FreeRTOS配置
//1.任务配置
//1.1 START_TASK 任务 配置
#define START_TASK_PRIO 1 /* 任务优先级 */
#define START_STK_SIZE 128 /* 任务堆栈大小 */
TaskHandle_t StartTask_Handler; /* 任务句柄 */
void start_task(void *pvParameters); /* 任务函数 */
//1.2 TASK1 任务 配置
#define TASK1_PRIO 2 /* 任务优先级 */
#define TASK1_STK_SIZE 128 /* 任务堆栈大小 */
TaskHandle_t Task1Task_Handler; /* 任务句柄 */
void task1(void *pvParameters); /* 任务函数 */
//1.2 TASK2 任务 配置
#define TASK2_PRIO 3 /* 任务优先级 */
#define TASK2_STK_SIZE 128 /* 任务堆栈大小 */
TaskHandle_t Task2Task_Handler; /* 任务句柄 */
void task2(void *pvParameters); /* 任务函数 */
//1.3 计数型信号量句柄定义
QueueHandle_t count_Semaphore_handle;
//2.在freertos_demo函数中创建start_task任务
void freertos_demo(void)
{
//创建计数型信号量
count_Semaphore_handle = xSemaphoreCreateCounting(100,0);
if(count_Semaphore_handle != NULL)
{
printf("计数型信号量创建成功!!!\r\n");
}
xTaskCreate((TaskFunction_t )start_task, /* 任务函数 */
(const char* )"start_task", /* 任务名称 */
(uint16_t )START_STK_SIZE, /* 任务堆栈大小 */
(void* )NULL, /* 传入给任务函数的参数 */
(UBaseType_t )START_TASK_PRIO, /* 任务优先级 */
(TaskHandle_t* )&StartTask_Handler); /* 任务句柄 */
vTaskStartScheduler();
}
//3.在start_task函数中创建task1、task2任务
void start_task(void *pvParameters)
{
//进入临界区
taskENTER_CRITICAL();
//创建任务1
xTaskCreate((TaskFunction_t )task1, /* 任务函数 */
(const char* )"task1", /* 任务名称 */
(uint16_t )TASK1_STK_SIZE, /* 任务堆栈大小 */
(void* )NULL, /* 传入给任务函数的参数 */
(UBaseType_t )TASK1_PRIO, /* 任务优先级 */
(TaskHandle_t* )&Task1Task_Handler); /* 任务句柄 */
//创建任务2
xTaskCreate((TaskFunction_t )task2, /* 任务函数 */
(const char* )"task2", /* 任务名称 */
(uint16_t )TASK2_STK_SIZE, /* 任务堆栈大小 */
(void* )NULL, /* 传入给任务函数的参数 */
(UBaseType_t )TASK2_PRIO, /* 任务优先级 */
(TaskHandle_t* )&Task1Task_Handler); /* 任务句柄*/
//删除开始任务
vTaskDelete(StartTask_Handler);
//退出临界区
taskEXIT_CRITICAL();
}
//4.在task1函数中释放计数型信号量
void task1(void *pvParameters)
{
uint8_t key = 0;
BaseType_t err = 0;
while (1)
{
//按键KEY0控制二值信号释放
key = key_scan(0);
switch (key)
{
case KEY0_PRES:
{
//如果二值信号量创建成功
if(count_Semaphore_handle != NULL)
{
err = xSemaphoreGive(count_Semaphore_handle); //释放计数型信号量
if(err == pdPASS)
{
printf("count_Semaphore_handle释放成功\r\n");
}
else
{
printf("count_Semaphore_handle释放失败\r\n");
}
}
break;
}
default:
{
break;
}
}
vTaskDelay(10);
}
}
//5.在task2函数中获取计数型信号量
void task2(void *pvParameters)
{
BaseType_t err = 0;
while(1)
{
err = xSemaphoreTake(count_Semaphore_handle,portMAX_DELAY);
if(err == pdPASS)
{
printf("信号量的计数值为:%d\r\n",(int)uxSemaphoreGetCount(count_Semaphore_handle) );
}
else printf("count_Semaphore_handle获取失败\r\n");
vTaskDelay(1000);
}
}