FreeRTOS學(xué)習(xí)筆記(6)——事件

一、頭文件

#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_TIMERSINCLUDE_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教程

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容