求知 文章 文库 Lib 视频 iPerson 课程 认证 咨询 工具 讲座 Modeler   Code  
会员   
要资料
 
追随技术信仰

随时听讲座
每天看新闻
 
 
FreeRTOS源码分析及应用开发
1. FreeRTOS系列 | FreeRTOS简介
2. FreeRTOS系列 | 开发环境
3. FreeRTOS系列 | 任务基础知识
4. FreeRTOS系列 | 任务创建和删除
5. FreeRTOS系列 | 任务挂起和恢复
6. FreeRTOS系列|多任务调度
7. FreeRTOS系列|时间管理
8. FreeRTOS系列|中断管理和临界段
9. FreeRTOS系列|任务堆栈
10. FreeRTOS系列 | 处理器利用率
11. FreeRTOS系列|任务相关API函数
12. FreeRTOS系列 | 列表和列表项
13. FreeRTOS系列|消息队列一
14. FreeRTOS系列|消息队列二
15. FreeRTOS系列 | 二值信号量
16. FreeRTOS系列 | 互斥信号量
17. FreeRTOS系列 | 计数信号量
18. FreeRTOS系列 | 递归互斥信号量
19. FreeRTOS系列 | 事件标志组
20. FreeRTOS系列 | 软件定时器
21. FreeRTOS系列 | 低功耗管理
22. FreeRTOS系列 | 内存管理一
23. FreeRTOS系列 | 内存管理二
 

 
目录
FreeRTOS系列|计数信号量
作者:安迪西嵌入式
191 次浏览
3次  

计数信号量

1. 计数信号量简介

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

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

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

 

2. 计数信号量的API函数

2.1 创建计数信号量

/********************动态创建计数信号量**********************************************/
SemaphoreHandle_t xSemaphoreCreateCounting(UBaseType_t uxMaxCount,
BaseType_t uxInitialCount)
/********************静态创建计数信号量**********************************************/
SemaphoreHandle_t xSemaphoreCreateCountingStatic(UBaseType_t uxMaxCount,//信号量最大计数值
BaseType_t uxInitialCount,//计数信号量初始值
taticSemaphore_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任务,设置任务名称、优先级、堆栈大小、函数名称等参数

 

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

 

  • 使用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元 10元 50元





认证码: 验证码,看不清楚?请点击刷新验证码 必填



191 次浏览
3次