Skip to main content

STM32 RTOS 系列教學 - 第三篇:RTOS 任務間通訊(Queue 與 Semaphore 實作)

STM32 RTOS 系列教學 - 第三篇:RTOS 任務間通訊(Queue 與 Semaphore 實作)

🎯 教學目標

  • 理解 RTOS 中 Queue(佇列)的用途與特性
  • 學會在任務之間安全地傳遞資料
  • 使用 Queue 實作一個簡單的生產者-消費者範例
  • 結合 Semaphore 控制 Queue 的存取

📦 Queue 是什麼?

Queue(佇列)是一種資料結構,可在 RTOS 中讓任務之間以 FIFO(先進先出)方式安全交換資料。每個任務可以是資料的「生產者」或「消費者」。

📌 特性

  • 支援固定長度的訊息資料(byte 或結構)
  • 多任務可同時傳送(Send)與接收(Receive)資料
  • 有 blocking / timeout 功能,等待 Queue 可用
  • 適合用於任務間資料傳輸、命令交換、感測器讀值同步等

🔒 Semaphore 是什麼?

Semaphore(信號量)是 RTOS 中的同步工具,用來控制對共享資源(如 Queue)的存取,避免資源競爭。

📌 常見類型

  • Binary Semaphore:常用於同步(如中斷觸發任務)
  • Counting Semaphore:常用於資源控制(如 Queue 空間或緩衝區)

🛠 STM32CubeMX 設定 Queue 與 Semaphore

Step 1:新增 Queue

  • 開啟 Middleware > FreeRTOS > CMSIS RTOS v2
  • 新增 Message Queue,命名為 myQueue01
  • 設定:
    • 資料長度:sizeof(uint16_t) 或自訂 struct
    • Queue 長度:例如 10(最多可存放 10 筆資料)

Step 2:新增 Semaphore(可選)

  • FreeRTOS > CMSIS RTOS v2 新增 Semaphore
  • 命名為 myBinarySem01,選擇 Binary

Step 3:初始化

// Queue 初始化
osMessageQueueId_t myQueue01Handle;
const osMessageQueueAttr_t myQueue01_attributes = {
  .name = "myQueue01"
};
myQueue01Handle = osMessageQueueNew(10, sizeof(uint16_t), &myQueue01_attributes);

// Semaphore 初始化
osSemaphoreId_t myBinarySem01Handle;
const osSemaphoreAttr_t myBinarySem01_attributes = {
  .name = "myBinarySem01"
};
myBinarySem01Handle = osSemaphoreNew(1, 1, &myBinarySem01_attributes); // 初始為可用

🧪 範例:數值傳送與接收

任務 A(傳送端) - 每秒傳送一個數字:

void StartSenderTask(void *argument)
{
  uint16_t value = 0;
  for(;;)
  {
    osSemaphoreAcquire(myBinarySem01Handle, osWaitForever);  // 取得信號
    osMessageQueuePut(myQueue01Handle, &value, 0, 0);
    osSemaphoreRelease(myBinarySem01Handle);  // 釋放信號
    value++;
    osDelay(1000);
  }
}

任務 B(接收端) - 接收後印出數值:

void StartReceiverTask(void *argument)
{
  uint16_t recvVal;
  for(;;)
  {
    osSemaphoreAcquire(myBinarySem01Handle, osWaitForever);  // 取得信號
    if(osMessageQueueGet(myQueue01Handle, &recvVal, NULL, osWaitForever) == osOK)
    {
      printf("Received: %d\n", recvVal);
    }
    osSemaphoreRelease(myBinarySem01Handle);  // 釋放信號
  }
}

🧠 應用場景

  • 任務間傳送 sensor 資料
  • 接收中斷服務程式的資料(需透過中斷內部觸發任務)
  • 排程控制命令、狀態
  • 結合 Semaphore 確保多任務對 Queue 的安全存取

✅ 成功條件檢查

  • 每秒有數值被傳送與接收
  • 無資料遺失(Queue 空間足夠)
  • 接收順序正確(FIFO)
  • Semaphore 正確同步,無競爭狀況

第 4 篇:RTOS 計時器(Software Timer)與非阻塞處理技巧