FreeRTOS计数信号量使用

基本特性

计数信号量,也可以看成是队列,但是长度大于1。用户只需关心是否为空。

典型应用

(1)计数

事件发生的时候,在事件处理函数中给一个信号量(既就是信号量值计数值加1),任务处理函数获取这个信号量(既就是信号量计数值值减1)。

信号量计数值初始为0。

 (2)资源管理

用于指示可用的资源。

当信号好计数值到0的时候,表示没有资源可用。

一个任务想要使用资源,需要先获取信号量——也就是信号量值减1;当一个任务使用完资源(释放资源)的时候,需要给一个信号——也就是信号量值加1。

信号量初始值为最大值。

典型场景:

比如有个30人的电脑机房,我们就可以创建信号量的初始化值是30,表示30个可用资源,是的,信号量说白了就是共享资源的数量。另外我们要求一个同学使用一台电脑,这样每有一个同学使用一台电脑,那么信号量的数值就减一,直到30台电脑都被占用,此时信号量的数值就是0。如果此时还有几个同学没有电脑可以使用,那么这几个同学就得等待,直到有同学离开。有一个同学离开,那么信号量的数值就加1,有两个就加2,依此类推。刚才没有电脑用的同学此时就有电脑可以用了,有几个同学用,信号量就减几,直到再次没有电脑可以用,这么一个过程就是使用信号量来管理共享资源的过程。

以上两种应用的最大区别就是,信号量计数值的初始值。

部分API

typedef void * QueueHandle_t;
typedef QueueHandle_t SemaphoreHandle_t;//信号量句柄,从这里也可以看到源码实现还是用的队列

xSemaphoreGive( SemaphoreHandle_t xSemaphore )  //给一个信号量
xSemaphoreTake( SemaphoreHandle_t xSemaphore,TickType_t xBlockTime)//获取信号量
xSemaphoreGiveFromISR(SemaphoreHandle_t xSemaphore,BaseType_t *pxHigherPriorityTaskWoken)
//给一个信号量,用于中断函数里面

可以看出以上的API与二值信号量API是一样的。

SemaphoreHandle_t xSemaphoreCreateCounting( UBaseType_t uxMaxCount, UBaseType_t uxInitialCount )
//创建计数信号量,uxMaxCount:表示最大计数值,uxInitialCount :初始化计数值
uxSemaphoreGetCount( SemaphoreHandle_t xSemaphore )//获取当前的计数

上面两个是计数信号量特有的API。

测试程序

总体设计:2个任务,1个计数信号量。

printcounttask:打印当前计数信号量的值;

serialtask:获取计数信号量,并打印获取之后的计数信号量的值;

串口中断:接收到串口数据后,给一个信号量。

 创建任务和计数信号量

#define PRINT_COUNT_TASK_PRIO		    1	   //任务优先级
#define PRINT_COUNT_TASK_STK_SIZE 	    80     //任务堆栈大小
TaskHandle_t PrintCountTaskHandler;                //任务句柄
void PrintCountFunc(void *pvParameters);           //任务函数

#define SERIAL_TASK_PRIO	            4	   //任务优先级
#define SERIAL_TASK_STK_SIZE 		    80     //任务堆栈大小
TaskHandle_t SerialTaskHandler;                    //任务句柄
void SerialTaskFunc(void *pvParameters);           //任务函数
SemaphoreHandle_t TaskToTrqSemaphoreCounting;

void OtherTest(void )
{
    BaseType_t ret;
	
    BoardInitMcu();
    BoardInitPeriph();
    
    TaskToTrqSemaphoreCounting=xSemaphoreCreateCounting( 10, 0 );

    ret=xTaskCreate((TaskFunction_t )PrintCountFunc,     	
		    (const char*    )"printcount",   	
		    (uint16_t       )PRINT_COUNT_TASK_STK_SIZE, 
	            (void*          )NULL,				
		    (UBaseType_t    )PRINT_COUNT_TASK_PRIO,	
		    (TaskHandle_t*  )&PrintCountFunc); 
			
    ret=xTaskCreate((TaskFunction_t )SerialTaskFunc,     
		    (const char*    )"serialtask",   
		    (uint16_t       )SERIAL_TASK_STK_SIZE, 
		    (void*          )NULL,
		    (UBaseType_t    )SERIAL_TASK_PRIO,
		    (TaskHandle_t*  )&SerialTaskHandler); 
				
    vTaskStartScheduler(); 
}

任务函数

void  PrintCountFunc(void *pvParameters)
{
    UBaseType_t count;

    for(;;)
    {
        count=uxSemaphoreGetCount(TaskToTrqSemaphoreCounting);
	printf("before =%d\r\n",(int)count);
		
	vTaskDelay(500);                        
    }
}

void SerialTaskFunc(void *pvParameters)
{
    UBaseType_t count;
	
    for(;;)
    {		
	if(xSemaphoreTake(TaskToTrqSemaphoreCounting,10))//阻塞10ms
	{
	    count=uxSemaphoreGetCount(TaskToTrqSemaphoreCounting);
	    printf("after =%d\r\n",(int)count);
	}

	vTaskDelay(1000);
    }
}

串口中断

void USART1_IRQHandler( void )
{
    BaseType_t pxHigherPriorityTaskWoken=pdFALSE;
	
    //省略部分代码,只列出重要部分

    if(RESET != __HAL_UART_GET_FLAG(&UartHandle,UART_FLAG_IDLE))//空闲中断
    {                   
	__HAL_UART_CLEAR_IDLEFLAG(&UartHandle);
  
        /*设置信号量*/
        xSemaphoreGiveFromISR(TaskToTrqSemaphoreCounting,&pxHigherPriorityTaskWoken);
	portYIELD_FROM_ISR(pxHigherPriorityTaskWoken);
    }
}

运行结果

发布了35 篇原创文章 · 获赞 25 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/freemote/article/details/104362461