本文章總結基於官方FreeRTOS手冊,測試系統為ESP32的IDF 4.0
本篇續上一篇《不可被忽視的操作系統( FreeRTOS )【1】》
其中上一篇主要內容為:
- FreeRTOS介紹
- FreeRTOS在ESP32中的特殊性
- 任務相關函數
- 隊列相關函數
本篇內容主要有:
- 信號量相關函數
- 計時器相關函數
- 事件組相關函數
- 任務通知相關函數
信號量
reertos / include / freertos / semphr.h
信號量是操作系統中重要的一部分,信號量一般用來進行資源管理和任務同步, FreeRTOS中信號量又分為
l 二值信號量、
l 計數型信號量、
l 互斥信號量、
l 遞歸互斥信號量
不同的信號量其應用場景不同,但有些應用場景是可以互換着使用的
創建二值信號量
創建一個新的二進制信號量(二值信號量)實例,並返回一個句柄,通過該句柄可以引用新的信號量。
通過使用現有隊列機制創建信號量的函數。隊列長度為1,因為它是二進制信號量。數據大小為0,因為實際上沒有任何存儲-重要的是隊列是否為空或已滿(二進制信號量是否可用)。
這種信號量可用於任務之間或中斷與任務之間的純同步。信號量不必一經獲得就退還,因此一個任務/中斷可以連續地“提供”該信號量,而另一任務/中斷則可以連續地“獲取”該信號量。因此,這種信號量不使用優先級繼承機制。有關不使用優先級繼承的替代方法,請參見xSemaphoreCreateMutex()。
東小東使用說明:
二值信號量即可以實現事件的計數,通過xSemaphoreGive()相關函數釋放信號量也就是將計數值加一,當前其最大值為1,通過xSemaphoreTake()相關函數獲取信號量也就是將計數值減一,當xSemaphoreTake()最終將計數值減到0時,將會觸發xSemaphoreTake()參數的超時等待。
SemaphoreHandle_t xSemaphoreCreateBinary ()
創建計數型信號量
創建一個新的計數信號量實例,並返回一個句柄,通過該句柄可以引用新的計數信號量。
計數信號量通常用於兩件事:
1)計數事件。
在這種使用情況下,事件處理程序將在每次事件發生時“給出”信號量(增加信號量計數值),而處理程序任務將在每次處理事件時“獲得”信號量(減少信號量計數值)。因此,計數值是已發生的事件數與已處理的事件數之間的差。在這種情況下,期望初始計數值為零。
2)資源管理。
在這種使用情況下,計數值指示可用資源的數量。為了獲得對資源的控制,任務必須首先獲得一個信號量-減少信號量計數值。當計數值達到零時,將沒有可用資源。當任務使用資源完成時,它將“給予”信號量-增加信號量計數值。在這種情況下,期望初始計數值等於最大計數值,指示所有資源都是空閑的。
東小東使用說明:
計數型信號量即可以實現事件的計數,通過xSemaphoreGive()相關函數釋放信號量也就是將計數值加一,其最大值為創建時設置的uxMaxCount,通過xSemaphoreTake()相關函數獲取信號量也就是將計數值減一,當xSemaphoreTake()最終將計數值減到0時,將會觸發xSemaphoreTake()參數的超時等待。
參數:
uxMaxCount:可以達到的最大計數值。當信號量達到此值時,就不能再“給予”它了。
uxInitialCount:初值,創建信號時分配給信號量的計數值
返回:
計數型信號量句柄,失敗則返回null
SemaphoreHandle_t xSemaphoreCreateCounting( uxMaxCount,uxInitialCount )
獲取計數型信號量的當前計數值
如果該信號量是一個計數信號量,則uxSemaphoreGetCount()返回其當前計數值。如果該信號量是二進制信號量,那么如果該信號量可用,則uxSemaphoreGetCount()返回1;如果該信號量不可用,則返回0。
參數:信號量句柄
UBaseType_t uxSemaphoreGetCount( xSemaphore )
獲取信號量
作用於二值信號量、計數型信號量、互斥信號量
宏獲取信號量。信號量必須事先通過調用vSemaphoreCreateBinary(),xSemaphoreCreateMutex()或xSemaphoreCreateCounting()來創建
通過xSemaphoreGive釋放后才有效,才能獲取為pdTRUE
參數:
xSemaphore:獲取信號量的句柄-創建信號量時獲得。
xBlockTime:等待信號量可用的時間(以毫秒為單位)。宏端口TICK_PERIOD_MS可用於將其轉換為實時。零的阻止時間可用於輪詢信號量。portMAX_DELAY的阻塞時間可以無限期地阻塞(在FreeRTOSConfig.h中將INCLUDE_vTaskSuspend設置為1)。
返回
如果獲得了信號量,則為pdTRUE。如果xBlockTime到期而信號燈不可用,則為pdFALSE。
BaseType_t xSemaphoreTake( xSemaphore,xBlockTime )
中斷服務函數中獲取信號量
作用於二值信號量、計數型信號量、互斥信號量
用於從ISR獲取信號量的宏。信號量必須事先通過調用vSemaphoreCreateBinary()或xSemaphoreCreateCounting()來創建。
互斥類型信號量(通過調用xSemaphoreCreateMutex()創建的信號量)不得與此宏一起使用。
可以從ISR使用此宏,但是從ISR獲取信號量並不常見。僅當中斷從資源池中獲取對象時(當信號量指示可用資源的數量時),才使用計數信號量。
參數:
xSemaphore:正在使用的信號量的句柄。這是創建信號量時返回的句柄。
pxHigherPriorityTaskWoken:如果采用信號量導致任務取消阻止,並且未阻止任務的優先級高於當前運行的任務,則xSemaphoreTakeFromISR()會將* pxHigherPriorityTaskWoken設置為pdTRUE。如果xSemaphoreTakeFromISR()將此值設置為pdTRUE,則應在退出中斷之前請求上下文切換。
返回
如果成功獲取了信號,則為pdTRUE,否則為pdFALSE
BaseType_t xSemaphoreTakeFromISR( xSemaphore,pxHigherPriorityTaskWoken )
釋放信號量
作用於二值信號量、計數型信號量、互斥信號量
釋放信號量的宏。信號量必須事先通過調用vSemaphoreCreateBinary(),xSemaphoreCreateMutex()或xSemaphoreCreateCounting()來創建。並使用sSemaphoreTake()獲得。
不得從ISR使用此宏。有關可以從ISR使用的替代方法,請參見xSemaphoreGiveFromISR()。
此宏也不得用於使用xSemaphoreCreateRecursiveMutex()創建的信號量。
參數:
xSemaphore:釋放信號量的句柄。這是創建信號量時返回的句柄。
返回:
如果已釋放信號,則為pdTRUE。如果發生錯誤,則為pdFALSE。信號量是使用隊列實現的。如果隊列上沒有空間可發布消息,則可能會發生錯誤-指示未正確正確獲取信號量。
BaseType_t xSemaphoreGive( xSemaphore)
中斷服務函數中釋放信號量
作用於二值信號量、計數型信號量、互斥信號量
釋放信號量的宏。信號量必須事先通過調用vSemaphoreCreateBinary()或xSemaphoreCreateCounting()來創建。
互斥類型信號量(通過調用xSemaphoreCreateMutex()創建的信號量)不得與此宏一起使用。
可以從ISR使用此宏。
參量
xSemaphore:釋放信號量的句柄。這是創建信號量時返回的句柄。
pxHigherPriorityTaskWoken:如果提供信號量導致任務取消阻止,並且未阻止的任務的優先級高於當前運行的任務,則xSemaphoreGiveFromISR()會將* pxHigherPriorityTaskWoken設置為pdTRUE。如果xSemaphoreGiveFromISR()將此值設置為pdTRUE,則應在退出中斷之前請求上下文切換。
返回
如果成功提供了信號量,則為pdTRUE,否則為errQUEUE_FULL。
BaseType_t xSemaphoreGiveFromISR( xSemaphore,pxHigherPriorityTaskWoken )
小試牛刀之二值信號量任務同步測試
輸出效果為3S間隔輸出兩條,分別為1條釋放,1條獲取,實現任務間的運行同步
必須先釋放才能獲取
1 #include <stdio.h> 2 #include "freertos/FreeRTOS.h"//freertos相關 3 #include "freertos/task.h" 4 #include "freertos/semphr.h" 5 //二值信號量句柄 6 SemaphoreHandle_t xSemaphore = NULL; 7 8 //創建二值信號量來保護共享資源。 9 void dong_creat_binary() 10 { 11 //調用創建函數,二進制值信號量 12 xSemaphore = xSemaphoreCreateBinary (); 13 if(xSemaphore != NULL) 14 { 15 printf("信號量 xSemaphore 創建成功了"); 16 } 17 } 18 //任務0處理函數 19 void Task_Run_0(){ 20 uint32_t num=0; 21 while(1){ 22 num++; 23 //死等獲取二值信號量 24 xSemaphoreTake(xSemaphore,portMAX_DELAY); 25 printf("【task 0】二值信號量獲取成功啦,觸發次數:%d\r\n",num); 26 } 27 } 28 //主函數,優先級為1 29 void app_main() 30 { 31 printf("\r\n--------------DONGIXAODONG FreeRTOS-----------------\r\n"); 32 //創建二值信號量 33 dong_creat_binary(); 34 35 //啟動任務0,簡化 36 //函數,名字,字節大小,參數,優先級[0,16](16最優先),任務句柄 37 BaseType_t t0res=xTaskCreate(Task_Run_0,"DONG Task_Run_0",1024*2,NULL,7,NULL); 38 if(t0res==pdPASS){ 39 printf("任務0啟動成功....\r\n"); 40 } 41 while(1){ 42 vTaskDelay(3000 / portTICK_PERIOD_MS);//延時3S 43 xSemaphoreGive(xSemaphore); 44 printf("【main】釋放一次二值信號量,獲取將立即執行一次\r\n"); 45 } 46 }
小試牛刀之二值信號量任務共享資源保護
測試公共資源訪問
測試可見,公共資源在什么任務里開始,必須在當前任務里接收后才能被其它任務開始,起到資源保護作用
1 #include <stdio.h> 2 #include "freertos/FreeRTOS.h"//freertos相關 3 #include "freertos/task.h" 4 #include "freertos/semphr.h" 5 6 //二值信號量句柄 7 SemaphoreHandle_t xSemaphore = NULL; 8 9 //創建二值信號量來保護共享資源。 10 void dong_creat_binary() 11 { 12 //調用創建函數,二進制值信號量 13 xSemaphore = xSemaphoreCreateBinary (); 14 if(xSemaphore != NULL) 15 { 16 printf("信號量 xSemaphore 創建成功了"); 17 } 18 } 19 //任務0處理函數 20 void Task_Run_0(){ 21 while(1){ 22 //延時3S,延時的時候將會使得低優先級main獲取CPU 23 vTaskDelay(3000 / portTICK_PERIOD_MS); 24 printf("【task 0】開始信號量等待---\r\n"); 25 //死等獲取二值信號量 26 xSemaphoreTake(xSemaphore,portMAX_DELAY); 27 printf("【task 0】*****公共資源開始*****-----\r\n"); 28 vTaskDelay(6000 / portTICK_PERIOD_MS); 29 printf("【task 0】*****公共資源結束*****------\r\n"); 30 xSemaphoreGive(xSemaphore);//釋放信號量 31 printf("【task 0】結束信號量等待---\r\n"); 32 taskYIELD();//在超時之處盡量調用任務切換檢查 33 } 34 } 35 //主函數,優先級為1 36 void app_main() 37 { 38 printf("\r\n--------------DONGIXAODONG FreeRTOS-----------------\r\n"); 39 //創建二值信號量 40 dong_creat_binary(); 41 xSemaphoreGive(xSemaphore);//釋放信號量,剛啟動是必須釋放一次才能獲取 42 //啟動任務0,簡化 43 //函數,名字,字節大小,參數,優先級[0,16](16最優先),任務句柄 44 BaseType_t t0res=xTaskCreate(Task_Run_0,"DONG Task_Run_0",1024*2,NULL,7,NULL); 45 if(t0res==pdPASS){ 46 printf("任務0啟動成功....\r\n"); 47 } 48 while(1){ 49 printf("【main】開始信號量等待//////\r\n"); 50 //死等獲取二值信號量 51 xSemaphoreTake(xSemaphore,portMAX_DELAY); 52 printf("【main】*****公共資源開始*****//////\r\n"); 53 vTaskDelay(6000 / portTICK_PERIOD_MS); 54 printf("【main】*****公共資源結束*****//////\r\n"); 55 xSemaphoreGive(xSemaphore);//釋放信號量 56 printf("【main】結束信號量等待//////\r\n"); 57 } 58 }
計時器
freertos / include / freertos / timers.h
相關的一些宏
#define configUSE_TIMERS 1 #define configTIMER_TASK_PRIORITY 1 #define configTIMER_QUEUE_LENGTH 10 #define configTIMER_TASK_STACK_DEPTH 2048 第一個:表示是否啟動計時器 第二個:表示計時器任務的優先級 第三個:表示計時器隊列長度 第四個:定時器堆棧,2048個字節
硬件定時器
CPU內部自帶的定時器模塊,通過初始化、配置可以實現定時,定時時間到以后就會執行相應的定時器中斷處理函數。硬件定時器一般都帶有其它功能,比如PWM輸出、輸入捕獲等等功能。但是缺點是硬件定時器數量少!
軟件定時器
軟件定時器允許設置一段時間,當設置的時間到達之后就執行指定的功能函數,被定時器調用的這個功能函數叫做定時器的回調函數。回調函數的兩次執行間隔叫做定時器的定時周期,簡而言之,當定時器的定時周期到了以后就會執行回調函數。
創建計時器實例
創建一個新的軟件計時器實例,並返回一個句柄,通過該句柄可以引用創建的軟件計時器。
在FreeRTOS的內部實現中,軟件計時器使用一塊內存,其中存儲着計時器數據結構。如果使用xTimerCreate()創建軟件計時器,則所需的內存將自動在xTimerCreate()函數內部動態分配。
創建后計時器處於休眠狀態。xTimerStart(),xTimerReset(),xTimerStartFromISR(),xTimerResetFromISR(),xTimerChangePeriod()和xTimerChangePeriodFromISR()API函數均可用於將計時器轉換為活動狀態。
參數
pcTimerName:分配給計時器的文本名稱。這樣做純粹是為了協助調試。內核本身僅通過其句柄引用計時器,而從未通過其名稱引用計時器。
xTimerPeriodInTicks:計時器時間段。時間以滴答周期定義,因此常數portTICK_PERIOD_MS可用於轉換以毫秒為單位指定的時間。例如,如果計時器必須在100個滴答之后過期,則xTimerPeriodInTicks應該設置為100。或者,如果計時器必須在500ms之后過期,則可以將xPeriod設置為(500 / portTICK_PERIOD_MS),前提是configTICK_RATE_HZ小於或等於1000。
uxAutoReload:如果將uxAutoReload設置為pdTRUE,則計時器將以xTimerPeriodInTicks參數設置的頻率重復終止。如果將uxAutoReload設置為pdFALSE,則該計時器將是單次計時器,並在其到期后進入休眠狀態。
pvTimerID:分配給正在創建的計時器的標識符。通常,在將同一回調函數分配給多個計時器時,將在計時器回調函數中使用它來標識哪個計時器到期。
pxCallbackFunction:計時器到期時要調用的函數。回調函數必須具有由TimerCallbackFunction_t定義的原型,即“ void vCallbackFunction(TimerHandle_t xTimer);”。
TimerHandle_t xTimerCreate(const char * const pcTimerName,const TickType_t xTimerPeriodInTicks,const UBaseType_t uxAutoReload,void * const pvTimerID,TimerCallbackFunction_t pxCallbackFunction )
獲取計時器的ID
使用用於創建計時器的xTimerCreated()調用的pvTimerID參數將ID分配給計時器。
如果將同一個回調函數分配給多個計時器,則可以在回調函數中使用計時器ID來標識實際終止了哪個計時器。
參量
xTimer:計時器句柄
返回
查詢的計時器的ID
void *pvTimerGetTimerID( const TimerHandle_t xTimer )
設置計時器ID
設置分配給計時器的ID。
使用用於創建計時器的xTimerCreated()調用的pvTimerID參數將ID分配給計時器。
如果將相同的回調函數分配給多個計時器,則計時器ID可用作特定時間(本地計時器)的存儲。
參量
xTimer:計時器句柄
pvNewID:分配給計時器的ID。
void vTimerSetTimerID( TimerHandle_t xTimer, void *pvNewID )
啟動計時器
必須將configUSE_TIMERS配置常量設置為1,xTimerStart()才可用。
xTimerStart()啟動一個計時器,該計時器先前是使用xTimerCreate()API函數創建的。如果計時器已經啟動並且已經處於活動狀態,則xTimerStart()具有與xTimerReset()API函數等效的功能。
啟動計時器可確保計時器處於活動狀態。如果同時沒有停止,刪除或重置計時器,則在調用xTimerStart()之后,與計時器關聯的回調函數將被稱為“ n”滴答,其中“ n”是計時器定義的時間段。
在啟動調度程序之前調用xTimerStart()是有效的,但是完成此操作后,計時器將不會真正啟動,直到啟動調度程序為止,並且計時器的到期時間將與啟動調度程序有關,而不是與啟動調度程序有關當xTimerStart()被調用時。
參量
xTimer:正在啟動/重新啟動的計時器的句柄。
xTicksToWait:指定在調用xTimerStart()時,如果隊列已滿,則調用任務應保持在Blocked狀態的時間,以等待啟動命令成功發送到計時器命令隊列的時間(以秒為單位)。如果在調度程序啟動之前調用了xTimerStart(),則xTicksToWait將被忽略,該參數的值請參考隊列
返回
如果即使經過xTicksToWait滴答聲后仍無法將啟動命令發送到計時器命令隊列,則將返回pdFAIL。如果命令已成功發送到計時器命令隊列,則將返回pdPASS。實際處理命令的時間將取決於計時器服務/守護程序任務相對於系統中其他任務的優先級,盡管計時器的到期時間與實際調用xTimerStart()有關。計時器服務/守護程序任務優先級由configTIMER_TASK_PRIORITY配置常量設置。
BaseType_t xTimerStart( xTimer, xTicksToWait )
停止計時器
必須將configUSE_TIMERS配置常量設置為1,xTimerStop()才可用。
xTimerStop()停止使用xTimerStart(),xTimerReset(),xTimerStartFromISR(),xTimerResetFromISR(),xTimerChangePeriod()或xTimerChangePeriodFromISR()API函數之一啟動的計時器。
停止計時器可確保計時器未處於活動狀態。
參量
xTimer:定時器的句柄正在停止。
xTicksToWait:指定在調用xTimerStop()時,如果隊列已滿,則調用任務應保持在Blocked狀態的時間,以等待stop命令成功發送到計時器命令隊列。如果在調度程序啟動之前調用了xTimerStop(),則xTicksToWait將被忽略。
返回
如果即使經過xTicksToWait滴答聲也無法將stop命令發送到計時器命令隊列,則將返回pdFAIL。如果命令已成功發送到計時器命令隊列,則將返回pdPASS。實際處理命令的時間將取決於計時器服務/守護程序任務相對於系統中其他任務的優先級。計時器服務/守護程序任務優先級由configTIMER_TASK_PRIORITY配置常量設置。該參數的值請參考隊列
BaseType_t xTimerStop( xTimer,xTicksToWait )
重置計時器
必須將configUSE_TIMERS配置常量設置為1,xTimerReset()才可用
xTimerReset()重新啟動以前使用xTimerCreate()API函數創建的計時器。如果計時器已經啟動並且已經處於活動狀態,則xTimerReset()將使計時器重新評估其到期時間,以使其與調用xTimerReset()的時間有關。如果計時器處於休眠狀態,則xTimerReset()具有與xTimerStart()API函數等效的功能。
重置計時器可確保計時器處於活動狀態。如果同時沒有停止,刪除或重置計時器,則在調用xTimerReset()之后,與計時器關聯的回調函數將被稱為“ n”滴答,其中“ n”是計時器定義的時間段。
在啟動調度程序之前調用xTimerReset()是有效的,但是完成此操作后,計時器將不會真正啟動,直到啟動調度程序為止,並且計時器的到期時間將與啟動調度程序的時間有關,而不是相對於啟動調度程序的時間當xTimerReset()被調用時。
參數:
xTimer:正在重置/啟動/重新啟動的計時器的句柄。
xTicksToWait:指定在調用xTimerReset()時,如果隊列已滿,則調用任務應保持在Blocked狀態的時間,以等待重置命令成功發送到計時器命令隊列的時間(以秒為單位)。如果在調度程序啟動之前調用了xTimerReset(),則xTicksToWait將被忽略。
返回
如果即使經過xTicksToWait滴答聲后仍無法將重置命令發送到計時器命令隊列,則將返回pdFAIL。如果命令已成功發送到計時器命令隊列,則將返回pdPASS。實際處理命令的時間將取決於計時器服務/守護程序任務相對於系統中其他任務的優先級,盡管計時器的到期時間與實際調用xTimerStart()有關。計時器服務/守護程序任務優先級由configTIMER_TASK_PRIORITY配置常量設置。
BaseType_t xTimerReset( xTimer,xTicksToWait )
刪除計時器
必須將configUSE_TIMERS配置常量設置為1,xTimerDelete()才可用。
xTimerDelete()刪除以前使用xTimerCreate()API函數創建的計時器。
參量
xTimer:定時器的句柄被刪除。
xTicksToWait:指定在調用xTimerDelete()時,如果隊列已滿,則調用任務應保持在Blocked狀態的時間,以等待刪除命令成功發送到計時器命令隊列。如果在啟動調度程序之前調用了xTimerDelete(),則xTicksToWait將被忽略。
返回
如果即使經過xTicksToWait滴答聲后仍無法將刪除命令發送到計時器命令隊列,則將返回pdFAIL。如果命令已成功發送到計時器命令隊列,則將返回pdPASS。實際處理命令的時間將取決於計時器服務/守護程序任務相對於系統中其他任務的優先級。計時器服務/守護程序任務優先級由configTIMER_TASK_PRIORITY配置常量設置
BaseType_t xTimerDelete( xTimer,xTicksToWait )
查看計時器的狀態
計時器處於休眠狀態。xTimerStart(),xTimerReset(),xTimerStartFromISR(),xTimerResetFromISR(),xTimerChangePeriod()和xTimerChangePeriodFromISR()API函數均可用於將計時器轉換為活動狀態。
參量
xTimer:計時器句柄
返回
如果計時器處於休眠狀態,則將返回pdFALSE。如果計時器處於活動狀態,則將返回pdFALSE以外的值。
BaseType_t xTimerIsTimerActive(TimerHandle_t xTimer )
更改計時器周期
必須將configUSE_TIMERS配置常量設置為1,xTimerChangePeriod()才可用
xTimerChangePeriod()更改以前使用xTimerCreate()API函數創建的計時器的周期。
可以調用xTimerChangePeriod()來更改活動或休眠狀態計時器的周期。
參數
xTimer:正在更改其周期的計時器的句柄。
xNewPeriod:xTimer的新時期。計時器周期以滴答周期指定,因此常數portTICK_PERIOD_MS可用於轉換以毫秒為單位指定的時間。例如,如果計時器必須在100個滴答之后過期,則xNewPeriod應該設置為100。或者,如果計時器必須在500ms之后過期,那么可以將xNewPeriod設置為(500 / portTICK_PERIOD_MS),前提是configTICK_RATE_HZ小於或等於1000。 。
xTicksToWait:指定在調用xTimerChangePeriod()時隊列已滿的情況下,調用任務應保持在“阻塞”狀態,等待更改周期命令成功發送到計時器命令隊列的時間(以滴答為單位)。如果在調度程序啟動之前調用了xTimerChangePeriod(),則xTicksToWait將被忽略。
返回
如果即使經過xTicksToWait滴答聲之后仍無法將更改周期命令發送到計時器命令隊列,則將返回pdFAIL。如果命令已成功發送到計時器命令隊列,則將返回pdPASS。實際處理命令的時間將取決於計時器服務/守護程序任務相對於系統中其他任務的優先級。計時器服務/守護程序任務優先級由configTIMER_TASK_PRIORITY配置常量設置。
BaseType_t xTimerChangePeriod( xTimer,xNewPeriod,xTicksToWait )
獲取定時器周期(嘀嗒數)
參量
xTimer:計時器句柄
返回
計時器的周期,以滴答為單位
TickType_t xTimerGetPeriod(TimerHandle_t xTimer )
獲取定時器周期(秒)
以秒為單位返回計時器將到期的時間。如果小於當前滴答計數,則到期時間從當前時間開始溢出。
參量
xTimer:計時器句柄
返回
如果計時器正在運行,則將返回計時器下一次到期的時間(以秒為單位)。如果計時器未運行,則返回值不確定
TickType_t xTimerGetExpiryTime(TimerHandle_t xTimer )
獲取計時器名稱
返回創建計時器時分配給計時器的名稱。
參量
xTimer:計時器句柄
返回
分配給xTimer參數指定的計時器的名稱
const char * pcTimerGetTimerName(TimerHandle_t xTimer )
計時器啟動/停止/重置對應的中斷函數有
參數
xTimer:正在啟動/重新啟動的計時器的句柄。
pxHigherPriorityTaskWoken:計時器服務/守護程序任務的大部分時間都處於“阻塞”狀態,等待消息到達計時器命令隊列。調用xTimerStartFromISR()會將消息寫入計時器命令隊列,因此有可能將計時器服務/守護程序任務轉換為“已阻止”狀態。如果調用xTimerStartFromISR()導致計時器服務/守護程序任務退出“阻塞”狀態,並且計時器服務/守護程序任務的優先級等於或大於當前正在執行的任務(被中斷的任務),則* pxHigherPriorityTaskWoken將獲得在xTimerStartFromISR()函數內部將其設置為pdTRUE。如果xTimerStartFromISR()將此值設置為pdTRUE,則應在中斷退出之前執行上下文切換。
返回:
如果無法將啟動命令發送到計時器命令隊列,則將返回pdFAIL。如果命令已成功發送到計時器命令隊列,則將返回pdPASS。實際處理命令的時間將取決於計時器服務/守護程序任務相對於系統中其他任務的優先級,盡管計時器的到期時間與實際調用xTimerStartFromISR()的時間有關。計時器服務/守護程序任務優先級由configTIMER_TASK_PRIORITY配置常量設置
啟動計時器
TickType_t xTimerStartFromISR( xTimer,pxHigherPriorityTaskWoken )
停止計時器
TickType_t xTimerStopFromISR( xTimer,pxHigherPriorityTaskWoken )
重置計時器
TickType_t xTimerResetFromISR( xTimer,pxHigherPriorityTaskWoken )
計時器設置周期中斷使用函數
參量
xTimer:正在更改其周期的計時器的句柄。
xNewPeriod:xTimer的新時期。計時器周期以滴答周期指定,因此常數portTICK_PERIOD_MS可用於轉換以毫秒為單位指定的時間。例如,如果計時器必須在100個滴答之后過期,則xNewPeriod應該設置為100。或者,如果計時器必須在500ms之后過期,那么可以將xNewPeriod設置為(500 / portTICK_PERIOD_MS),前提是configTICK_RATE_HZ小於或等於1000。 。
pxHigherPriorityTaskWoken:計時器服務/守護程序任務的大部分時間都處於“阻塞”狀態,等待消息到達計時器命令隊列。調用xTimerChangePeriodFromISR()會將消息寫入計時器命令隊列,因此有可能將計時器服務/守護程序任務從“阻塞”狀態轉換出來。如果調用xTimerChangePeriodFromISR()導致計時器服務/守護程序任務退出“阻塞”狀態,並且計時器服務/守護程序任務的優先級等於或大於當前正在執行的任務(被中斷的任務),則* pxHigherPriorityTaskWoken將獲得在xTimerChangePeriodFromISR()函數內部將其設置為pdTRUE。如果xTimerChangePeriodFromISR()將此值設置為pdTRUE,則應在中斷退出之前執行上下文切換。
返回:
如果無法將更改計時器周期的命令發送到計時器命令隊列,則將返回pdFAIL。如果命令已成功發送到計時器命令隊列,則將返回pdPASS。實際處理命令的時間將取決於計時器服務/守護程序任務相對於系統中其他任務的優先級。計時器服務/守護程序任務優先級由configTIMER_TASK_PRIORITY配置常量設置
TickType_t xTimerChangePeriodFromISR( xTimer,xNewPeriod,pxHigherPriorityTaskWoken )
小試牛刀
1 #include <stdio.h> 2 #include "freertos/FreeRTOS.h"//freertos相關 3 #include "freertos/task.h" 4 #include "freertos/semphr.h" 5 #include "freertos/timers.h" 6 7 //計時器器句柄 8 TimerHandle_t onetimer = NULL; 9 TimerHandle_t cirtimer = NULL; 10 11 //計時器回調函數 12 void oneTimerCallback( TimerHandle_t pxTimer ) 13 { 14 uint32_t timerid=(uint32_t)pvTimerGetTimerID(pxTimer);//獲取ID 15 16 printf("【單次計時任務 onetimer】 回調函數觸發,ID為:%d\r\n",timerid); 17 if( xTimerReset( pxTimer, 100 ) == pdPASS ) 18 { 19 printf("【單次計時任務 onetimer】 重置成功*****\r\n"); 20 } 21 } 22 23 //計時器回調函數 24 void cirTimerCallback( TimerHandle_t pxTimer ) 25 { 26 printf("【循環計時任務 cirtimer】 回調函數觸發\r\n"); 27 28 } 29 30 void dong_create_timer() 31 { 32 //創建一個一次性計時任務 33 onetimer = xTimerCreate("dong_onetimer", // 設置一個名詞,便於調試 34 ( 2000 / portTICK_PERIOD_MS), //定時周期 35 pdFALSE, // pdFALSE為單次,pdTRUE為循環 36 (void *)100, //設置一個ID用於標識 37 oneTimerCallback //回調函數 38 ); 39 if( onetimer != NULL ) 40 { 41 printf("【單次計時任務 onetimer】 創建成功\r\n"); 42 xTimerStart( onetimer, 10 );//開啟計數器 43 } 44 45 //創建一個循環計時任務 46 cirtimer = xTimerCreate("dong_cirtimer", // 設置一個名詞,便於調試 47 ( 4000 / portTICK_PERIOD_MS), //定時周期 48 pdTRUE, // pdFALSE為單次,pdTRUE為循環 49 (void *)11, //設置一個ID用於標識 50 cirTimerCallback //回調函數 51 ); 52 if( cirtimer != NULL ) 53 { 54 printf("【循環計時任務 cirtimer】 創建成功\r\n"); 55 xTimerStart( cirtimer, 10 );//開啟計時器 56 } 57 } 58 59 //主函數,優先級為1 60 void app_main() 61 { 62 printf("\r\n--------------DONGIXAODONG FreeRTOS-----------------\r\n"); 63 64 //創建並開始計時器 65 dong_create_timer(); 66 67 while(1){ 68 //taskYIELD();//任務調度 69 vTaskDelay(10);//還是的用延時函數進行任務調度 70 } 71 }
在上述例程中添加延時函數
1 //計時器回調函數 2 void oneTimerCallback( TimerHandle_t pxTimer ) 3 { 4 uint32_t timerid=(uint32_t)pvTimerGetTimerID(pxTimer);//獲取ID 5 6 printf("【單次計時任務 onetimer】 回調函數觸發,ID為:%d\r\n",timerid); 7 8 printf("【單次計時任務 onetimer】10///秒延時開始啦\r\n"); 9 vTaskDelay(10000 / portTICK_PERIOD_MS); 10 printf("【單次計時任務 onetimer】10///秒延時結束啦\r\n"); 11 12 if( xTimerReset( pxTimer, 100 ) == pdPASS ) 13 { 14 printf("【單次計時任務 onetimer】 重置成功*****\r\n"); 15 } 16 }
輸出:
可見:
延時函數將阻塞定時任務,會影響到其它定時任務功能,所以定時回調函數中操作盡量少
事件組
freertos / include / freertos / event_groups.h
以數據位標志事件
創建事件組
盡管事件組與滴答無關,但出於內部實現的原因,事件組中可使用的位數取決於FreeRTOSConfig.h中的configUSE_16_BIT_TICKS設置。如果configUSE_16_BIT_TICKS為1,則每個事件組包含8個可用位(位0至位7)。如果configUSE_16_BIT_TICKS設置為0,則每個事件組都有24個可用位(位0到位23)。EventBits_t類型用於在事件組中存儲事件位。
返回:事件組句柄,創建失敗為NULL
EventGroupHandle_t xEventGroupCreate()
等待事件位
[可能]阻止等待先前創建的事件組中的一個或多個位設置。
不能從中斷中調用此函數
參數:
xEventGroup:事件組句柄。事件組必須先前已通過調用xEventGroupCreate()創建
uxBitsToWaitFor:按位的值,指示事件組中要測試的一位或多位。例如,要等待位0和/或位2,請將uxBitsToWaitFor設置為0x05。要等待位0和/或位1和/或位2,請將uxBitsToWaitFor設置為0x07。等等
xClearOnExit:如果xClearOnExit設置為pdTRUE,則如果滿足等待條件(如果函數由於超時以外的原因返回),則在xEventGroupWaitBits()返回之前,將清除事件組中設置的uxBitsToWaitFor中的任何位。如果xClearOnExit設置為pdFALSE,則在對xEventGroupWaitBits()的調用返回時,事件組中設置的位不會更改。
xWaitForAllBits:如果xWaitForAllBits設置為pdTRUE,則當uxBitsToWaitFor中的所有位都已設置或指定的塊時間到期時,xEventGroupWaitBits()將返回。如果將xWaitForAllBits設置為pdFALSE,則當設置uxBitsToWaitFor中設置的任何一位或指定的塊時間到期時,xEventGroupWaitBits()將返回。阻止時間由xTicksToWait參數指定
xTicksToWait:等待設置uxBitsToWaitFor指定的位中的一個/全部(取決於xWaitForAllBits值)的最長時間(以“ ticks”指定),與其它設置等待時間一致,可以立即、一段、永遠。
返回
在等待位被置位或塊時間到期時事件組的值。測試返回值以了解設置了哪些位。如果xEventGroupWaitBits()由於其超時到期而返回,則不會設置所有等待的位。如果由於設置了xEventGroupWaitBits()而等待的位而返回,則在xClearOnExit參數設置為pdTRUE的情況下,返回值是在自動清除任何位之前的事件組值。
EventBits_t xEventGroupWaitBits(EventGroupHandle_t xEventGroup,const EventBits_t uxBitsToWaitFor,const BaseType_t xClearOnExit,const BaseType_t xWaitForAllBits,TickType_t xTicksToWait )
獲取事件組中當前值
返回事件組中位的當前值。不能從中斷使用此功能。
參量
xEventGroup:正在查詢的事件組
返回
調用xEventGroupGetBits()時的事件組位
EventBits_t xEventGroupGetBits( xEventGroup )
清除事件組中的位
清除事件組中的位。不能從中斷中調用此函數。
參數:
xEventGroup:事件組句柄,其中的位將被清除
uxBitsToClear:按位表示在事件組中要清除的一個或多個位。例如,僅清除位3,將uxBitsToClear設置為0x08。要清除位3和位0,請將uxBitsToClear設置為0x09。
返回:
清除指定位之前的事件組的值
EventBits_t xEventGroupClearBits(EventGroupHandle_t xEventGroup,const EventBits_t uxBitsToClear )
設置事件組中的位
設置事件組中的位。不能從中斷中調用此函數。xEventGroupSetBitsFromISR()是可以從中斷中調用的版本。
在事件組中設置位將自動解除阻止等待這些位的任務。
參數:
xEventGroup:要設置位的事件組。
uxBitsToSet:按位的值,指示要設置的一個或多個位。例如,要僅設置位3,請將uxBitsToSet設置為0x08。要設置位3和位0,請將uxBitsToSet設置為0x09。
返回
返回xEventGroupSetBits()調用時事件組的值。返回值可能清除了uxBitsToSet參數指定的位有兩個原因。首先,如果設置一個位導致正在等待該位離開阻塞狀態的任務,則有可能該位將被自動清除(請參閱xEventGroupWaitBits()的xClearBitOnExit參數)。其次,任何優先級高於被稱為xEventGroupSetBits()的任務的無阻塞(或就緒狀態)任務都將執行,並且可能會在調用xEventGroupSetBits()返回之前更改事件組的值。
EventBits_t xEventGroupSetBits(EventGroupHandle_t xEventGroup,const EventBits_t uxBitsToSet )
刪除事件組
刪除以前通過調用xEventGroupCreate()創建的事件組。在事件組上被阻止的任務將被取消阻止,並獲得0作為事件組的值。
參數:
xEventGroup事件組句柄
Void vEventGroupDelete(EventGroupHandle_t xEventGroup )
中斷中獲取事件組的位
可以從ISR調用的xEventGroupGetBits()版本
參量
xEventGroup:正在查詢的事件組
返回
調用xEventGroupGetBitsFromISR()時的事件組位
EventBits_t xEventGroupGetBitsFromISR(EventGroupHandle_t xEventGroup )
中斷中清除數據組的位
可以從中斷中調用的xEventGroupClearBits()版本。
在事件組中設置位不是確定性操作,因為可能有未知數量的任務正在等待設置一個或多個位。FreeRTOS不允許在禁用中斷時執行不確定的操作,因此通過掛起調度程序而不是禁用中斷來保護從任務訪問的事件組。結果,不能從中斷服務程序直接訪問事件組。因此,xEventGroupClearBitsFromISR()向計時器任務發送一條消息,以在計時器任務的上下文中執行清除操作。
參量
xEventGroup:事件組,其中的位將被清除。
uxBitsToClear:按位的值,指示要清除的一個或多個位。例如,僅清除位3,將uxBitsToClear設置為0x08。要清除位3和位0,請將uxBitsToClear設置為0x09
返回
如果成功執行了執行功能的請求,則返回pdPASS,否則返回pdFALSE。如果計時器服務隊列已滿,則將返回pdFALSE
xEventGroupClearBitsFromISR( xEventGroup,uxBitsToClear )
中斷中設置事件組的位
可以從中斷中調用的xEventGroupSetBits()版本。
在事件組中設置位不是確定性操作,因為可能有未知數量的任務正在等待設置一個或多個位。FreeRTOS不允許在中斷或關鍵部分執行不確定的操作。因此,xEventGroupSetBitFromISR()向計時器任務發送一條消息,以在計時器任務的上下文中執行設置操作-在該上下文中,使用調度程序鎖來代替關鍵節。
參量
xEventGroup:要設置位的事件組。
uxBitsToSet:按位的值,指示要設置的一個或多個位。例如,要僅設置位3,請將uxBitsToSet設置為0x08。要設置位3和位0,請將uxBitsToSet設置為0x09。
pxHigherPriorityTaskWoken:如上所述,調用此函數將導致消息發送到計時器守護程序任務。如果計時器守護程序任務的優先級高於當前正在運行的任務(中斷被中斷的任務)的優先級,則xEventGroupSetBitsFromISR()將* pxHigherPriorityTaskWoken設置為pdTRUE,指示應在中斷退出之前請求上下文切換。因此,必須將* pxHigherPriorityTaskWoken初始化為pdFALSE。
返回
如果成功執行了執行功能的請求,則返回pdPASS,否則返回pdFALSE。如果計時器服務隊列已滿,則將返回pdFALSE。
xEventGroupSetBitsFromISR( xEventGroup,uxBitsToSet,pxHigherPriorityTaskWoken )
小試牛刀
1 #include <stdio.h> 2 #include "freertos/FreeRTOS.h"//freertos相關 3 #include "freertos/task.h" 4 #include "freertos/event_groups.h" 5 //事件組句柄 6 EventGroupHandle_t eventgroup=NULL; 7 8 //管理的位, 9 #define BIT_0 (1 << 0) 10 #define BIT_5 (1 << 5) 11 12 //任務0處理函數 13 void Task_Run_0(){ 14 while(1){ 15 printf("【task 0】事件標志組等待開始---\r\n"); 16 xEventGroupWaitBits( 17 eventgroup, // 事件標志組句柄 18 BIT_0 | BIT_5, //時間標志位 19 pdTRUE, //pdTRUE為滿足條件則清除返回,pdFALSE為不清除返回 20 pdTRUE, //pdTRUE為所有標志位滿足才有效,pdFALSE為部分滿足有效 21 portMAX_DELAY); //等待時間,portMAX_DELAY為一直等待,0為立即返回,其它為節拍數 22 23 printf("【task 0】事件標志組等待結束---\r\n"); 24 printf("【task 0】開始動作啦---\r\n"); 25 printf("【task 0】.......................---\r\n"); 26 printf("【task 0】結束動作啦---\r\n"); 27 } 28 } 29 //主函數,優先級為1 30 void app_main() 31 { 32 printf("\r\n--------------DONGIXAODONG FreeRTOS-----------------\r\n"); 33 //創建時間組 34 eventgroup=xEventGroupCreate(); 35 36 //啟動任務0,簡化 37 //函數,名字,字節大小,參數,優先級[0,16](16最優先),任務句柄 38 BaseType_t t0res=xTaskCreate(Task_Run_0,"DONG Task_Run_0",1024*2,NULL,7,NULL); 39 if(t0res==pdPASS){ 40 printf("任務0啟動成功....\r\n"); 41 } 42 while(1){ 43 printf("【main】///////開始設置位//////\r\n"); 44 45 printf("【main】設置位:BIT_0\r\n"); 46 xEventGroupSetBits(eventgroup, BIT_0); 47 vTaskDelay(2000 / portTICK_PERIOD_MS); 48 49 printf("【main】設置位:BIT_5\r\n"); 50 xEventGroupSetBits(eventgroup, BIT_5); 51 vTaskDelay(3000 / portTICK_PERIOD_MS); 52 53 printf("【main】設置位:BIT_5|BIT_0 \r\n"); 54 xEventGroupSetBits(eventgroup, BIT_5|BIT_0); 55 vTaskDelay(3000 / portTICK_PERIOD_MS); 56 } 57 }
任務通知
任務通知在FreeRTOS中是一個可選的功能,要使用任務通知的話就需要將宏contfigUSE TASK NOTIFICATIONS定義為1
FreeRTOS的每個任務都有一個32位的通知值,任務控制塊中的成員變量ulNotifiedValue就是這個通知值。任務通知是一個事件,假如某個任務通知的接收任務因為等待任務通知而阻塞的話,向這個接收任務發送任務通知以后就會解除這個任務的阻塞狀態。也可以更新接收任務的任務通知值,任務通知可以通過如下方法更新接收任務的通知值:
不覆蓋接收任務的通知值(如果上次發送給接收任務的通知還沒被處理)。
覆蓋接收任務的通知值。
更新接收任務通知值的一個或多個bit.增加接收任務的通知值。
合理、靈活的使用上面這些更改任務通知值的方法可以在一些場合中替代隊列、二值信號·量、計數型信號量和事件標志組。使用任務通知來實現二值信號量功能的時候,解除任務阻塞的時間比直接使用二值信號量要快45%(FreeRTOS官方測試結果,使用v8.1.2版本中的二值信號量, GCC編譯器,-02優化的條件下測試的,沒有使能斷言函數configASSERTO),並且使用的RAM更少!
任務通知的發送使用函數xTaskNotify)或者xTaskNotifyGive)(還有此函數的中斷版本)來完成,這個通知值會一直被保存着,直到接收任務調用函數xTaskNotifyWait)或者ulTaskNotifyTake)來獲取這個通知值。假如接收任務因為等待任務通知而阻塞的話那么在接收到任務通知以后就會解除阻塞態。任務通知雖然可以提高速度,並且減少RAM的使用,但是任務通知也是有使用限制的:
FreeRTOS的任務通知只能有一個接收任務,其實大多數的應用都是這種情況。
接收任務可以因為接收任務通知而進入阻塞態,但是發送任務不會因為任務通知發送失敗而阻塞
發送任務通知
configUSE_TASK_NOTIFICATIONS必須未定義或定義為1才能使此功能可用。
將configUSE_TASK_NOTIFICATIONS設置為1時,每個任務都有其自己的專用“通知值”,該值是32位無符號整數(uint32_t)。
可以使用中介對象將事件發送到任務。此類對象的示例是隊列,信號量,互斥對象和事件組。任務通知是一種將事件直接發送到任務而無需此類中介對象的方法。
發送給任務的通知可以選擇執行某項操作,例如更新,覆蓋或增加任務的通知值。這樣,任務通知可用於將數據發送到任務,或用作輕量級和快速二進制或計數信號量。
發送給任務的通知將保持待處理狀態,直到任務調用xTaskNotifyWait()或ulTaskNotifyTake()將其清除為止。如果通知到達時任務已經處於“阻止”狀態以等待通知,則該任務將自動從“阻止”狀態中刪除(取消阻止),並清除通知。
任務可以使用xTaskNotifyWait()來[可選地]阻塞以等待通知掛起,或者使用ulTaskNotifyTake()來[可選地]阻塞以等待其通知值具有非零值。處於“阻塞”狀態時,該任務不會消耗任何CPU時間。
參數:
xTaskToNotify:通知任務的句柄。可以從用於創建任務的xTaskCreate()API函數返回任務的句柄,並且可以通過調用xTaskGetCurrentTaskHandle()獲得當前正在運行的任務的句柄。
ulValue:可以隨通知一起發送的數據。數據的使用方式取決於eAction參數的值。
eAction:指定通知如何更新任務的通知值(如果有的話)。eAction的有效值如下:
eNoAction = 0,無動作,通知任務而不更新其通知值。始終返回pdPASS。
eSetBits, 任務的通知值與ulValue按位或,始終返回pdPASS。
eIncrement, 任務的通知值增加1,始終返回pdPASS。
eSetValueWithOverwrite, 復寫方式更新通知值,不管任務是否讀取該值,都將更新通知值,始終返回pdPASS
esetvaluewithoutoverwrite果任務已經讀取了之前的值,則設置任務的通知值。如果被通知的任務尚未有待處理的通知,則該任務的通知值將設置為ulValue,xTaskNotify()將返回pdPASS。如果要通知的任務已經有待處理的通知,則不執行任何操作,並返回pdFAIL。
BaseType_t xTaskNotify(TaskHandle_t xTaskToNotify,uint32_t ulValue,eNotifyAction eAction )
ISR發送任務通知
configUSE_TASK_NOTIFICATIONS必須未定義或定義為1才能使此功能可用。
相較於xTaskNotify多了如下參數:
pxHigherPriorityTaskWoken:如果發送通知導致發送通知的任務離開阻塞狀態,並且未阻塞任務的優先級高於當前運行的任務,則xTaskNotifyFromISR()會將* pxHigherPriorityTaskWoken設置為pdTRUE。如果xTaskNotifyFromISR()將此值設置為pdTRUE,則應在退出中斷之前請求上下文切換。從ISR請求上下文切換的方式取決於端口-有關正在使用的端口,請參閱文檔頁面
BaseType_t xTaskNotifyFromISR(TaskHandle_t xTaskToNotify,uint32_t ulValue,eNotifyAction eAction,BaseType_t * pxHigherPriorityTaskWoken )
等待任務通知
configUSE_TASK_NOTIFICATIONS必須未定義或定義為1才能使此功能可用。
任務可以使用xTaskNotifyWait()來[可選地]阻塞以等待通知掛起,或者使用ulTaskNotifyTake()來[可選地]阻塞以等待其通知值具有非零值。處於“阻塞”狀態時,該任務不會消耗任何CPU時間。
參數:
l ulBitsToClearOnEntry注意:等待前的清除,在檢查任務是否有待處理的通知之前,將在調用任務的通知值中清除ulBitsToClearOnEntry值中設置的位,如果沒有待處理的通知,則將阻塞該任務。將ulBitsToClearOnEntry設置為ULONG_MAX(如果包括limits.h)或0xffffffffUL(如果不包括limits.h)將具有將任務的通知值重置為0的作用。將ulBitsToClearOnEntry設置為0將使任務的通知值保持不變。
l ulBitsToClearOnExit:退出等待的清除,如果在調用任務退出xTaskNotifyWait()函數之前有待處理或已收到通知,則使用pulNotificationValue參數傳遞任務的通知值(請參閱xTaskNotify()API函數)。然后,將在任務的通知值中清除在ulBitsToClearOnExit中設置的所有位(請注意,在清除任何位之前已設置* pulNotificationValue)。將ulBitsToClearOnExit設置為ULONG_MAX(如果包括limits.h)或0xffffffffUL(如果不包括limits.h)將在功能退出之前將任務的通知值重置為0。將ulBitsToClearOnExit設置為0將在函數退出時使任務的通知值保持不變(在這種情況下,在pulNotificationValue中傳遞的值將與任務的通知值匹配)。
l pulNotificationValue:用於將任務的通知值傳遞出函數。注意,由於ulBitsToClearOnExit非零而導致清除任何位,不會影響傳遞的值。
l xTicksToWait:如果在調用xTaskNotifyWait()時通知尚未掛起,則任務在“已阻止”狀態下等待接收通知的最長時間。處於“阻塞”狀態時,該任務不會消耗任何處理時間。這是在內核滴答中指定的,宏pdMS_TO_TICSK(value_in_ms)可用於將以毫秒為單位指定的時間轉換為以滴答為單位指定的時間。
返回
如果收到通知(包括調用xTaskNotifyWait時已待處理的通知),則返回pdPASS。否則,返回pdFAIL。
BaseType_t xTaskNotifyWait( uint32_t ulBitsToClearOnEntry,uint32_t ulBitsToClearOnExit,uint32_t * pulNotificationValue,TickType_t xTicksToWait )
簡化的通知
適用於模擬任務對任務的二值信號量和計數型信號量功能
參數:接收的任務句柄
返回:始終返回pdPASS
xTaskNotifyGive( xTaskToNotify )
函數原型
可見,其功能是給eAction參數的值進行加一操作
#define xTaskNotifyGive( xTaskToNotify ) xTaskNotify( ( xTaskToNotify ), 0, eIncrement )
簡化的接收
適用於模擬任務對任務的二值信號量和計數型信號量功能
參數:
xClearCountOnExit:如果xClearCountOnExit為pdFALSE,則函數退出時任務的通知值將減小。這樣,通知值就像計數信號量一樣。如果xClearCountOnExit不是pdFALSE,則函數退出時,任務的通知值將清除為零。這樣,通知值的作用就像一個二進制信號量。
xTicksToWait:如果在調用ulTaskNotifyTake()時計數尚未大於零,則任務應在“阻塞”狀態下等待的最大時間,以使該任務的通知值大於零。處於“阻塞”狀態時,該任務不會消耗任何處理時間。這是在內核滴答中指定的,宏pdMS_TO_TICSK(value_in_ms)可用於將以毫秒為單位指定的時間轉換為以滴答為單位指定的時間。
返回
任務的通知計數在清零或遞減之前(請參閱xClearCountOnExit參數)
uint32_t ulTaskNotifyTake( BaseType_t xClearCountOnExit,TickType_t xTicksToWait )
其功能是給eAction參數的值進行減一或清零操作
小試牛刀(任務同步效果)
1 #include <stdio.h> 2 #include "freertos/FreeRTOS.h"//freertos相關 3 #include "freertos/task.h" 4 #include "freertos/semphr.h" 5 //任務句柄 6 TaskHandle_t TaskH_0=NULL; 7 8 //任務0處理函數 9 void Task_Run_0(){ 10 uint32_t Noti_vlaue=0; 11 while(1){ 12 /* 13 參數1:進入時,傳遞的參數取反后按位與來設定任務通知初值(ULONG_MAX表示清零,0表示值不變,其他值按規則) 14 參數2:退出時,傳遞的參數取反后按位與來設定任務通知初值(ULONG_MAX表示清零,0表示值不變,其他值按規則) 15 參數3:通知值獲取 16 參數4:等待時間 17 */ 18 xTaskNotifyWait(ULONG_MAX,ULONG_MAX,&Noti_vlaue,portMAX_DELAY); 19 printf("【task 0】接收到通知,其值為:%d\r\n",Noti_vlaue); 20 } 21 } 22 //主函數,優先級為1 23 void app_main() 24 { 25 printf("\r\n--------------DONGIXAODONG FreeRTOS-----------------\r\n"); 26 27 //啟動任務0,簡化 28 //函數,名字,字節大小,參數,優先級[0,16](16最優先),任務句柄 29 BaseType_t t0res=xTaskCreate(Task_Run_0,"DONG Task_Run_0",1024*2,NULL,7,&TaskH_0); 30 if(t0res==pdPASS){ 31 printf("任務0啟動成功....\r\n"); 32 } 33 while(1){ 34 vTaskDelay(3000 / portTICK_PERIOD_MS);//延時3S 35 printf("【main】即將發送一次通知\r\n"); 36 /* 37 參數1:任務句柄 38 參數2:通知值 39 參數3: 40 eNoAction = 0,無動作,通知任務而不更新其通知值 41 eSetBits, 任務的通知值與ulValue按位或 42 eIncrement, 任務的通知值增加1 43 eSetValueWithOverwrite, 復寫方式更新通知值,不管任務是否讀取該值,都將更新通知值 44 eSetValueWithoutOverwrite 果任務已經讀取了之前的值,則設置任務的通知值 45 */ 46 xTaskNotify(TaskH_0,1,eNoAction); 47 } 48 }
小試牛刀(任務同步與值傳遞效果)
1 #include <stdio.h> 2 #include "freertos/FreeRTOS.h"//freertos相關 3 #include "freertos/task.h" 4 #include "freertos/semphr.h" 5 //任務句柄 6 TaskHandle_t TaskH_0=NULL; 7 8 //任務0處理函數 9 void Task_Run_0(){ 10 uint32_t Noti_vlaue=0; 11 while(1){ 12 /* 13 參數1:進入時,傳遞的參數取反后按位與來設定任務通知初值(ULONG_MAX表示清零,0表示值不變,其他值按規則) 14 參數2:退出時,傳遞的參數取反后按位與來設定任務通知初值(ULONG_MAX表示清零,0表示值不變,其他值按規則) 15 參數3:通知值獲取 16 參數4:等待時間 17 */ 18 xTaskNotifyWait(ULONG_MAX,ULONG_MAX,&Noti_vlaue,portMAX_DELAY); 19 printf("【task 0】接收到通知,其值為:%d\r\n",Noti_vlaue); 20 } 21 } 22 //主函數,優先級為1 23 void app_main() 24 { 25 printf("\r\n--------------DONGIXAODONG FreeRTOS-----------------\r\n"); 26 27 //啟動任務0,簡化 28 //函數,名字,字節大小,參數,優先級[0,16](16最優先),任務句柄 29 BaseType_t t0res=xTaskCreate(Task_Run_0,"DONG Task_Run_0",1024*2,NULL,7,&TaskH_0); 30 if(t0res==pdPASS){ 31 printf("任務0啟動成功....\r\n"); 32 } 33 uint32_t num=0; 34 while(1){ 35 vTaskDelay(3000 / portTICK_PERIOD_MS);//延時3S 36 printf("【main】即將發送一次通知\r\n"); 37 num++; 38 /* 39 參數1:任務句柄 40 參數2:通知值 41 參數3: 42 eNoAction = 0,無動作,通知任務而不更新其通知值 43 eSetBits, 任務的通知值與ulValue按位或 44 eIncrement, 任務的通知值增加1 45 eSetValueWithOverwrite, 復寫方式更新通知值,不管任務是否讀取該值,都將更新通知值 46 eSetValueWithoutOverwrite 如果任務已經讀取了之前的值,則設置任務的通知值 47 */ 48 xTaskNotify(TaskH_0,num,eSetValueWithoutOverwrite); 49 } 50 }
小試牛刀(任務同步與自動加一效果)
1 #include <stdio.h> 2 #include "freertos/FreeRTOS.h"//freertos相關 3 #include "freertos/task.h" 4 #include "freertos/semphr.h" 5 //任務句柄 6 TaskHandle_t TaskH_0=NULL; 7 8 //任務0處理函數 9 void Task_Run_0(){ 10 uint32_t Noti_vlaue=0; 11 while(1){ 12 /* 13 參數1:進入時,傳遞的參數取反后按位與來設定任務通知初值(ULONG_MAX表示清零,0表示值不變,其他值按規則) 14 參數2:退出時,傳遞的參數取反后按位與來設定任務通知初值(ULONG_MAX表示清零,0表示值不變,其他值按規則) 15 參數3:通知值獲取 16 參數4:等待時間 17 */ 18 xTaskNotifyWait(0,0,&Noti_vlaue,portMAX_DELAY); 19 printf("【task 0】接收到通知,其值為:%d\r\n",Noti_vlaue); 20 } 21 } 22 //主函數,優先級為1 23 void app_main() 24 { 25 printf("\r\n--------------DONGIXAODONG FreeRTOS-----------------\r\n"); 26 27 //啟動任務0,簡化 28 //函數,名字,字節大小,參數,優先級[0,16](16最優先),任務句柄 29 BaseType_t t0res=xTaskCreate(Task_Run_0,"DONG Task_Run_0",1024*2,NULL,7,&TaskH_0); 30 if(t0res==pdPASS){ 31 printf("任務0啟動成功....\r\n"); 32 } 33 while(1){ 34 vTaskDelay(3000 / portTICK_PERIOD_MS);//延時3S 35 printf("【main】DONG 即將發送一次通知\r\n"); 36 /* 37 參數1:任務句柄 38 參數2:通知值 39 參數3: 40 eNoAction = 0,無動作,通知任務而不更新其通知值 41 eSetBits, 任務的通知值與ulValue按位或 42 eIncrement, 任務的通知值增加1 43 eSetValueWithOverwrite, 復寫方式更新通知值,不管任務是否讀取該值,都將更新通知值 44 eSetValueWithoutOverwrite 如果任務已經讀取了之前的值,則設置任務的通知值 45 */ 46 xTaskNotify(TaskH_0,0,eIncrement); 47 } 48 }
參考:
https://zhidao.baidu.com/question/7412988.html
ESP32文檔:https://docs.espressif.com/projects/esp-idf/en/v4.0/api-reference/system/freertos.html
正點原子