衡阳派盒市场营销有限公司

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

FreeRTOS信號量使用教程

CHANBAEK ? 來源:凌云物聯網實驗室 ? 作者:郭工 ? 2022-12-19 09:22 ? 次閱讀

11.1 信號量說明

信號量是操作系統中重要的一部分,信號量一般用來進行資源管理和任務同步, FreeRTOS中信號量又分為二值信號量、 計數型信號量、互斥信號量和遞歸互斥信號量。信號量在實際應用中最廣泛的兩個用途是:

  • 臨界資源的鎖機制:用于控制共享資源訪問的場景相當于一個上鎖機制, 代碼只有獲得了這個鎖的鑰匙才能夠執行。
  • 多個任務同步機制:用于任務與任務或中斷與任務之間的同步。

在編寫中斷服務函數的時候我們都知道一定要快進快出,中斷服務函數里面不能放太多的代碼,否則的話會影響的中斷的實時性。 裸機編寫中斷服務函數的時候一般都只是在中斷服務函數中打個標記,然后在其他的地方根據標記來做具體的處理過程。在使用 RTOS 系統的時候我們就可以借助信號量完成此功能, 當中斷發生的時候就釋放信號量,中斷服務函數不做具體的處理。具體的處理過程做成一個任務,這個任務會獲取信號量,如果獲取到信號量就說明中斷發生了,那么就開始完成相應的處理,這樣做的好處就是中斷執行時間非常短。 這個例子就是中斷與任務之間使用信號量來完成同步,當然了, 任務與任務之間也可以使用信號量來完成同步。

在實際4G/WiFi等網絡應用中,一般最簡單的方法就是使用一個任務去查詢 4G/WiFi 模塊是否有數據到來,當有數據的時候就處理這個網絡數據。但這樣使用輪詢的方式是很浪費CPU 資源的,而且也阻止了其他任務的運行。一種理想的解決方法應該是當沒有網絡數據的時候網絡任務就進入阻塞態,把 CPU 讓給其他的任務,當有數據的時候網絡任務才去執行。現在使用二值信號量就可以實現這樣的功能,任務通過獲取信號量來判斷是否有網絡數據,沒有的話就進入阻塞態,而網絡中斷服務函數通過釋放信號量來通知任務以太網外設接收到了網絡數據,網絡任務可以去提取處理了。網絡任務只是在一直的獲取二值信號量,它不會釋放信號量,而中斷服務函數是一直在釋放信號量,它不會獲取信號量。

接下來,我們以二值信號量為例,講解信號量實現任務同步的大致流程。其實,二值信號量其實就是一個只有一個隊列項的隊列,這個特殊的隊列要么是滿的,要么是空的。二值信號量通常用于互斥訪問或任務同步,它與互斥信號量非常類似,但是還是有一些細微的差別,互斥信號量擁有優先級繼承機制,二值信號量沒有優先級繼承。因此二值信號另更適合用于同步(任務與任務或任務與中斷的同步),而互斥信號量適合用于簡單的互斥訪問。

  1. 任務獲取信號量有效
    如下圖所示,任務Task通過調用 xSemaphoreTake() 函數獲取信號量,但此時二值信號量無效,所以任務Task進入到阻塞態。
    圖片
  2. 中斷釋放信號量
    當有數據到來產生中斷后,在中斷服務處理程序中通過調用 xSemaphoreGiveFromISR() 函數釋放信號量,此后二值信號量有效。
    圖片
  3. 任務獲取信號量有效
    由于此時信號量已經有效了,所以任務 Task 獲取信號量成功,任務從阻塞態解除,開始執行相關的處理過程。
    圖片
  4. 任務再次進入阻塞
    由于任務一般是一個大的死循環,所以在任務做完相關處理以后就會再次調用 xSemaphoreTake() 函數獲取信號量,但此時信號量已經失效,因此任務將進入到狀態1下阻塞等待信號量有效。

11.2 信號量API說明

11.2.1 獲取信號量

不管是二值信號量、計數型信號量還是互斥信號量,它們都使用以下兩個函數獲取信號量。

/*
 參數
     xSemaphore: 要獲取的信號量句柄。
??  xBlockTime: 阻塞時間。??       
返回值:
     pdTRUE: 獲取信號量成功。
     pdFALSE: 超時,獲取信號量失敗。
 */
BaseType_t xSemaphoreTake(SemaphoreHandle_t xSemaphore,TickType_t xBlockTime)


/*
說明: 此函數用于在中斷服務函數中獲取信號量, 此函數用于獲取二值信號量和計數型信號量,絕對不能使用此函數來獲取互斥信號量。
參數: xSemaphore: 要獲取的信號量句柄。
      pxHigherPriorityTaskWoken: 標記退出此函數以后是否進行任務切換,這個變量的值由這三個函數來設置的,用戶不用進行設置,
              用戶只需要提供一個變量來保存這個值就行了。當此值為 pdTRUE 的時候在退出中斷服務函數之前一定要進行一次任務切換。
回值: pdPASS: 獲取信號量成功。
      pdFALSE: 獲取信號量失敗。   
 */      
BaseType_t xSemaphoreTakeFromISR(SemaphoreHandle_t xSemaphore,BaseType_t * pxHigherPriorityTaskWoken)

11.2.2 釋放信號量

釋放信號量分為任務級和中斷級。不管是二值信號量、計數型信號量還是互斥信號量,它們都使用以下兩個函數釋放信號量。

/*    
  參數:xSemaphore: 要釋放的信號量句柄。
返回值:
       pdPASS: 釋放信號量成功; 
       errQUEUE_FULL: 釋放信號量失敗。
 */  
BaseType_t xSemaphoreGive( xSemaphore )


/*    
說明: 此函數用于在中斷中釋放信號量, 此函數只能用來釋放二值信號量和計數型信號量,絕對不能用來在中斷服務函數中釋放互斥信號量。
參數: xSemaphore: 要釋放的信號量句柄。
      pxHigherPriorityTaskWoken: 標記退出此函數以后是否進行任務切換,這個變量的值由這三個函數來設置的,用戶不用進行設置,
               用戶只需要提供一個變量來保存這個值就行了。當此值為 pdTRUE 的時候在退出中斷服務函數之前一定要進行一次任務切換。
返回值:
      pdPASS: 釋放信號量成功。
      errQUEUE_FULL: 釋放信號量失敗。
*/      
BaseType_t xSemaphoreTakeFromISR(SemaphoreHandle_t xSemaphore,BaseType_t * pxHigherPriorityTaskWoken)

11.2.3 創建二值信號量

在FreeRTOS中,有兩個函數可以創建二值信號量:

/*
說明:  使用此函數創建二值信號量的話信號量所需要的 RAM 是由 FreeRTOS 的內存管理部分來動態分配的。
返回值:
      NULL: 二值信號量創建失敗。
      其他值: 創建成功的二值信號量的句柄。
 */
SemaphoreHandle_t xSemaphoreCreateBinary( void )


/*
說明:  此函數也是創建二值信號量的,只不過使用此函數創建二值信號量的話信號量所需要的RAM需要由用戶來分配
參數:  pxSemaphoreBuffer: 此參數指向一個 StaticSemaphore_t 類型的變量,用來保存信號量結構體。
返回值:
      NULL: 二值信號量創建失敗。
      其他值: 創建成功的二值信號量句柄。
 */
SemaphoreHandle_t xSemaphoreCreateBinaryStatic( StaticSemaphore_t *pxSemaphoreBuffer )

11.2.4 創建互斥信號量

在FreeRTOS中,有兩個函數可以創建互斥信號量:

/*
說明:此函數用于創建一個互斥信號量,所需要的內存通過動態內存管理方法分配。
參數:無
返回值:
     NULL: 互斥信號量創建失敗。
     其他值: 創建成功的互斥信號量的句柄。
 */
SemaphoreHandle_t xSemaphoreCreateMutex( void )


/*
說明: 此函數也是創建互斥信號量的,只不過使用此函數創建互斥信號量的話信號量所需要的RAM 需要由用戶來分配
參數: pxMutexBuffer: 此參數指向一個 StaticSemaphore_t 類型的變量,用來保存信號量結構體。
返回值:
      NULL: 互斥信號量創建失敗。
      其他值: 創建成功的互斥信號量的句柄。
 */
SemaphoreHandle_t xSemaphoreCreateMutexStatic( StaticSemaphore_t *pxMutexBuffer )

11.2.5 創建計數信號量

在FreeRTOS中,有兩個函數可以創建計數信號量:

/*
說明: 此函數用于創建一個計數型信號量,所需要的內存通過動態內存管理方法分配。
參數:  
      uxMaxCount: 計數信號量最大計數值,當信號量值等于此值的時候釋放信號量就會失敗。
      uxInitialCount: 計數信號量初始值。
返回值:
      NULL: 計數型信號量創建失敗。
      其他值: 計數型信號量創建成功,返回計數型信號量句柄。
 */
SemaphoreHandle_t xSemaphoreCreateCounting(UBaseType_t uxMaxCount,UBaseType_t uxInitialCount )


/*
說明: 此函數也是用來創建計數型信號量的,使用此函數創建計數型信號量的時候所需要的內存需要由用戶分配。
參數: 
      uxMaxCount: 計數信號量最大計數值,當信號量值等于此值的時候釋放信號量就會失敗。
      uxInitialCount: 計數信號量初始值。
      pxSemaphoreBuffer: 指向一個 StaticSemaphore_t 類型的變量,用來保存信號量結構體。
返回值:
      NULL: 計數型信號量創建失敗。
      其他值: 計數型號量創建成功,返回計數型信號量句柄。
 */
SemaphoreHandle_t xSemaphoreCreateCountingStatic( UBaseType_t uxMaxCount,UBaseType_t uxInitialCount,StaticSemaphore_t * pxSemaphoreBuffer )

11.2.6 遞歸互斥信號量

遞歸互斥信號量可以看是一種特殊的互斥信號量,已經獲取了信號量的任務就不能再次獲取這個互斥量,但是遞歸互斥信號量不同,已經獲取了遞歸互斥信號量的任務可以再次獲取這個遞歸互斥信號量,次數不限。也就是在同一個任務中可以無限次獲取遞歸互斥信號量,中途不需要釋放,而互斥信號量獲取一次后就失效,需要再次釋放才有效。注意:任務獲取多少次遞歸互斥信號量,就要釋放多少次遞歸信號量。

/*
說明:  動態創建遞歸互斥信號量
參數:  無
返回值:創建失敗NULL,創建成功返回信號量句柄。
*/
SemaphoreHandle_t xSemaphoreCreateRecursiveMutex( void )
#define xSemaphoreCreateRecursiveMutex()            xQueueCreateMutex( queueQUEUE_TYPE_RECURSIVE_MUTEX )


/*
說明:  靜態創建遞歸互斥信號量
參數:  pxMutexBuffer:指向StaticSemaphore_t類型的變量,用來保存信號量結構體。
返回值: 創建失敗NULL,創建成功返回信號量句柄。
*/    
SemaphoreHandle_t xSemaphoreCreateRecursiveMutexStatic( StaticSemaphore_t *pxMutexBuffer )
#define xSemaphoreCreateRecursiveMutexStatic( pxStaticSemaphore )          xQueueCreateMutexStatic( queueQUEUE_TYPE_RECURSIVE_MUTEX, pxStaticSemaphore )


/*
說明:  釋放遞歸互斥信號量
參數:  xMutex:  信號量句柄
返回值:
       pdPASS:  釋放信號量成功
       pdFAIL:  釋放信號量失敗
*/
xSemaphoreGiveRecursive( SemaphoreHandle_t xMutex )
#define xSemaphoreGiveRecursive( xMutex )    xQueueGiveMutexRecursive( ( xMutex ) )


/*
說明:獲取遞歸互斥信號量
參數:
     xMutex:    信號量句柄
     xBlockTime:阻塞時間
返回值:
     pdPASS:    獲取信號量成功
     pdFAIL:    獲取信號量失敗
*/
xSemaphoreTakeRecursive( SemaphoreHandle_t xMutex, TickType_t xBlockTime );
#define xSemaphoreTakeRecursive( xMutex, xBlockTime )    
        xQueueTakeMutexRecursive( ( xMutex ), ( xBlockTime ) )

11.3 信號量多任務同步實例

在這里我們將創建兩個Led線程,其中藍色Led線程每隔200ms閃爍一次,而紅色Led線程則每隔1200ms閃爍一次。然后我們使用二值信號量的機制,讓兩個Led線程同步交替閃爍一次。

11.3.1 創建兩個線程任務

如下圖所示,單擊窗格頂部的 “New Thread 按鈕,添加兩個線程分別命名為 thread_led1 和 thread_led2 ,其它的保持默認配置即可,并重新生成代碼。

圖片

如下圖所示,單擊窗口的 “New Object” 按鈕,選擇 “Binary Semaphore” 添加一個二值信號量,然后修改該信號量的名稱為 g_led_semaphore ,并重新生成代碼。

圖片

11.3.2 修改信號量實例代碼

修改 thread_led1_entry.c 源碼如下:

#include "thread_led1.h"

/* Led Thread entry function */
/* pvParameters contains TaskHandle_t */
void thread_led1_entry(void *pvParameters)
{
    FSP_PARAMETER_NOT_USED (pvParameters);

    R_BSP_PinAccessEnable(); /* Enable access to the PFS registers. */

    /* TODO: add your own code here */
    while (1)
    {
        xSemaphoreTake( g_led_semaphore, portMAX_DELAY );

        R_BSP_PinWrite(LedRed, BSP_IO_LEVEL_HIGH);
        vTaskDelay (600);
        R_BSP_PinWrite(LedRed, BSP_IO_LEVEL_LOW);
        vTaskDelay (600);
    }
}
  • 如果不加信號量操作部分代碼,紅色Led將每隔1200ms閃爍一次;
  • 這里調用了xSemaphoreTake() 函數來獲取信號量 g_led_semaphore,如果 thread_led2 線程沒有運行并釋放信號量的話,它將會阻塞;
  • xSemaphoreTake() 函數在獲取到信號之后,將會讓紅色Led閃爍一次;
  • 之后該線程將會再次調用了xSemaphoreTake() 函數,等待 thread_led2 線程釋放信號;

修改 thread_led2_entry.c 源碼如下:

#include "thread_led2.h"

/* Led Thread entry function */
/* pvParameters contains TaskHandle_t */
void thread_led2_entry(void *pvParameters)
{
    FSP_PARAMETER_NOT_USED (pvParameters);

    R_BSP_PinAccessEnable(); /* Enable access to the PFS registers. */

    /* TODO: add your own code here */
    while (1)
    {
        if( pdTRUE == xSemaphoreGive( g_led_semaphore) )
        {
            R_BSP_PinWrite(LedBlue, BSP_IO_LEVEL_HIGH);
            vTaskDelay (100);
            R_BSP_PinWrite(LedBlue, BSP_IO_LEVEL_LOW);
            vTaskDelay (100);
        }
    }
}
  • 如果不加信號量操作部分代碼,藍色Led將每隔200ms閃爍一次;
  • 這里調用了xSemaphoreGive() 函數釋放信號量 g_led_semaphore,用來同步通知 thread_led1 線程運行;
  • xSemaphoreGive() 函數在釋放信號之后,如果 thread_led1 沒有來得及獲取信號量的話,則會返回pdFALSE;
  • 這樣,如果 thread_led1 沒有運行的話,藍色Led也不會閃爍了,從而實現了兩個線程中的Led同步交替閃爍一次效果了;
聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 操作系統
    +關注

    關注

    37

    文章

    6892

    瀏覽量

    123742
  • FreeRTOS
    +關注

    關注

    12

    文章

    484

    瀏覽量

    62394
  • 信號量
    +關注

    關注

    0

    文章

    53

    瀏覽量

    8373
收藏 人收藏

    評論

    相關推薦

    實時操作系統FreeRTOS信號量應用

    二值信號量通常用于互斥訪問或同步,二值信號量和互斥信號量非常相似,但還是有細微差別,互斥信號量擁有優先級繼承機制,二值信號沒有。因此二值信
    的頭像 發表于 06-08 09:24 ?3757次閱讀
    實時操作系統<b class='flag-5'>FreeRTOS</b><b class='flag-5'>信號量</b>應用

    FreeRTOS信號量的使用與實例

    在嵌入式系統中,任務管理是一個重要的部分,它涉及到任務之間的通信和同步,信號量,隊列,互斥鎖和事件標志組等概念。本文將以 FreeRTOS 為例,詳細講解這些內容。
    的頭像 發表于 12-12 15:25 ?2769次閱讀

    轉:freeRTOS信號量學習

    信號量同樣是RTOS學習中很重要的一節,信號量可以用在共享資源或者同步任務中,對執行權的控制,誰擁有信號量誰擁有執行權,在freeRTOS信號量
    發表于 08-12 18:29

    【NUCLEO-F412ZG試用體驗】FreeRTOS_信號量實現任務和中斷的同步

    上一期是用事件標志組實現的任務和中斷同步,使用信號量一樣可以實現任務之間以及任務和中斷的同步。首先說明,本例程參考了官方例程。實驗現象:1、3個LED閃爍。2、按鍵按下,發送相關信息。步驟:1、使能信號量。2、編寫測試代碼。新建信號量
    發表于 01-03 19:24

    FreeRTOS信號量不能刪除的原因?

    定義了兩個任務,第一個任務是使用串口收到Task字符則刪除信號量,但是經過測試,并不能刪除,發送兩次Task字符之后,程序回來死在信號量刪除部分,求解答為什么?
    發表于 07-27 08:00

    【轉載】AT32 FreeRTOS應用筆記

    ..................................................52FreeRTOS 信號量 ......................................59什么是信號量
    發表于 08-16 11:56

    FreeRTOS信號量介紹

    FreeRTOS信號量 & ESP32實戰閱讀建議:有一定操作系統基礎知識。FreeRTOS信號量1. 二值信號量??二值
    發表于 01-27 07:28

    FreeRTOS信號量的相關資料推薦

    一、互斥信號量簡介互斥信號量其實就是一個擁有優先級繼承的二值信號量,在同步的應用中(任務與任務或中斷與任務之間的同步)二值信號量最適合。互斥信號量
    發表于 02-28 13:39

    McuXpresso的靜態庫和IRQ處理程序問題求解

    我想制作一個靜態庫來處理一些 IRQ 和使用 FreeRTOS 信號量來處理具體處理的主程序。有些事情逃避了我,我不明白如何正確地做到這一點。我試圖制作一個靜態庫,但它有他的 SDK 和外圍設備定義。不調用 IRQ Handler 和 lib 中的初始化。解決此問題的最佳
    發表于 03-22 08:18

    FreeRTOS信號量 & ESP32實戰

    FreeRTOS信號量 & ESP32實戰閱讀建議:有一定操作系統基礎知識。FreeRTOS信號量1. 二值信號量??二值
    發表于 12-03 18:06 ?1次下載
    <b class='flag-5'>FreeRTOS</b><b class='flag-5'>信號量</b> & ESP32實戰

    FreeRTOS高級篇6---FreeRTOS信號量分析

    FreeRTOS信號量包括二進制信號量、計數信號量、互斥信號量(以后簡稱互斥)和遞歸互斥
    發表于 01-26 17:39 ?7次下載
    <b class='flag-5'>FreeRTOS</b>高級篇6---<b class='flag-5'>FreeRTOS</b><b class='flag-5'>信號量</b>分析

    FreeRTOS系列第20篇---FreeRTOS信號量API函數

    FreeRTOS信號量包括二進制信號量、計數信號量、互斥信號量(以后簡稱互斥)和遞歸互斥
    發表于 01-26 17:44 ?4次下載
    <b class='flag-5'>FreeRTOS</b>系列第20篇---<b class='flag-5'>FreeRTOS</b><b class='flag-5'>信號量</b>API函數

    在Arduino IDE中使用FreeRTOS信號量

    電子發燒友網站提供《在Arduino IDE中使用FreeRTOS信號量.zip》資料免費下載
    發表于 01-04 10:18 ?0次下載
    在Arduino IDE中使用<b class='flag-5'>FreeRTOS</b><b class='flag-5'>信號量</b>

    FreeRTOS的二值信號量

    FreeRTOS中的信號量是一種任務間通信的方式,信號量包括:二值信號量、互斥信號量、計數信號量
    的頭像 發表于 02-10 15:07 ?1553次閱讀

    FreeRTOS信號量介紹

    1、信號量用于控制對共享資源的訪問 舉一個很常見的例子,某個停車場有100個停車位,這 100 個停車位大家都可以用,對于大家來說這 100 個停車位就是共享資源。假設現在這個停車場正常運行,你要把
    的頭像 發表于 07-06 17:09 ?670次閱讀
    风水24向吉项| K7百家乐的玩法技巧和规则| 大发888 yule| 百家乐官网棋牌游戏正式版| 百家乐如何稳赢| 大发888在线充值| 网络百家乐官网投注| 百家乐网投注| 大发888娱乐| 立即博百家乐官网的玩法技巧和规则| 百家乐庄闲和各| 禄丰县| 属兔做生意门面房朝向| 大发888| 巴黎人百家乐官网的玩法技巧和规则 | tt百家乐官网的玩法技巧和规则 | 微信百家乐官网群二维码| 百家乐官网技巧在那里| 大发888开户送58| 百家乐开发软件| 杭州百家乐官网西园| 邯郸县| 大发888娱乐场下载制度| 百家乐荷官培训| 富二代百家乐官网的玩法技巧和规则 | 新田县| 宾利百家乐现金网| 足球走地| 任你博百家乐现金网| 伊川县| 广州百家乐牌具公司| 百家乐官网心态研究| 百家乐双人操作分析仪| 百家乐官网哪家信誉好| 百家乐稳赢投资法| 平台百家乐官网的区别| 电子百家乐作假| 百家乐官网双倍派彩的娱乐城| 百家乐大钱赢小钱| 百家乐官网换房| 德州扑克发牌规则|