目錄
一、計數型信號量簡介
二、計數型信號量相關API
1、創建計數型信號量
2、釋放計數型信號量
3、獲取計數型信號量
4、獲取計數型信號量的計數值
三、計數型信號量實操
1、實驗需求
2、CubeMX配置
3、代碼實現
一、計數型信號量簡介
①取值只有0與1兩種狀態的信號量稱之為二值信號量;取值大于1的信號量稱之為計數信號量
②計數信號量是一種長度大于1,消息大小為0的特殊消息隊列。 ?
③計數信號量的取值也可以為1,但通常大于1,如果取值為1,相當于只有0與1兩種狀態,用二值信號量即可。
④創建計數信號量時,系統會為創建的計數信號量分配內存。
計數型信號量相當于隊列長度大于1 的隊列,因此計數型信號量能夠容納多個資源,這在計數型信號量被創建的時候確定的。
使用計數型信號量可以解決多個任務之間的同步問題,例如控制對共享資源的訪問和協調任務的執行順序。
二、計數型信號量相關API
函數 | 描述 |
xSemaphoreCreateCounting() | 使用動態方法創建計數型信號量 |
xSemaphoreCreateCountingStatic() | 使用靜態方法創建計數型信號量 |
xSemaphoreGive() | 釋放信號量 |
xSemaphoreGiveFromISR() | 在中斷中釋放信號量 |
xSemaphoreTake() | 獲取信號量 |
xSemaphoreTakeFromISR() | 在中斷中獲取信號量 |
uxSemaphoreGetCount() | 獲取信號量的計數值 |
1、創建計數型信號量
SemaphoreHandle_t xSemaphoreCreateCounting( UBaseType_t uxMaxCount,UBaseType_t uxInitialCount);
參數:
- uxMaxCount:可以達到的最大計數值
- uxInitialCount:創建信號量時分配給信號量的計數值,即計數值的初始值(一般設置為0才能正常計數)
返回值:
- 成功,返回對應計數型信號量的句柄;
- 失敗,返回 NULL。
2、釋放計數型信號量
BaseType_t xSemaphoreGive( SemaphoreHandle_t xSemaphore );
參數:
- xSemaphore:要釋放的信號量句柄
返回值:
- 成功,返回 pdPASS ;
- 失敗,返回 errQUEUE_FULL 。
3、獲取計數型信號量
BaseType_t xSemaphoreTake( SemaphoreHandle_t xSemaphore,TickType_t xTicksToWait );
參數:
- xSemaphore:要獲取的信號量句柄
- xTicksToWait:超時時間,0 表示不超時,portMAX_DELAY表示卡死等待;
返回值:
- 成功,返回 pdPASS ;
- 失敗,返回 errQUEUE_FULL 。
4、獲取計數型信號量的計數值
BaseType_t uxSemaphoreGetCount( SemaphoreHandle_t xSemaphore );
參數:
- xSemaphore:要獲取的信號量句柄
返回值:
????????得到計數型信號量的值。
三、計數型信號量實操
1、實驗需求
創建一個計數型信號量,按下 KEY1 則釋放信號量,按下 KEY2 獲取信號量。
2、CubeMX配置
這里已經將FreeRTOS移植到STM32F103C8T6,具體操作流程看前面的文章。
查看原理圖配置按鍵引腳
?創建兩個任務用來放入和獲取信號量
使能計數型信號量
創建計數型信號量
3、代碼實現
uart.c 重定向printf
#include "stdio.h"
int fputc(int ch,FILE *f)
{unsigned char temp[1] = {ch};HAL_UART_Transmit(&huart1,temp,1,0xffff);return ch;
}
需要打開魔術棒勾上紅框內選項實現串口打印
打開freertos.c并添加代碼
void StartTaskKey1(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){if(xSemaphoreGive(myCountingSemHandle) == pdTRUE) printf("計數型信號量放入成功\r\n");elseprintf("計數型信號量放入失敗\r\n");}while (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_RESET);}osDelay(10);}
}void StartTaskKey2(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){ if(xSemaphoreTake(myCountingSemHandle,0) == pdTRUE) printf("計數型信號量獲取成功\r\n");elseprintf("計數型信號量獲取失敗\r\n");}while (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_1) == GPIO_PIN_RESET);}osDelay(10);}
}
兩個紅框說明當釋放信號量成功時,能成功獲取信號量(在設置最大范圍之內);當超過最大范圍后再次釋放會失敗,同時成功獲取信號量次數也是3次(設置的最大數),超過了再次獲取也會失敗。
注意:
創建后的計數型信號量原先代碼和修改后的代碼如下:
由于CubeMX內置函數設置計數值的初始值為最大值,即我們一開始設置的可以達到的最大計數值為3,所以第一次復位后釋放信號量總是失敗,初始值為最大值說明已經釋放完畢,此時可以直接獲取成功,當全部被獲取后,計數值才從0開始,即此時可以正常釋放信號量直至設定的最大值,如下: