**1、freeRTOS中的消息郵箱 **
freeRTOS實(shí)現(xiàn)的消息郵箱是基于任務(wù)通知方式而實(shí)現(xiàn)的。
采用這種方式有什么優(yōu)勢呢?
從官方給出的測試報(bào)告中有說明到,喚醒由于信號量和事件標(biāo)志組而處于阻塞態(tài)的任務(wù),消息郵箱的速度會提升大約 45%,而且這種方式需要的 RAM 空間更小。
freeRTOS中的消息郵箱使用是比較靈活的,它可以實(shí)現(xiàn)二值信號量、計(jì)數(shù)信號量、事件標(biāo)志組、消息隊(duì)列等通知方式。
但用這種 方式實(shí)現(xiàn)信號量和事件標(biāo)志組也有它的局限性,主要表現(xiàn)在以下兩個(gè)方面:
1)任務(wù)通知方式僅可以用在只有一個(gè)任務(wù)等待信號量,消息郵箱或者事件標(biāo)志組的情況。
2)如果使用任務(wù)通知方式實(shí)現(xiàn)消息郵箱替代消息隊(duì)列時(shí),發(fā)送消息的任務(wù)是不支持超時(shí)等待的。在消息隊(duì)列中,當(dāng)數(shù)據(jù)已經(jīng)滿時(shí),是可以等待消息隊(duì)列有空間才存新的數(shù)據(jù)的,但是任務(wù)通知方式實(shí)現(xiàn)的消 息郵箱就不支持超時(shí)等待。
2、有關(guān)freeRTOS中的任務(wù)控制塊
freeRTOS中的每一個(gè)任務(wù)都有一個(gè)任務(wù)控制塊,而任務(wù)控制塊本質(zhì)就是一個(gè)結(jié)構(gòu)體變量,用于記錄任務(wù)的相關(guān)的消息。
而在結(jié)構(gòu)體變量中有一個(gè)32位的變量成員ulNotifiedValue是可以專門用于任務(wù)通知的。這個(gè)變量可以實(shí)現(xiàn)計(jì)數(shù)信號量,二值信號量,事件標(biāo)志組和消息郵箱(消息郵箱就是消息隊(duì) 列長度為 1 的情況)。
ulNotifiedValue 實(shí)現(xiàn)的:
1)設(shè)置接收任務(wù)控制塊中的變量 ulNotifiedValue 可以實(shí)現(xiàn)消息郵箱。
2)如果接收任務(wù)控制塊中的變量 ulNotifiedValue 還沒有被其接收到,也可以用新數(shù)據(jù)覆蓋原有數(shù)據(jù) ,這就是 覆蓋方式的消息郵箱 。
3)設(shè)置接收任務(wù)控制塊中的變量 ulNotifiedValue 的 bit0-bit31 數(shù)值可以實(shí)現(xiàn)事件標(biāo)志組。
4)設(shè)置接收任務(wù)控制塊中的變量 ulNotifiedValue 數(shù)值進(jìn)行加一或者減一操作可以實(shí)現(xiàn)計(jì)數(shù)信號量和二 值信號量。
3、freeRTOS中消息郵箱的管理API函數(shù)
消息郵箱實(shí)現(xiàn)的相關(guān)API函數(shù):
3.1、消息郵箱的創(chuàng)建
freeRTOS中的消息郵箱是用于任務(wù)之間的一種通知方式,它的使用是不需要像信號量這樣要專門創(chuàng)建的。是直接發(fā)送通知的。
3.2、消息郵箱的發(fā)送
1)在任務(wù)函數(shù)中發(fā)送
函數(shù)原型:
BaseType_t xTaskNotify( TaskHandle_t xTaskToNotify, /* 任務(wù)句柄 */
uint32_t ulValue, /* 更新任務(wù)控制塊中的變量 ulNotifiedValue */
eNotifyAction eAction ); /* 任務(wù)通知模式設(shè)置 */
函數(shù)描述:
第 1 個(gè)參數(shù)是任務(wù)句柄。
第 2 個(gè)參數(shù)是用來更新任務(wù)控制塊中的 32 位變量 ulNotifiedValue。
第 3 個(gè)參數(shù)是任務(wù)通知模式設(shè)置,支持以下 5 個(gè)參數(shù):
返回值,根據(jù)上面第3個(gè)參數(shù)的說明,將其設(shè)置為 :
eSetValueWithoutOverwrite ,有可能返回 pdFALSE,其余所有情況都返回值 pdPASS。
使用這個(gè)函數(shù)要注意以下問題:
1)任務(wù)創(chuàng)建后,任務(wù)控制塊中的變量 ulNotifiedValue 初始計(jì)數(shù)值是 0。
2)默認(rèn)配置此函數(shù)可以使用的的宏定義已經(jīng)在 FreeRTOS.h 文件中使能:
#define configUSE_TASK_NOTIFICATIONS 1
當(dāng)然,如果不需要使用任務(wù)通知功能相關(guān)的函數(shù),可以在 FreeRTOSConfig.h 文件中配置此宏定 義為 0 來禁止,這樣創(chuàng)建的每個(gè)任務(wù)可以節(jié)省 8 個(gè)字節(jié)的需求。
3)此函數(shù)是用于任務(wù)代碼中調(diào)用的,故不可以在中斷服務(wù)程序中調(diào)用此函數(shù),中斷服務(wù)程序中使用的是 xTaskNotifyFromISR。
4)根據(jù) FreeRTOS 的建議,實(shí)現(xiàn)二值信號量和計(jì)數(shù)信號量時(shí)使用函數(shù) xTaskNotifyGive()替代此函數(shù) xTaskNotify()。
2)在中斷中發(fā)送
函數(shù)原型:
BaseType_t xTaskNotifyFromISR( TaskHandle_t xTaskToNotify, /* 任務(wù)句柄 */
uint32_t ulValue, /* 更新任務(wù)控制塊中的變量 ulNotifiedValue */
eNotifyAction eAction, /* 任務(wù)通知模式設(shè)置 */
BaseType_t *pxHigherPriorityTaskWoken ); /* 高優(yōu)先級任務(wù)是否被喚醒的狀態(tài)保存 */
函數(shù)描述:
函數(shù) xTaskNotifyFromISR 通過設(shè)置任務(wù)控制塊中的變量 ulNotifiedValue 可以在中斷服務(wù)程序中實(shí)現(xiàn)任 務(wù)事件標(biāo)志組,任務(wù)計(jì)數(shù)信號量,任務(wù)消息郵箱和任務(wù)二值信號量四種方式的消息通知。
第 1 個(gè)參數(shù)是任務(wù)句柄。
第 2 個(gè)參數(shù)是用來更新任務(wù)控制塊中的 32 位變量 ulNotifiedValue。
第 3 個(gè)參數(shù)是任務(wù)通知模式設(shè)置,支持以下 5 個(gè)參數(shù):
第4個(gè)參數(shù)用于保存是否有高優(yōu)先級任務(wù)準(zhǔn)備就緒。如果函數(shù)執(zhí)行完畢后,此參數(shù)的數(shù)值是 pdTRUE , 說明有高優(yōu)先級任務(wù)要執(zhí)行,否則沒有。
返回值,根據(jù)上面第 3 個(gè)參數(shù)的說明,將其設(shè)置為:
eSetValueWithoutOverwrite ,有可能返回 pdFALSE ,其余所有情況都返回值 pdPASS 。
使用這個(gè)函數(shù)要注意以下問題:
- 任務(wù)創(chuàng)建后,任務(wù)控制塊中的變量** ulNotifiedValue **初始計(jì)數(shù)值是 0。
- 默認(rèn)配置此函數(shù)可以使用的的宏定義已經(jīng)在 FreeRTOS.h 文件中使能:
#define configUSE_TASK_NOTIFICATIONS 1
當(dāng)然,如果用戶不需要使用任務(wù)通知功能相關(guān)的函數(shù),可以在 FreeRTOSConfig.h 文件中配置此宏定 義為 0 來禁止,這樣創(chuàng)建的每個(gè)任務(wù)可以節(jié)省 8 個(gè)字節(jié)的需求。
3)此函數(shù)是用于中斷服務(wù)程序中調(diào)用的,故不可以在任務(wù)代碼中調(diào)用此函數(shù),任務(wù)代碼中使用的是 xTaskNotify。
4)FreeRTOS 的建議,實(shí)現(xiàn)二值信號量和計(jì)數(shù)信號量時(shí)使用函數(shù) vTaskNotifyGiveFromISR ()替代 此函數(shù) xTaskNotifyFromISR ()。
3.3、等待消息郵箱
(1)等待消息郵箱
函數(shù)原型:
BaseType_t xTaskNotifyWait(
/* 設(shè)置函數(shù)執(zhí)行前清零任務(wù)控制塊中變量 ulNotifiedValue 那些位 */
uint32_t ulBitsToClearOnEntry,
/*設(shè)置函數(shù)退出前清零任務(wù)控制塊中變量 ulNotifiedValue 那些位 */
uint32_t ulBitsToClearOnExit,
/* 保存任務(wù)控制塊中的變量 ulNotifiedValue 到指針變量 pulNotifiedValue 所指向的存儲單元 */
uint32_t *pulNotificationValue,
/* 等待消息通知的最大等待時(shí)間 */
TickType_t xTicksToWait
);
函數(shù)描述:
函數(shù) xTaskNotifyWait 可以在任務(wù)代碼中實(shí)現(xiàn)任務(wù)事件標(biāo)志組,任務(wù)計(jì)數(shù)信號量,任務(wù)消息郵箱和任務(wù)二 值信號量四種方式的消息獲取。
第 1 個(gè)參數(shù) ulBitsToClearOnEntry 用于函數(shù)執(zhí)行之前,將任務(wù)控制塊中的變量 ulNotifiedValue 進(jìn) 行如下操作 :
ulNotifiedValue &= ~ulBitsToClearOnEntry
簡單的說就是參數(shù) ulBitsToClearOnEntry 哪個(gè)位是 1,那么變量 ulNotifiedValue 的那個(gè)位就會被 清零。比如 ulBitsToClearOnEntry = 0x01 表示將變量 ulNotifiedValue 的 bit0 清零,又比如 ulBitsToClearOnEntry = 0xffffffff 表示將變量 ulNotifiedValue 的所有位清零。
第 2 個(gè)參數(shù) ulBitsToClearOnExit 用于函數(shù)退出前,將任務(wù)控制塊中的變量 ulNotifiedValue 進(jìn)行如 下操作 :
ulNotifiedValue &= ~ ulBitsToClearOnExit
簡單的說就是參數(shù) ulBitsToClearOnExit 哪個(gè)位是 1,那么變量 ulNotifiedValue 的那個(gè)位就會被清 零。比如 ulBitsToClearOnExit= 0x01 表示將變量 ulNotifiedValue 的 bit0 清零,又比如 ulBitsToClearOnExit= 0xffffffff 表示將變量 ulNotifiedValue 的所有位清零。
第 3 個(gè)參數(shù)用于將任務(wù)控制塊中的變量 ulNotifiedValue 保存到此參數(shù)指針?biāo)赶虻拇鎯卧?。如?此參數(shù)沒有用上,可以將其設(shè)置為 NULL。
第 4 個(gè)參數(shù)是沒有消息時(shí),等待消息的最大等待時(shí)間,單位系統(tǒng)時(shí)鐘節(jié)拍。
返回值,如果成功接收到消息返回 pdTRUE,否則返回 pdFALSE,比如在設(shè)置的超時(shí)時(shí)間內(nèi)沒有收 到消息。
使用這個(gè)函數(shù)要注意以下問題:
1)任務(wù)創(chuàng)建后,任務(wù)控制塊中的變量 ulNotifiedValue 初始計(jì)數(shù)值是 0。
2)默認(rèn)配置此函數(shù)可以使用的的宏定義已經(jīng)在 FreeRTOS.h 文件中使能:
#define configUSE_TASK_NOTIFICATIONS 1
當(dāng)然,如果用戶不需要使用任務(wù)通知功能相關(guān)的函數(shù),可以在 FreeRTOSConfig.h 文件中配置此宏定 義為 0 來禁止,這樣創(chuàng)建的每個(gè)任務(wù)可以節(jié)省 8 個(gè)字節(jié)的需求。
3)如果用戶將 FreeRTOSConfig.h 文件中的宏定義 INCLUDE_vTaskSuspend 配置為 1 且第 2 個(gè)參數(shù)配 置為:
portMAX_DELAY ,那么此函數(shù)會永久等待直到消息可用。
4)根據(jù) FreeRTOS 的建議,實(shí)現(xiàn)二值信號量和計(jì)數(shù)信號量時(shí)使用函數(shù) ulTaskNotifyTake ()替代此函數(shù) xTaskNotifyWait ()。
4、消息郵箱的應(yīng)用示例
為了更好的說明freeRTOS中的消息郵箱的使用。下面給出了一個(gè)簡單的示例。
代碼思路如下:
創(chuàng)建3個(gè)任務(wù):start_task,led0_task,led2_task。start_task任務(wù)用于創(chuàng)建led0_task和led2_task任務(wù),led0_task任務(wù)判斷按鍵的情況,然后根據(jù)按鍵按下,消息郵箱發(fā)送不同的消息到任務(wù)led2_task,在這個(gè)任務(wù)中改變LED2和LED3的狀態(tài)。代碼示例如下:
void start_task(void *pvParameters)
{
pvParameters = pvParameters;
taskENTER_CRITICAL(); //進(jìn)入臨界區(qū)
xTaskCreate((TaskFunction_t) led0_task,
(const char*) "led0_task",
(uint16_t) TASK_STK_LED0_SIZE,
(void*) NULL,
(UBaseType_t) TASK_LED0_PRIO,
(TaskHandle_t*) &LED0_Handler );
xTaskCreate((TaskFunction_t) led2_task,
(const char*) "led2_task",
(uint16_t) TASK_STK_LED2_SIZE,
(void*) NULL,
(UBaseType_t) TASK_LED2_PRIO,
(TaskHandle_t*) &LED2_Handler );
vTaskDelete(StartTask_Handler); //刪除開始任務(wù)
taskEXIT_CRITICAL(); //退出臨界區(qū)
}
void led0_task(void *pvParameters)
{
//pvParameters = pvParameters;
BaseType_t err = pdFALSE;
uint32_t MboxValue=0;
for(;;)
{
if(gd_eval_key_state_get(KEY_WAKEUP) == RESET)
{
MboxValue = 10;
err = xTaskNotify((TaskHandle_t ) LED2_Handler, //任務(wù)句柄,指明往哪個(gè)任務(wù)發(fā)送消息,很重要
(uint32_t ) MboxValue, //發(fā)送的消息
(eNotifyAction) eSetValueWithOverwrite //消息發(fā)送方式
);
}
else if(gd_eval_key_state_get(KEY_TAMPER) == RESET)
{
MboxValue = 50;
err = xTaskNotify((TaskHandle_t ) LED2_Handler, //任務(wù)句柄
(uint32_t ) MboxValue, //發(fā)送的消息
(eNotifyAction) eSetValueWithOverwrite //消息發(fā)送方式
);
}
else{}
gd_eval_led_toggle(LED4);
vTaskDelay(200);
}
}
void led2_task(void *pvParameters)
{
//pvParameters = pvParameters;
uint32_t notifyValue = 0;
BaseType_t err;
for(;;)
{
err = xTaskNotifyWait((uint32_t ) 0x00, //進(jìn)入函數(shù)時(shí)不清楚bit
(uint32_t) 0xffffffff, //退出函數(shù)時(shí)清除所有的bit
(uint32_t*) ¬ifyValue, //保存消息的內(nèi)容
(TickType_t) portMAX_DELAY //阻塞時(shí)間
);
if(err == pdTRUE)
{
switch(notifyValue)
{
case 10:
gd_eval_led_toggle(LED2);
break;
case 50:
gd_eval_led_toggle(LED3);
break;
default:
break;
}
}
vTaskDelay(100);
}
}
-
FreeRTOS
+關(guān)注
關(guān)注
12文章
484瀏覽量
62271 -
信號量
+關(guān)注
關(guān)注
0文章
53瀏覽量
8362 -
消息隊(duì)列
+關(guān)注
關(guān)注
0文章
33瀏覽量
3010
發(fā)布評論請先 登錄
相關(guān)推薦
評論