FreeRTOS系列|计数信号量

1. 计数信号量简介

计数型信号量有以下两种典型用法

  • 事件计数:每次事件发生,事件处理函数将释放信号量(信号量计数值加1),其他处理任务会获取信号量(信号量计数值减1)来处理事件。因此,计数值是事件发生的数量和事件处理的数量差值。计数信号量在创建时其值为0
  • 资源管理:信号量表示有效的资源数目。任务必须先获取信号量才能获取资源控制权。当计数值减为零时表示没有的资源。当任务完成后,它会返还信号量(信号量计数值增加)。信号量创建时计数值应等于最大资源数目

计数信号量有释放信号量操作和获取信号量操作,释放信号量操作的时候计数器的值会加一,获取信号操作,计数器的值减一,如果减到0任务会进入到等待状态;具体操作方式有两种,如下图所示:

在这里插入图片描述

2. 计数信号量的API函数
2.1 创建计数信号量
/********************动态创建计数信号量**********************************************/
SemaphoreHandle_t xSemaphoreCreateCounting(UBaseType_t uxMaxCount,
										   UBaseType_t uxInitialCount)
/********************静态创建计数信号量**********************************************/
SemaphoreHandle_t xSemaphoreCreateCountingStatic(UBaseType_t uxMaxCount,//信号量最大计数值
											 UBaseType_t uxInitialCount,//计数信号量初始值
								  StaticSemaphore_t * pxSemaphoreBuffer)//保存信号量结构体
/***********************************************************************************/
返回值:创建成功返回计数信号量句柄;失败返回NULL


动态计数信号量创建函数是一个宏,最终是通过xQueueCreateCountingSemaphore()函数来完成,其源码如下:

#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
#define xSemaphoreCreateCounting( uxMaxCount, uxInitialCount ) 	\
xQueueCreateCountingSemaphore( (uxMaxCount),(uxInitialCount) )	
#endif

QueueHandle_t xQueueCreateCountingSemaphore(const UBaseType_t uxMaxCount,const UBaseType_t uxInitialCount){
	QueueHandle_t xHandle;
	/* 调用消息队列创建函数,创建队列长度为uxMaxCount,队列项长度为0,类型为计数信号量的队列 */
	xHandle = xQueueGenericCreate(uxMaxCount,queueSEMAPHORE_QUEUE_ITEM_LENGTH,queueQUEUE_TYPE_COUNTING_SEMAPHORE);
	if( xHandle != NULL ){
		/* 将计数信号量的初始值来设置uxMessagesWaiting,代表可用的资源数量 */
		( ( Queue_t * ) xHandle )->uxMessagesWaiting = uxInitialCount;
		traceCREATE_COUNTING_SEMAPHORE();
	}
	else{
		traceCREATE_COUNTING_SEMAPHORE_FAILED();
	}
	return xHandle;
}

2.2 释放和获取计数信号量

计数型信号量的释放与获取与二值信号量相同,可参考二值信号量中的3.2和3.3章节

3. 计数信号量的应用实例

本实例的功能需求是使用两个按键触发计数信号量的释放和获取,并打印出当前信号量的计数值

使用STM32CubeMX将FreeRTOS移植到工程中,创建一个按键处理任务、一个计数信号量

Keyscan_Task:扫描按键状态,根据不同的键值释放或者获取信号量

3.1 STM32CubeMX设置
  • RCC设置外接HSE,时钟设置为72M
  • PC0设置为GPIO推挽输出模式、上拉、高速、默认输出电平为高电平
  • USART1选择为异步通讯方式,波特率设置为115200Bits/s,传输数据长度为8Bit,无奇偶校验,1位停止位;开启串口中断
  • 激活FreeRTOS,添加Keyscan_Task任务,设置任务名称、优先级、堆栈大小、函数名称等参数

在这里插入图片描述

  • 动态创建计数信号量,需要先使能USE_COUNTING_SEMAPHORES

在这里插入图片描述
在这里插入图片描述

  • 使用FreeRTOS操作系统,一定要将HAL库的Timebase Source从SysTick改为其他定时器,选好定时器后,系统会自动配置TIM
  • 输入工程名,选择路径(不要有中文),选择MDK-ARM V5;勾选Generated periphera initialization as a pair of ‘.c/.h’ files per IP ;点击GENERATE CODE,生成工程代码
3.2 MDK-ARM软件编程
  • 创建按键驱动文件key.c和key.h,参考按键输入例程
  • 添加KeyscanTask任务函数代码
void KeyscanTask(void const * argument){
  int8_t key;
  int8_t sem_value;
  BaseType_t err;
  for(;;){
	key = KEY_Scan(0);
	if(CountingSemHandle != NULL){
	  switch(key){
		case KEY_UP_PRES:
		  err = xSemaphoreTake(CountingSemHandle,portMAX_DELAY);
		  if(err == pdFALSE)
			printf("Semaphore Take failed!\r\n");
		  else{
			sem_value = uxSemaphoreGetCount(CountingSemHandle);
			printf("Semaphore Take successed, Semvalue = %d\r\n",sem_value);
			HAL_GPIO_WritePin(GPIOC,GPIO_PIN_0,GPIO_PIN_RESET);
		  }
		  break;
		case KEY_DOWN_PRES:
		  err = xSemaphoreGive(CountingSemHandle);
		  if(err == pdFALSE)
			printf("Semaphore Give failed!\r\n");
		  else{
			sem_value = uxSemaphoreGetCount(CountingSemHandle);
			printf("Semaphore Give successed, Semvalue = %d\r\n",sem_value);
			HAL_GPIO_WritePin(GPIOC,GPIO_PIN_0,GPIO_PIN_SET);
		  }
		  break;
	  }
	}
    osDelay(10);
  }
}

3.3 下载验证

编译无误下载到开发板后,按下K_UP按键获取信号,串口打印出当前信号量的计数值,同时点亮LED0;按下K_DOWN按键释放信号量,串口打印出当前信号量的计数值,同时熄灭LED0;信号量最大计数值设置为10了,因此信号量释放到10后,无法继续释放

在这里插入图片描述

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值