溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

FreeRTOS實時操作系統(tǒng)的任務通知怎么實現(xiàn)

發(fā)布時間:2022-04-08 10:05:23 來源:億速云 閱讀:164 作者:iii 欄目:開發(fā)技術

這篇文章主要介紹“FreeRTOS實時操作系統(tǒng)的任務通知怎么實現(xiàn)”的相關知識,小編通過實際案例向大家展示操作過程,操作方法簡單快捷,實用性強,希望這篇“FreeRTOS實時操作系統(tǒng)的任務通知怎么實現(xiàn)”文章能幫助大家解決問題。

前言

注:本文介紹任務通知的基礎知識,詳細源碼分析見FreeRTOS進階《FreeRTOS高級篇8---FreeRTOS任務通知分析》

每個RTOS任務都有一個32位的通知值,任務創(chuàng)建時,這個值被初始化為0。RTOS任務通知相當于直接向任務發(fā)送一個事件,接收到通知的任務可以解除阻塞狀態(tài),前提是這個阻塞事件是因等待通知而引起的。發(fā)送通知的同時,也可以可選的改變接收任務的通知值。

可以通過下列方法向接收任務更新通知:

  • 不覆蓋接收任務的通知值

  • 覆蓋接收任務的通知值

  • 設置接收任務通知值的某些位

  • 增加接收任務的通知值

相對于用前必須分別創(chuàng)建隊列、二進制信號量、計數(shù)信號量或事件組的情況,使用任務通知顯然更靈活。更好的是,相比于使用信號量解除任務阻塞,使用任務通知可以快45%、使用更少的RAM(使用GCC編譯器,-o2優(yōu)化級別)。

使用API函數(shù)xTaskNotify()和xTaskNotifyGive()(中斷保護等價函數(shù)為xTaskNotifyFromISR()和vTaskNotifyGiveFromISR())發(fā)送通知,在接收RTOS任務調用API函數(shù)xTaskNotifyWait()或ulTaskNotifyTake()之前,這個通知都被保持著。如果接收RTOS任務已經因為等待通知而進入阻塞狀態(tài),則接收到通知后任務解除阻塞并清除通知。

RTOS任務通知功能默認是使能的,可以通過在文件FreeRTOSConfig.h中設置宏configUSE_TASK_NOTIFICATIONS為0來禁止這個功能,禁止后每個任務節(jié)省8字節(jié)內存。

雖然RTOS任務通知速度更快并且占用內存更少,但它也有一些限制:

只能有一個任務接收通知事件。

接收通知的任務可以因為等待通知而進入阻塞狀態(tài),但是發(fā)送通知的任務即便不能立即完成通知發(fā)送也不能進入阻塞狀態(tài)。

1.發(fā)送通知-方法1

1.1函數(shù)描述

         BaseType_t xTaskNotify( TaskHandle_txTaskToNotify,
                         uint32_t ulValue,
                         eNotifyAction eAction);

向指定任務發(fā)送指定的通知值。如果打算使用RTOS任務通知實現(xiàn)輕量級的二進制或計數(shù)信號量,推薦使用API函數(shù)xTaskNotifyGive()來代替本函數(shù)。

此函數(shù)不可以在中斷服務例程中調用,中斷保護等價函數(shù)為xTaskNotifyFromISR()。

1.2參數(shù)描述

xTaskToNotify:被通知的任務句柄。

ulValue:通知更新值eAction:枚舉類型,指明更新通知值的方法

枚舉變量成員以及作用如下表所示。

FreeRTOS實時操作系統(tǒng)的任務通知怎么實現(xiàn)

1.3返回值

參數(shù)eAction為eSetValueWithoutOverwrite時,如果被通知任務還沒取走上一個通知,又接收到了一個通知,則這次通知值未能更新并返回pdFALSE,否則返回pdPASS。

2.發(fā)送通知-方法2

2.1函數(shù)描述

BaseType_t xTaskNotifyGive(TaskHandle_t xTaskToNotify );

其實這是一個宏,本質上相當于xTaskNotify( ( xTaskToNotify ), ( 0 ), eIncrement )??梢允褂迷揂PI函數(shù)代替二進制或計數(shù)信號量,但速度更快。在這種情況下,應該使用API函數(shù)ulTaskNotifyTake()來等待通知,而不應該使用API函數(shù)xTaskNotifyWait()。

此函數(shù)不可以在中斷服務例程中調用,中斷保護等價函數(shù)為vTaskNotifyGiveFromISR()。

2.2參數(shù)描述

xTaskToNotify:被通知的任務句柄。

2.3用法舉例

staticvoid prvTask1( void *pvParameters );
staticvoid prvTask2( void *pvParameters );
/* 保存任務句柄 */
staticTaskHandle_t xTask1 = NULL, xTask2 = NULL;
/* 創(chuàng)建兩個任務,它們之間反復發(fā)送通知,啟動RTOS調度器*/
voidmain( void )
{
    xTaskCreate( prvTask1, "Task1",200, NULL, tskIDLE_PRIORITY, &xTask1 );
    xTaskCreate( prvTask2, "Task2",200, NULL, tskIDLE_PRIORITY, &xTask2 );
    vTaskStartScheduler();
}
/*-----------------------------------------------------------*/
staticvoid prvTask1( void *pvParameters )
{
    for( ;; )
    {
        /*向prvTask2(),發(fā)送通知,使其解除阻塞狀態(tài) */
        xTaskNotifyGive( xTask2 );
 
        /* 等待prvTask2()的通知,進入阻塞 */
        ulTaskNotifyTake( pdTRUE, portMAX_DELAY);
    }
}
/*-----------------------------------------------------------*/
staticvoid prvTask2( void *pvParameters )
{
    for( ;; )
    {
        /* 等待prvTask1()的通知,進入阻塞 */
        ulTaskNotifyTake( pdTRUE, portMAX_DELAY);
        /*向prvTask1(),發(fā)送通知,使其解除阻塞狀態(tài) */
        xTaskNotifyGive( xTask1 );
    }
}

3.獲取通知

3.1函數(shù)描述

         uint32_t ulTaskNotifyTake( BaseType_txClearCountOnExit,
                            TickType_txTicksToWait );

ulTaskNotifyTake()是專門為使用更輕量級更快的方法來代替二進制或計數(shù)信號量而量身打造的。FreeRTOS獲取信號量的API函數(shù)為xSemaphoreTake(),可以使用ulTaskNotifyTake()函數(shù)等價代替。

當一個任務使用通知值來實現(xiàn)二進制或計數(shù)信號量時,其它任務或者中斷要使用API函數(shù)xTaskNotifyGive()或者使用參數(shù)eAction為eIncrement的API函數(shù)xTaskNotify()。推薦使用xTaskNotifyGive()函數(shù)(其實是個宏,我們這里把它看作一個API函數(shù))。另外需要注意的是,如果在中斷中使用,要使用它們的中斷保護等價函數(shù):vTaskNotifyGiveFromISR()和xTaskNotifyFromISR()。

API函數(shù)xTaskNotifyTake()有兩種方法處理任務的通知值,一種方法是在函數(shù)退出時將通知值清零,這種方法適用于實現(xiàn)二進制信號量;另外一種方法是在函數(shù)退出時將通知值減1,這種方法適用于實現(xiàn)計數(shù)信號量。

如果RTOS任務的通知值為0,使用xTaskNotifyTake()可以可選的使任務進入阻塞狀態(tài),直到該任務的通知值不為0。進入阻塞的任務不消耗CPU時間。

3.2參數(shù)描述

xClearCountOnExit:如果該參數(shù)設置為pdFALSE,則API函數(shù)xTaskNotifyTake()退出前,將任務的通知值減1;如果該參數(shù)設置為pdTRUE,則API函數(shù)xTaskNotifyTake()退出前,將任務通知值清零。

xTicksToWait:因等待通知而進入阻塞狀態(tài)的最大時間。時間單位為系統(tǒng)節(jié)拍周期。宏pdMS_TO_TICKS用于將指定的毫秒時間轉化為相應的系統(tǒng)節(jié)拍數(shù)。

3.3返回值

返回任務的當前通知值,為0或者為調用API函數(shù)xTaskNotifyTake()之前的通知值減1。

3.4用法舉例

/* 中斷處理程序。*/
voidvANInterruptHandler( void )
{
BaseType_txHigherPriorityTaskWoken;
    prvClearInterruptSource();
     /* xHigherPriorityTaskWoken必須被初始化為pdFALSE。如果調用vTaskNotifyGiveFromISR()會解除vHandlingTask任務的阻塞狀態(tài),并且vHandlingTask任務的優(yōu)先級高于當前處于運行狀態(tài)的任務,則xHigherPriorityTaskWoken將會自動被設置為pdTRUE。*/
    xHigherPriorityTaskWoken = pdFALSE;
    /*向一個任務發(fā)送通知,xHandlingTask是該任務的句柄。*/
    vTaskNotifyGiveFromISR( xHandlingTask,&xHigherPriorityTaskWoken );
    /* 如果xHigherPriorityTaskWoken為pdTRUE,則強制上下文切換。這個宏的實現(xiàn)取決于移植層,可能會調用portEND_SWITCHING_ISR */
    portYIELD_FROM_ISR(xHigherPriorityTaskWoken );
}
/*---------------------------------------------------------------------------------------------------*/
/* 一個因為等待通知而阻塞的任務。*/
voidvHandlingTask( void *pvParameters )
{
BaseType_txEvent;
    for( ;; )
    {
        /*等待通知,無限期阻塞。參數(shù)pdTRUE表示函數(shù)退出前會清零通知值。這顯然是用于替代二進制信號量的用法。需要注意的是,真實的程序一般不會無限期阻塞。*/
        ulTaskNotifyTake( pdTRUE, portMAX_DELAY);
        /* 當處理完所有事件后,仍然等待下一個通知*/
        do
        {
            xEvent = xQueryPeripheral();
            if( xEvent != NO_MORE_EVENTS )
            {
                vProcessPeripheralEvent( xEvent);
            }
        } while( xEvent != NO_MORE_EVENTS );
    }
}

4.等待通知

4.1函數(shù)描述

         BaseType_t xTaskNotifyWait( uint32_tulBitsToClearOnEntry,
                             uint32_tulBitsToClearOnExit,
                             uint32_t*pulNotificationValue,
                             TickType_txTicksToWait );

如果打算使用RTOS任務通知實現(xiàn)輕量級的二進制或計數(shù)信號量,推薦使用API函數(shù)ulTaskNotifyTake()來代替本函數(shù)。

4.2參數(shù)描述

ulBitsToClearOnEntry:在使用通知之前,先將任務的通知值與參數(shù)ulBitsToClearOnEntry的按位取反值按位與操作。設置參數(shù)ulBitsToClearOnEntry為0xFFFFFFFF(ULONG_MAX),表示清零任務通知值。

ulBitsToClearOnExit:在函數(shù)xTaskNotifyWait()退出前,將任務的通知值與參數(shù)ulBitsToClearOnExit的按位取反值按位與操作。

設置參數(shù)ulBitsToClearOnExit為0xFFFFFFFF(ULONG_MAX),表示清零任務通知值。

pulNotificationValue:用于向外回傳任務的通知值。這個通知值在參數(shù)ulBitsToClearOnExit起作用前將通知值拷貝到*pulNotificationValue中。如果不需要返回任務的通知值,這里設置成NULL。

xTicksToWait:因等待通知而進入阻塞狀態(tài)的最大時間。時間單位為系統(tǒng)節(jié)拍周期。宏pdMS_TO_TICKS用于將指定的毫秒時間轉化為相應的系統(tǒng)節(jié)拍數(shù)。

4.3返回值

如果接收到通知,返回pdTRUE,如果API函數(shù)xTaskNotifyWait()等待超時,返回pdFALSE。

4.4用法舉例

/*這個任務使用任務通知值的位來傳遞不同的事件,這在某些情況下可以代替事件組。*/
voidvAnEventProcessingTask( void *pvParameters )
{
uint32_tulNotifiedValue;
    for( ;; )
    {
        /*等待通知,無限期阻塞(沒有超時,所以不用檢查函數(shù)返回值)。其它任務或者中斷設置的通知值中的不同位表示不同的事件。參數(shù)0x00表示使用通知前不清除任務的通知值位,參數(shù)ULONG_MAX 表示函數(shù)xTaskNotifyWait()退出前將任務通知值設置為0*/
        xTaskNotifyWait( 0x00, ULONG_MAX,&ulNotifiedValue, portMAX_DELAY );
 
        /*根據(jù)通知值處理事件*/
        if( ( ulNotifiedValue & 0x01 ) != 0)
        {
            prvProcessBit0Event();
        }
        if( ( ulNotifiedValue & 0x02 ) != 0)
        {
            prvProcessBit1Event();
        }
        if( ( ulNotifiedValue & 0x04 ) != 0)
        {
            prvProcessBit2Event();
        }
        /* ……*/
    }
}

5.任務通知并查詢

5.1函數(shù)描述

         BaseType_t xTaskNotifyAndQuery(TaskHandle_t xTaskToNotify,
                                 uint32_tulValue,
                                 eNotifyActioneAction,
                                 uint32_t*pulPreviousNotifyValue );

此函數(shù)與任務通知API函數(shù)xTaskNotify()非常像,只不過此函數(shù)具有一個附加參數(shù),用來回傳任務當前的通知值,然后根據(jù)參數(shù)ulValue和eAction更新任務的通知值。

此函數(shù)不能在中斷服務例程中使用,在中斷服務例程中使用xTaskNotifyAndQueryFromISR()函數(shù)。

5.2參數(shù)描述

xTaskToNotify:被通知的任務句柄。

ulValue:通知更新值

eAction:枚舉類型,指明更新通知值的方法,枚舉變量成員以及作用見xTaskNotify()一節(jié)。

pulPreviousNotifyValue:回傳未被更新的任務通知值。如果不需要回傳未被更新的任務通知值,這里設置為NULL,這樣就等價于調用xTaskNotify()函數(shù)。

5.3返回值

參數(shù)eAction為eSetValueWithoutOverwrite時,如果被通知任務還沒取走上一個通知,又接收到了一個通知,則這次通知值未能更新并返回pdFALSE,否則返回pdPASS。

關于“FreeRTOS實時操作系統(tǒng)的任務通知怎么實現(xiàn)”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關的知識,可以關注億速云行業(yè)資訊頻道,小編每天都會為大家更新不同的知識點。

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng)、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經查實,將立刻刪除涉嫌侵權內容。

AI