# STM32 RTOS 系列教學 - 第五篇：RTOS 訊號量（Semaphore）與資源同步應用

## 🎯 教學目標
- 理解 RTOS 中 Semaphore 的概念與分類（Binary / Counting）
- 學會在多任務間使用 Semaphore 實現資源同步
- 實作一個防止資源衝突的共享範例

## 🔐 Semaphore 是什麼？
Semaphore（訊號量）是 RTOS 中用來控制任務間共享資源的一種同步工具，避免同時存取導致資源衝突。

### 📌 種類
- **Binary Semaphore**：僅有 0 和 1，用於任務間同步（類似旗標）
- **Counting Semaphore**：允許多個資源存取計數（像計數器），適用於多個資源管理

---

## 🛠 STM32CubeMX 設定 Semaphore

### Step 1：新增 Semaphore
- 開啟 `Middleware > FreeRTOS > CMSIS RTOS v2`
- 新增 `Semaphore`，命名為 `myBinarySem01`
- 類型選擇 `Binary`

### Step 2：取得 Handle 並初始化
- 在 `main.c` 中取得 handle：
```c
osSemaphoreId_t myBinarySem01Handle;
```
- 在初始化階段建立 semaphore：
```c
const osSemaphoreAttr_t myBinarySem01_attributes = {
  .name = "myBinarySem01"
};
myBinarySem01Handle = osSemaphoreNew(1, 0, &myBinarySem01_attributes);
```

---

## ✋ 任務同步範例：Button Trigger

### 範例說明：
- 任務 A 持續等待 semaphore（類似被 block）
- 中斷服務程式 (EXTI) 發生時觸發 `osSemaphoreRelease()`

### EXTI 中斷觸發：
```c
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
  if(GPIO_Pin == GPIO_PIN_13)
  {
    osSemaphoreRelease(myBinarySem01Handle);
  }
}
```

### 任務中等待觸發：
```c
void StartDefaultTask(void *argument)
{
  for(;;)
  {
    if(osSemaphoreAcquire(myBinarySem01Handle, osWaitForever) == osOK)
    {
      HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5);
    }
  }
}
```

---

## 🧠 常見應用場景
- Button / IRQ 中斷喚醒任務
- 任務間事件同步（生產者-消費者）
- 控制一次只允許一個任務進入共享區（Critical Section）

---

## ✅ 成功條件檢查
- 按下按鈕，LED 能夠閃爍一次，且不會重複觸發
- 任務能穩定接收中斷產生的 semaphore
- 無資源衝突或 crash 現象

---

## 🧩 下一篇預告
**第 6 篇：RTOS Queue 任務間資料傳輸實作**