
FreeRTOS 入門系列文章,在自己梳理知識的同時,希望能夠幫助初學者快速入門,掌握FreeRTOS的基本原理和使用方法。
FreeRTOS快速入門-初探系統
FreeRTOS 官方中文版網站上線啦
FreeRTOS編碼標準與數據類型
FreeRTOS快速入門-任務管理
FreeRTOS學習之消息隊列詳解
本篇文章介紹一下 FreeRTOS 的計數信號量相關內容。
計數信號量是FreeRTOS中一種重要的同步機制,它允許任務之間或任務與中斷服務程序(ISR)之間進行事件通知和資源管理。
計數信號量具有以下特點:
計數信號量的核心是一個計數器和一個任務等待列表:
計數信號量在嵌入式系統中主要有兩種用途:
SemaphoreHandle_t xSemaphoreCreateCounting( UBaseType_t uxMaxCount,
UBaseType_t uxInitialCount );
uxMaxCount:信號量可以達到的最大計數值uxInitialCount:信號量的初始計數值示例:
// 創建一個最大計數值為10,初始值為0的計數信號量
SemaphoreHandle_t xCountingSemaphore = xSemaphoreCreateCounting(10, 0);
FreeRTOS提供了多種獲取信號量的方式:
阻塞方式獲取
BaseType_t xSemaphoreTake( SemaphoreHandle_t xSemaphore, TickType_t xTicksToWait );
xSemaphore:信號量句柄xTicksToWait:最大阻塞時間(單位:tick),使用portMAX_DELAY表示無限等待非阻塞方式獲取
BaseType_t xSemaphoreTakeFromISR( SemaphoreHandle_t xSemaphore,
BaseType_t *pxHigherPriorityTaskWoken );
pxHigherPriorityTaskWoken用于指示是否有更高優先級任務被喚醒普通釋放
BaseType_t xSemaphoreGive( SemaphoreHandle_t xSemaphore );
在ISR中釋放
BaseType_t xSemaphoreGiveFromISR( SemaphoreHandle_t xSemaphore,
BaseType_t *pxHigherPriorityTaskWoken );
pxHigherPriorityTaskWoken用于指示是否有更高優先級任務被喚醒事件計數示例
// 信號量句柄聲明
SemaphoreHandle_t xEventSemaphore;
// 任務函數:事件處理
void vEventHandlerTask(void *pvParameters) {
while(1) {
// 等待事件發生
if(xSemaphoreTake(xEventSemaphore, portMAX_DELAY) == pdTRUE) {
// 處理事件
printf("Event processed. Remaining events: %u\n",
uxSemaphoreGetCount(xEventSemaphore));
}
}
}
// 中斷服務程序:產生事件
void vInterruptHandler(void) {
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
// 釋放信號量(通知事件發生)
xSemaphoreGiveFromISR(xEventSemaphore, &xHigherPriorityTaskWoken);
// 如果需要,進行上下文切換
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}
// 主函數
int main(void) {
// 創建計數信號量,初始值為0,最大值為10
xEventSemaphore = xSemaphoreCreateCounting(10, 0);
// 創建事件處理任務
xTaskCreate(vEventHandlerTask, "EventHandler", configMINIMAL_STACK_SIZE, NULL, 2, NULL);
// 啟動調度器
vTaskStartScheduler();
while(1);
}
資源管理示例
// 假設我們有3個相同的硬件資源(如UART接口)
#define MAX_UART_RESOURCES 3
// 信號量句柄
SemaphoreHandle_t xUARTSemaphore;
// 任務函數:使用UART資源
void vUARTUserTask(void *pvParameters) {
while(1) {
// 嘗試獲取UART資源
if(xSemaphoreTake(xUARTSemaphore, pdMS_TO_TICKS(100)) == pdTRUE) {
// 成功獲取資源
printf("Task %s got UART resource\n", pcTaskGetName(NULL));
// 模擬使用UART資源
vTaskDelay(pdMS_TO_TICKS(500));
// 釋放資源
xSemaphoreGive(xUARTSemaphore);
printf("Task %s released UART resource\n", pcTaskGetName(NULL));
} else {
// 獲取資源超時
printf("Task %s failed to get UART resource\n", pcTaskGetName(NULL));
}
vTaskDelay(pdMS_TO_TICKS(200));
}
}
// 主函數
int main(void) {
// 創建計數信號量,初始值=最大值=3(表示有3個可用資源)
xUARTSemaphore = xSemaphoreCreateCounting(MAX_UART_RESOURCES, MAX_UART_RESOURCES);
// 創建多個任務競爭使用UART資源
xTaskCreate(vUARTUserTask, "Task1", configMINIMAL_STACK_SIZE, NULL, 1, NULL);
xTaskCreate(vUARTUserTask, "Task2", configMINIMAL_STACK_SIZE, NULL, 1, NULL);
xTaskCreate(vUARTUserTask, "Task3", configMINIMAL_STACK_SIZE, NULL, 1, NULL);
xTaskCreate(vUARTUserTask, "Task4", configMINIMAL_STACK_SIZE, NULL, 1, NULL);
// 啟動調度器
vTaskStartScheduler();
while(1);
}
UBaseType_t uxSemaphoreGetCount( SemaphoreHandle_t xSemaphore );
當信號量計數值達到最大值時,再次釋放信號量將失敗。在實際應用中應考慮:
xSemaphoreGive的返回值configUSE_16_BIT_TICKS設置為0以使用32位計數值)FromISR版本的APITake都有對應的Give可能原因:
解決方案:
uxSemaphoreGetCount調試當前計數值xSemaphoreGive的返回值可能原因:
解決方案:
可能原因:
pxHigherPriorityTaskWoken標志解決方案:
FromISR版本的APIpxHigherPriorityTaskWoken標志通過合理使用計數信號量,可以構建出高效、可靠的嵌入式多任務系統。關鍵點包括:

覺得文章不錯,點擊“分享”、“贊”、“推薦” 唄!