一、頭文件
#include "FreeRTOS.h"
#include "event_groups.h"
二、事件
2.1 基本概念
事件是一種實(shí)現(xiàn)任務(wù)間通信的機(jī)制,主要用于實(shí)現(xiàn)多任務(wù)間的同步,但事件通信只能是事件類型的通信,無數(shù)據(jù)傳輸。 與信號量不同的是,它可以實(shí)現(xiàn)一對多,多對多的同步。即一個任務(wù)可以等待多個事件的發(fā)生:可以是任意一個事件發(fā)生時喚醒任務(wù)進(jìn)行事件處理;也可以是幾個事件都發(fā)生后才喚醒任務(wù)進(jìn)行事件處理。同樣,也可以是多個任務(wù)同步多個事件。
每一個事件組只需要很少的 RAM 空間來保存事件組的狀態(tài)。事件組存儲在一個 EventBits_t 類型的變量中,該變量在事件組結(jié)構(gòu)體中定義 。在 STM32 中 , 我們一般 configUSE_16_BIT_TICKS 定義為 0,那么 uxEventBits 是 32 位的,有 24 個位用來實(shí)現(xiàn)事 件標(biāo)志組。每一位代表一個事件,任務(wù)通過“邏輯與”或“邏輯或”與一個或多個事件建立關(guān)聯(lián),形成一個事件組。 事件的“邏輯或”也被稱作是獨(dú)立型同步,指的是任務(wù)感興趣的所有事件任一件發(fā)生即可被喚醒;事件“邏輯與”則被稱為是關(guān)聯(lián)型同步,指的是任務(wù)感興趣的若干事件都發(fā)生時才被喚醒,并且事件發(fā)生的時間可以不同步。
多任務(wù)環(huán)境下,任務(wù)、中斷之間往往需要同步操作,一個事件發(fā)生會告知等待中的任務(wù),即形成一個任務(wù)與任務(wù)、中斷與任務(wù)間的同步。 事件可以提供一對多、多對多的同步操作。一對多同步模型:一個任務(wù)等待多個事件的觸發(fā),這種情況是比較常見的;多對多同步模型:多個任務(wù)等待多個事件的觸發(fā)。
任務(wù)可以通過設(shè)置事件位來實(shí)現(xiàn)事件的觸發(fā)和等待操作。FreeRTOS 的事件僅用于同步,不提供數(shù)據(jù)傳輸功能。
FreeRTOS 提供的事件具有如下特點(diǎn):
- 事件只與任務(wù)相關(guān)聯(lián),事件相互獨(dú)立,一個 32 位的事件集合(EventBits_t 類型的變量,實(shí)際可用與表示事件的只有 24 位),用于標(biāo)識該任務(wù)發(fā)生的事件類型,其中每一位表示一種事件類型(0 表示該事件類型未發(fā)生、1 表示該事件類型已經(jīng)發(fā)生),一共 24 種事件類型。
- 事件僅用于同步,不提供數(shù)據(jù)傳輸功能。
- 事件無排隊(duì)性,即多次向任務(wù)設(shè)置同一事件(如果任務(wù)還未來得及讀走),等效于只設(shè)置一次。
- 允許多個任務(wù)對同一事件進(jìn)行讀寫操作。
- 支持事件等待超時機(jī)制。
在 FreeRTOS 事件中,每個事件獲取的時候,用戶可以選擇感興趣的事件,并且選擇讀取事件信息標(biāo)記,它有三個屬性,分別是邏輯與,邏輯或以及是否清除標(biāo)記。當(dāng)任務(wù)等待事件同步時,可以通過任務(wù)感興趣的事件位和事件信息標(biāo)記來判斷當(dāng)前接收的事件是否滿足要求,如果滿足則說明任務(wù)等待到對應(yīng)的事件,系統(tǒng)將喚醒等待的任務(wù);否則,任務(wù)會根據(jù)用戶指定的阻塞超時時間繼續(xù)等待下去。
2.2 運(yùn)作機(jī)制

接收事件時,可以根據(jù)感興趣的參事件類型接收事件的單個或者多個事件類型。事件接收成功后,必須使用 xClearOnExit 選項(xiàng)來清除已接收到的事件類型,否則不會清除已接收到的事件,這樣就需要用戶顯式清除事件位。用戶可以自定義通過傳入?yún)?shù) xWaitForAllBits 選擇讀取模式,是等待所有感興趣的事件還是等待感興趣的任意一個事件。
設(shè)置事件時,對指定事件寫入指定的事件類型,設(shè)置事件集合的對應(yīng)事件位為 1,可以一次同時寫多個事件類型,設(shè)置事件成功可能會觸發(fā)任務(wù)調(diào)度。清除事件時,根據(jù)入?yún)?shù)事件句柄和待清除的事件類型,對事件對應(yīng)位進(jìn)行清 0 操作。事件不與任務(wù)相關(guān)聯(lián),事件相互獨(dú)立,一個 32 位的變量(事件集合,實(shí)際用于表示事件的只有 24 位),用于標(biāo)識該任務(wù)發(fā)生的事件類型,其中每一位表示一種事件類型(0 表示該事件類型未發(fā)生、1 表示該事件類型已經(jīng)發(fā)生),一共 24 種事件類型。

事件喚醒機(jī)制,當(dāng)任務(wù)因?yàn)榈却硞€或者多個事件發(fā)生而進(jìn)入阻塞態(tài),當(dāng)事件發(fā)生的時候會被喚醒。
任務(wù) 1 對事件 3 或事件 5 感興趣(邏輯或),當(dāng)發(fā)生其中的某一個事件都會被喚醒,并且執(zhí)行相應(yīng)操作。而任務(wù) 2 對事件 3 與事件 5 感興趣(邏輯與),當(dāng)且僅當(dāng)事件 3 與事件 5 都發(fā)生的時候,任務(wù) 2 才會被喚醒,如果只有一個其中一個事件發(fā)生,那么任務(wù)還是會繼續(xù)等待事件發(fā)生。如果接在收事件函數(shù)中設(shè)置了清除事件位 xClearOnExit,那么當(dāng)任務(wù)喚醒后將把事件 3 和事件 5 的事件標(biāo)志清零,否則事件標(biāo)志將依然存在。
三、相關(guān)API說明
3.1 xEventGroupCreate
用于創(chuàng)建一個事件組,并返回對應(yīng)的句柄。
| 函數(shù) | EventGroupHandle_t xEventGroupCreate( void ) |
|---|---|
| 參數(shù) | 無 |
| 返回值 | 事件句柄 |
要想使用該函數(shù)必須在 FreeRTOSConfig.h 中把 configSUPPORT_DYNAMIC_ALLOCATION 定義為 1 來使能。

同時把
FreeRTOS/source/event_groups.c 這個 C 文件添加到工程中。
3.2 vEventGroupDelete
當(dāng)系統(tǒng)不再使用事件對象時,可以通過刪除事件對象控制塊來釋放系統(tǒng)資源。
| 函數(shù) | void vEventGroupDelete( EventGroupHandle_t xEventGroup ) |
|---|---|
| 參數(shù) | 事件句柄 |
| 返回值 | 無 |
3.3 xEventGroupSetBits(任務(wù))
用于置位事件組中指定的位,當(dāng)位被置位之后,阻塞在該位上的任務(wù)將會被解鎖。使用該函數(shù)接口時,通過參數(shù)指定的事件標(biāo)志來設(shè)定事件的標(biāo)志位,然后遍歷等待在事件對象上的事件等待列表,判斷是否有任務(wù)的事件激活要求與當(dāng)前事件對象標(biāo)志值匹配,如果有,則喚醒該任務(wù)。簡單來說,就是設(shè)置我們自己定義的事件標(biāo)志位為 1,并且看看有沒有任務(wù)在等待這個事件,有的話就喚醒它。注意的是該函數(shù)不允許在中斷中使用。
| 函數(shù) | EventBits_t xEventGroupSetBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet ) |
|---|---|
| 參數(shù) |
xEventGroup: 事件句柄 uxBitsToSet: 指定事件中的事件標(biāo)志位。如設(shè)置 uxBitsToSet 為 0x08 則只置位位 3,如果設(shè)置 uxBitsToSet 為 0x09 則位 3 和位 0 都需要被置位 |
| 返回值 | 返回調(diào)用 xEventGroupSetBits() 時事件組中的值 |
3.4 xEventGroupSetBitsFromISR(中斷)
xEventGroupSetBitsFromISR()是 xEventGroupSetBits()的中斷版本,用于置位事件組中指定的位。置位事件組中的標(biāo)志位是一個不確定的操作,因?yàn)樽枞谑录M的標(biāo)志位上的任務(wù)的個數(shù)是不確定的。FreeRTOS 是不允許不確定的操作在中斷和臨界段中發(fā)生的,所以 xEventGroupSetBitsFromISR() 給 FreeRTOS 的守護(hù)任務(wù)發(fā)送一個消息,讓置位事件組的操作在守護(hù)任務(wù)里面完成,守護(hù)任務(wù)是基于調(diào)度鎖而非臨界段的機(jī)制來實(shí)現(xiàn)的。需要注意的地方:正如上文提到的那樣,在中斷中事件標(biāo)志的置位是在守護(hù)任務(wù)(也叫軟件定時器服務(wù)任務(wù))中完成的。因此 FreeRTOS 的守護(hù)任務(wù)與其他任務(wù)一樣,都是系統(tǒng)調(diào)度器根據(jù)其優(yōu)先級進(jìn)行任務(wù)調(diào)度的,但守護(hù)任務(wù)的優(yōu)先級必須比任何任務(wù)的優(yōu)先級都要高,保證在需要的時候能立即切換任務(wù)從而達(dá)到快速處理的目的,因?yàn)檫@是在中斷中讓事件標(biāo)志位置位,其優(yōu)先級由 FreeRTOSConfig.h 中的宏 configTIMER_TASK_PRIORITY 來定義。
| 函數(shù) | BaseType_t xEventGroupSetBitsFromISR(EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet, BaseType_t *pxHigherPriorityTaskWoken) |
|---|---|
| 參數(shù) |
xEventGroup: 事件句柄 uxBitsToSet: 指定事件中的事件標(biāo)志位。如設(shè)置 uxBitsToSet 為 0x08 則只置位位 3,如果設(shè)置 uxBitsToSet 為 0x09 則位 3 和位 0 都需要被置位 pxHigherPriorityTaskWoken: pxHigherPriorityTaskWoken 在使用之前必須初始化成 pdFALSE。調(diào)用 xEventGroupSetBitsFromISR() 會給守護(hù)任務(wù)發(fā)送一個消息,如果守護(hù)任務(wù)的優(yōu)先級高于當(dāng)前被中斷的任務(wù)的優(yōu)先級的話(一般情況下都需要將守護(hù)任務(wù)的優(yōu)先級設(shè)置為所有任務(wù)中最高優(yōu)先級),pxHigherPriorityTaskWoken 會被置為 pdTRUE,然后在中斷退出前執(zhí)行一次上下文切換 |
| 返回值 | 消息成功發(fā)送給守護(hù)任務(wù)之后則返回 pdTRUE,否則返回 pdFAIL。如果定時器服務(wù)隊(duì)列滿了將返回 pdFAIL |
要想使用該函數(shù)必須在 FreeRTOSConfig.h 中把 configUSE_TIMERS 和 INCLUDE_xTimerPendFunctionCall 定義為 1 來使能。


同時把 FreeRTOS/source/event_groups.c 這個 C 文件添加到工程中。
3.5 xEventGroupWaitBits
用于獲取事件組中的一個或多個事件發(fā)生標(biāo)志,當(dāng)要讀取的事件標(biāo)志位沒有被置位時任務(wù)將進(jìn)入阻塞等待狀態(tài)。
| 函數(shù) | EventBits_t xEventGroupWaitBits(const EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToWaitFor, const BaseType_t xClearOnExit, const BaseType_t xWaitForAllBits, TickType_t xTicksToWait ) |
|---|---|
| 參數(shù) |
xEventGroup: 事件句柄 uxBitsToWaitFor: 一個按位或的值,指定需要等待事件組中的哪些位置 1。如果需要等待 bit 0 and/or bit 2 那么 uxBitsToWaitFor 配置為 0x05(0101b)。如果需要等待 bits 0 and/or bit 1 and/or bit 2 那么 uxBitsToWaitFor 配置為 0x07(0111b) xClearOnExit: pdTRUE:當(dāng) xEventGroupWaitBits()等待到滿足任務(wù)喚醒的事件時,系統(tǒng)將清除由形參 uxBitsToWaitFor 指定的事件標(biāo)志位。pdFALSE:不會清除由形參 uxBitsToWaitFor 指定的事件標(biāo)志位。 xWaitForAllBits: pdTRUE : 當(dāng) 形 參 uxBitsToWaitFor 指 定 的 位 都 置 位 的 時 候 ,xEventGroupWaitBits()才滿足任務(wù)喚醒的條件,這也是“邏輯與”等待事件,并且在沒有超時的情況下返回對應(yīng)的事件標(biāo)志位的值。pdFALSE:當(dāng)形參 uxBitsToWaitFor 指定的位有其中任意一個置位的時候,這也是常說的“邏輯或”等待事件,在沒有超時的情況下函數(shù)返回對應(yīng)的事件標(biāo)志位的值。 xTicksToWait: 最大超時時間,單位為系統(tǒng)節(jié)拍周期,常量 portTICK_PERIOD_MS 用于輔助把時間轉(zhuǎn)換成 MS |
| 返回值 | 返回事件中的哪些事件標(biāo)志位被置位,返回值很可能并不是用戶指定的事件位,需要對返回值進(jìn)行判斷再處理 |
3.6 xEventGroupClearBits(任務(wù))
用于清除事件組指定的位,如果在獲取事件的時候沒有將對應(yīng)的標(biāo)志位清除,那么就需要用這個函數(shù)來進(jìn)行顯式清除,xEventGroupClearBits() 函數(shù)不能在中斷中使用。
| 函數(shù) | EventBits_t xEventGroupClearBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToClear ) |
|---|---|
| 參數(shù) |
xEventGroup: 事件句柄 uxBitsToClear: 指定事件組中的哪個位需要清除。如設(shè)置 uxBitsToSet 為 0x08 則只清除位 3,如果設(shè)置 uxBitsToSet 為 0x09 則位 3 和位 0 都需要被清除 |
| 返回值 | 事件在還沒有清除指定位之前的值 |
3.7 xEventGroupClearBitsFromISR(中斷)
用于清除事件組指定的位,如果在獲取事件的時候沒有將對應(yīng)的標(biāo)志位清除,那么就需要用這個函數(shù)來進(jìn)行顯式清除。中斷清除事件標(biāo)志位的操作在守護(hù)任務(wù)(也叫定時器服務(wù)任務(wù))里面完成。守護(hù)進(jìn)程的優(yōu)先級 FreeRTOSConfig.h 中的宏 configTIMER_TASK_PRIORITY 來定義 。
| 函數(shù) | BaseType_t xEventGroupClearBitsFromISR(EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToClear ) |
|---|---|
| 參數(shù) |
xEventGroup: 事件句柄 uxBitsToClear: 指定事件組中的哪個位需要清除。如設(shè)置 uxBitsToSet 為 0x08 則只清除位 3,如果設(shè)置 uxBitsToSet 為 0x09 則位 3 和位 0 都需要被清除 |
| 返回值 | 事件在還沒有清除指定位之前的值 |
四、示例
4.1 任務(wù)式
/* FreeRTOS 頭文件 */
#include "FreeRTOS.h"
#include "task.h"
#include "event_groups.h"
/* 開發(fā)板硬件 bsp 頭文件 */
#include "bsp_led.h"
#include "bsp_usart.h"
#include "bsp_key.h"
/**************************** 任務(wù)句柄 ********************************/
/*
* 任務(wù)句柄是一個指針,用于指向一個任務(wù),當(dāng)任務(wù)創(chuàng)建好之后,它就具有了一個任務(wù)句柄
* 以后我們要想操作這個任務(wù)都需要通過這個任務(wù)句柄,如果是自身的任務(wù)操作自己,那么
* 這個句柄可以為 NULL。
*/
static TaskHandle_t AppTaskCreate_Handle = NULL;/* 創(chuàng)建任務(wù)句柄 */
static TaskHandle_t LED_Task_Handle = NULL;/* LED_Task 任務(wù)句柄 */
static TaskHandle_t KEY_Task_Handle = NULL;/* KEY_Task 任務(wù)句柄 */
/**************************** 內(nèi)核對象句柄 ****************************/
/*
* 信號量,消息隊(duì)列,事件標(biāo)志組,軟件定時器這些都屬于內(nèi)核的對象,要想使用這些內(nèi)核
* 對象,必須先創(chuàng)建,創(chuàng)建成功之后會返回一個相應(yīng)的句柄。實(shí)際上就是一個指針,后續(xù)我
* 們就可以通過這個句柄操作這些內(nèi)核對象。
*
* 內(nèi)核對象說白了就是一種全局的數(shù)據(jù)結(jié)構(gòu),通過這些數(shù)據(jù)結(jié)構(gòu)我們可以實(shí)現(xiàn)任務(wù)間的通信,
* 任務(wù)間的事件同步等各種功能。至于這些功能的實(shí)現(xiàn)我們是通過調(diào)用這些內(nèi)核對象的函數(shù)
* 來完成的
*
*/
static EventGroupHandle_t Event_Handle = NULL;
/************************** 宏定義 *********************************/
/*
* 當(dāng)我們在寫應(yīng)用程序的時候,可能需要用到一些宏定義。
*/
#define KEY1_EVENT (0x01 << 0)//設(shè)置事件掩碼的位 0
#define KEY2_EVENT (0x01 << 1)//設(shè)置事件掩碼的位 1
/*
*************************************************************************
* 函數(shù)聲明
*************************************************************************
*/
static void AppTaskCreate(void);/* 用于創(chuàng)建任務(wù) */
static void LED_Task(void* pvParameters);/* LED_Task 任務(wù)實(shí)現(xiàn) */
static void KEY_Task(void* pvParameters);/* KEY_Task 任務(wù)實(shí)現(xiàn) */
static void BSP_Init(void);/* 用于初始化板載相關(guān)資源 */
int main(void)
{
BaseType_t xReturn = pdPASS;/* 定義一個創(chuàng)建信息返回值,默認(rèn)為 pdPASS */
/* 開發(fā)板硬件初始化 */
BSP_Init();
/* 創(chuàng)建 AppTaskCreate 任務(wù) */
xReturn = xTaskCreate((TaskFunction_t )AppTaskCreate,/* 任務(wù)入口函數(shù) */
(const char* )"AppTaskCreate",/* 任務(wù)名字 */
(uint16_t )512, /* 任務(wù)棧大小 */
(void* )NULL,/* 任務(wù)入口函數(shù)參數(shù) */
(UBaseType_t )1, /* 任務(wù)的優(yōu)先級 */
(TaskHandle_t* )&AppTaskCreate_Handle);/*任務(wù)控制塊指針 */
/* 啟動任務(wù)調(diào)度 */
if (pdPASS == xReturn)
{
vTaskStartScheduler(); /* 啟動任務(wù),開啟調(diào)度 */
}
else
{
return -1;
}
while (1); /* 正常不會執(zhí)行到這里 */
}
/***********************************************************************
* @ 函數(shù)名 : AppTaskCreate
* @ 功能說明: 為了方便管理,所有的任務(wù)創(chuàng)建函數(shù)都放在這個函數(shù)里面
* @ 參數(shù) : 無
* @ 返回值 : 無
**********************************************************************/
static void AppTaskCreate(void)
{
BaseType_t xReturn = pdPASS;/* 定義一個創(chuàng)建信息返回值,默認(rèn)為 pdPASS */
taskENTER_CRITICAL(); //進(jìn)入臨界區(qū)
/* 創(chuàng)建 Event_Handle */
Event_Handle = xEventGroupCreate();
if (NULL != Event_Handle)
{
printf("Event_Handle 事件創(chuàng)建成功!\r\n");
}
/* 創(chuàng)建 LED_Task 任務(wù) */
xReturn = xTaskCreate((TaskFunction_t )LED_Task, /* 任務(wù)入口函數(shù) */
(const char* )"LED_Task",/* 任務(wù)名字 */
(uint16_t )512, /* 任務(wù)棧大小 */
(void* )NULL, /* 任務(wù)入口函數(shù)參數(shù) */
(UBaseType_t )2, /* 任務(wù)的優(yōu)先級 */
(TaskHandle_t* )&LED_Task_Handle);/* 任務(wù)控制塊指針 */
if (pdPASS == xReturn)
{
printf("創(chuàng)建 LED_Task 任務(wù)成功!\r\n");
}
/* 創(chuàng)建 KEY_Task 任務(wù) */
xReturn = xTaskCreate((TaskFunction_t )KEY_Task, /* 任務(wù)入口函數(shù) */
(const char* )"KEY_Task",/* 任務(wù)名字 */
(uint16_t )512, /* 任務(wù)棧大小 */
(void* )NULL,/* 任務(wù)入口函數(shù)參數(shù) */
(UBaseType_t )3, /* 任務(wù)的優(yōu)先級 */
(TaskHandle_t* )&KEY_Task_Handle);/* 任務(wù)控制塊指針 */
if (pdPASS == xReturn)
{
printf("創(chuàng)建 KEY_Task 任務(wù)成功!\n");\
}
vTaskDelete(AppTaskCreate_Handle); //刪除 AppTaskCreate 任務(wù)
taskEXIT_CRITICAL(); //退出臨界區(qū)
}
/**********************************************************************
* @ 函數(shù)名 : LED_Task
* @ 功能說明: LED_Task 任務(wù)主體
* @ 參數(shù) :
* @ 返回值 : 無
********************************************************************/
static void LED_Task(void* parameter)
{
EventBits_t r_event; /* 定義一個事件接收變量 */
/* 任務(wù)都是一個無限循環(huán),不能返回 */
while (1)
{
/*************************************************************
* 等待接收事件標(biāo)志
*
* 如果 xClearOnExit 設(shè)置為 pdTRUE,那么在 xEventGroupWaitBits()返回之前,
* 如果滿足等待條件(如果函數(shù)返回的原因不是超時),那么在事件組中設(shè)置
* 的 uxBitsToWaitFor 中的任何位都將被清除。
* 如果 xClearOnExit 設(shè)置為 pdFALSE,
* 則在調(diào)用 xEventGroupWaitBits()時,不會更改事件組中設(shè)置的位。
*
* xWaitForAllBits 如果 xWaitForAllBits 設(shè)置為 pdTRUE,則當(dāng) uxBitsToWaitFor 中
* 的所有位都設(shè)置或指定的塊時間到期時,xEventGroupWaitBits()才返回。
* 如果 xWaitForAllBits 設(shè)置為 pdFALSE,則當(dāng)設(shè)置 uxBitsToWaitFor 中設(shè)置的任何
* 一個位置 1 或指定的塊時間到期時,xEventGroupWaitBits()都會返回。
* 阻塞時間由 xTicksToWait 參數(shù)指定。
*********************************************************/
r_event = xEventGroupWaitBits(Event_Handle, /* 事件對象句柄 */
KEY1_EVENT|KEY2_EVENT,/* 接收任務(wù)感興趣的事件 */
pdTRUE, /* 退出時清除事件位 */
pdTRUE, /* 滿足感興趣的所有事件 */
portMAX_DELAY);/* 指定超時事件,一直等 */
if ((r_event & (KEY1_EVENT|KEY2_EVENT)) == (KEY1_EVENT|KEY2_EVENT))
{
/* 如果接收完成并且正確 */
printf ( "KEY1 與 KEY2 都按下\n");
LED1_TOGGLE; //LED1 反轉(zhuǎn)
}
else
{
printf ( "事件錯誤!\n");
}
}
}
/**********************************************************************
* @ 函數(shù)名 : KEY_Task
* @ 功能說明: KEY_Task 任務(wù)主體
* @ 參數(shù) :
* @ 返回值 : 無
********************************************************************/
static void KEY_Task(void* parameter)
{
/* 任務(wù)都是一個無限循環(huán),不能返回 */
while (1)
{
//如果 KEY2 被按下
if ( Key_Scan(KEY1_GPIO_PORT,KEY1_GPIO_PIN) == KEY_ON )
{
printf ( "KEY1 被按下\n" );
/* 觸發(fā)一個事件 1 */
xEventGroupSetBits(Event_Handle,KEY1_EVENT);
}
//如果 KEY2 被按下
if ( Key_Scan(KEY2_GPIO_PORT,KEY2_GPIO_PIN) == KEY_ON )
{
printf ( "KEY2 被按下\n" );
/* 觸發(fā)一個事件 2 */
xEventGroupSetBits(Event_Handle,KEY2_EVENT);
}
vTaskDelay(20); //每 20ms 掃描一次
}
}
/***********************************************************************
* @ 函數(shù)名 : BSP_Init
* @ 功能說明: 板級外設(shè)初始化,所有板子上的初始化均可放在這個函數(shù)里面
* @ 參數(shù) :
* @ 返回值 : 無
*********************************************************************/
static void BSP_Init(void)
{
/*
* STM32 中斷優(yōu)先級分組為 4,即 4bit 都用來表示搶占優(yōu)先級,范圍為:0~15
* 優(yōu)先級分組只需要分組一次即可,以后如果有其他的任務(wù)需要用到中斷,
* 都統(tǒng)一用這個優(yōu)先級分組,千萬不要再分組,切忌。
*/
NVIC_PriorityGroupConfig( NVIC_PriorityGroup_4 );
/* LED 初始化 */
LED_GPIO_Config();
/* 串口初始化 */
USART_Config();
/* 按鍵初始化 */
Key_GPIO_Config();
}
4.2 中斷式
#define BIT_0 ( 1 << 0 )
#define BIT_4 ( 1 << 4 )
/* 假定事件組已經(jīng)被創(chuàng)建 */
EventGroupHandle_t xEventGroup;
/* 中斷 ISR */
void anInterruptHandler( void )
{
BaseType_t xHigherPriorityTaskWoken, xResult;
/* xHigherPriorityTaskWoken 在使用之前必須先初始化為 pdFALSE */
xHigherPriorityTaskWoken = pdFALSE;
/* 置位事件組 xEventGroup 的的 Bit0 和 Bit4 */
xResult = xEventGroupSetBitsFromISR(xEventGroup, BIT_0 | BIT_4, &xHigherPriorityTaskWoken );
/* 信息是否發(fā)送成功 */
if ( xResult != pdFAIL )
{
/* 如果 xHigherPriorityTaskWoken 的值為 pdTRUE 則進(jìn)行一次上下文切換*/
portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
}
}
? 由 Leung 寫于 2020 年 11 月 24 日
? 參考:野火FreeRTOS視頻與PDF教程