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);
    }
}

運行結果

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章