计数型信号量

回顾上节所讲:

Q: 什么是信号量?

A: 信号量(Semaphore),是在多任务环境下使用的一种机制,是可以用来保证两个或多个关键代码段不被并发调用。 信号量这个名字,我们可以把它拆分来看,“信号”可以起到通知信号的作用,“量”还可以用来表示资源的数量,当“量”只有0和1的时候,它就可以被称作“二值信号量”,只有两个状 ,当我们的那个量没有限制的时候,它就可以被称作为“计数型信号量”。 信号量也是队列的一种。

计数型信号量相当于队列长度大于1 的队列,因此计数型信号量能够容纳多个资源,计数型信号量的值反应的是资源的状态

关于计数信号量的理解,比较经典的就是“停车场”,假如停车场有3个车位,那么这就是个计数值为3的计数信号量,每当有一辆车开进停车场,计数值就会减1,如果停车场停满了3辆车,计数值就会为0,此时有新的车开过停车场,只需要查看计数值就知道,无法进入停车,只能返回或者继续等着。

 

 计数型信号量相关 API 函数

  • uxMaxCount:可以达到的最大计数值
  • uxInitialCount:创建信号量时分配给信号量的计数值
  • 返回值: 成功,返回对应计数型信号量的句柄; 失败,返回 NULL 

 除了创建有略微的区别,计数型信号量的释放和获取与二值信号量完全相同 !

实操演示

需求:创建一个计数型信号量,按下 KEY1 则释放信号量,按下 KEY2 获取信号量。

由于计数信号量和二值信号量的实现非常类似,所以直接复制上节二值信号量的Cube文件“mjm_freeRTOS_Sema_Bi” 并重命名为 “mjm_freeRTOS_Sema_coun

 打开相应的Cube文件: 

1. 配置按钮的GPIO:

2.  找到左侧的Middleware --> FREERTOS:

2.1 在“Config parameters”,将“USE_COUNTING_SEMAPHORES” 设置为 “Enabled”:

2.2 在“Timers and Semaphores”,删除刚刚创建的二值信号量,并创建一个新的计数信号量:

 

 

3. 生成代码打开Keil:

3.1 查看生成计数信号量的函数:

跳转这个函数并查看计数型信号量的部分:

 

可见,Cube封装的这个函数在创建计数型信号量的时候,将“xSemaphoreCreateCounting()" 的两个输入参数都设置为了count,所以和二值信号量一样,在创建计数信号量的时候,会同时释放所有的信号量。

3.2 代码实现:
#include "stdio.h"

void StartTaskGive(void const * argument)
{
  for(;;)
  {
		if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_RESET){
			osDelay(20);
			if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_RESET){ //按键消抖
				printf("KEY1 has been pressed\r\n");
				if (xSemaphoreGive(myCountingSemHandle) == pdTRUE){ //释放信号量并判断返回值,如果返回成功
					printf("successfully give\r\n");
				}else{//如果返回失败
					printf("fail to give\r\n");
				}		
			}
			while (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_RESET); //等待按键松开,防止出现按钮一直按着,就一直删除创建任务			
		}
		osDelay(10);
  }
}


void StartTaskTake(void const * argument)
{
  for(;;)
  {
		if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_1) == GPIO_PIN_RESET){
			osDelay(20);
			if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_1) == GPIO_PIN_RESET){ //按键消抖
				printf("KEY2 has been pressed\r\n");
				if (xSemaphoreTake(myCountingSemHandle, 0 ) == pdTRUE){ //获取信号量并判断返回值,如果返回成功 
					printf("successfully take\r\n");
				}else{//如果返回失败
					printf("fail to take\r\n");
				}
			}
			while (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_1) == GPIO_PIN_RESET); //等待按键松开,防止出现按钮一直按着,就一直删除创建任务			
		}
		osDelay(10);
  }
}

可见,关于计数信号量的获取和释放,其实除了函数不同之外其余完全相同!

实现效果

打开串口助手,先按一下KEY1:

如上面所说,创建计数信号量的函数将“uxInitialCount” 设为了3,所以一旦创建就先全部被释放了,所以再次释放不成功。

那么此时连按四下KEY2:

每获取一次,计数量减1,三次之后计数信号量被全部获取,计数值归0,所以在第四次获取失败

此时再按四下KEY1:

每释放一次,计数值加1,三次之后计数信号量全部被释放,计数值为3,所以在第四次释放失败

 

 

 

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
在FreeRTOS中,计数信号量是一种同步机制,用于在多个任务之间传递和管理资源的访问。当一个任务需要访问某个资源时,它需要获取计数信号量,如果计数信号量计数大于0,那么任务可以继续执行,计数信号量计数减1。如果计数信号量计数为0,则任务会被阻塞,直到有其他任务释放了计数信号量并将其计数增加。 要读取计数信号量的值,可以使用FreeRTOS提供的API函数xSemaphoreGetCount。这个函数返回计数信号量的当前计数值。需要注意的是,计数信号量计数值仅仅表示资源的可用数量,并不保证是准确的,因为在多任务环境中,计数信号量计数可能会在任务切换的过程中发生变化。 在使用计数信号量时,需要注意以下几个方面: . 在需要使用计数信号量的任务中,首先要创建一个计数信号量的句柄,使用xSemaphoreCreateCounting函数来创建,指定计数信号量的最大计数值和初始计数值。 2. 在任务中使用xSemaphoreTake函数获取计数信号量,如果计数信号量计数大于0,任务可以继续执行,否则任务会被阻塞,直到有其他任务释放计数信号量。 3. 在其他任务中,可以使用xSemaphoreGive函数释放计数信号量,并将其计数增加。 综上所述,要读取FreeRTOS计数信号量的值,可以使用xSemaphoreGetCount函数。但需要注意计数信号量计数值只是表示资源的可用数量,并不保证是准确的。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [FreeRTOS(4)----信号量](https://blog.csdn.net/weixin_63032791/article/details/130773792)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* [FreeRTOS学习------信号量(实践)](https://blog.csdn.net/Freelifewe/article/details/64907349)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值