FreeRTOS_事件標志組


FreeRTOS事件標志組

事件標志組簡介

1. 事件位(事件標志)

事件位用於表明某個事件是否發生,事件位通常用作事件標志,比如下面的幾個例子:

  當收到一條消息並且把這條消息處理掉以后就可以將某個位(標志)置1,當隊列中沒有消息需要處理的時候就可以將這個位(標志)置0。

  當把隊列中的消息通過網絡發送輸出以后就可以將某個位(標志)置1,當沒有數據需要從網絡發送出去的話就將這個位(標志)置0。

  現在需要向網絡中發送一個心跳信息,將某個位(標志)置1。現在不需要項網絡中發送心跳信息,這個位(標志)置0。

2. 事件組

一個事件組就是一組的事件位,事件組中的事件位通過位編號來訪問,同樣,以上面列出的三個例子為例:

  事件標志組bit0 表示隊列中的消息是否處理掉。

  事件標志組bit1 表示是否有纖細需要從網絡中發送出去。

  事件標志組bit2 表示現在是否需要向網路發送心跳信息。

3. 事件標志組和事件位的數據類型

  事件標志組的數據類型為 EventBits_t,當configUSE_16_BIT_TICKS為1的時候,事件標志組可以存儲8個事件位,當configUSE_16_BIT_TICKS為0的時候,事件標志組存儲24個事件位。

  事件標志組中所有事件位都存儲在一個無符號的EventBits_t類型的變量中,EventBits_t在event_groups.h中有如下定義:

typedef TickType_t EventBits_t;

  數據類型TickType_t在文件portmacro.h中有如下定義:

#if( configUSE_16_BIT_TICKS == 1 )
    typedef uint16_t TickType_t;
    #define portMAX_DELAY ( TickType_t ) 0xffff
#else
    typedef uint32_t TickType_t;
    #define portMAX_DELAY ( TickType_t ) 0xffffffffUL

    /* 32-bit tick type on a 32-bit architecture, so reads of the tick count do
    not need to be guarded with a critical section. */
    #define portTICK_TYPE_IS_ATOMIC 1
#endif

  可以看出當 configUSE_16_BIT_TICKS 為0的時候,TickType_t是個32位的數據類型,因此EventBits_t也是個32位的數據類型。EventBits_t類型的變量可以存儲24個事件位,另外的那高8位有其他用。事件位0存放在這個變量的bit0上,變量的bit1就是事件位1,以此類推。對於STM32來說,一個事件標志組最多可以存儲24個事件位,如下圖:

 

創建事件標志組

   FreeRTOS提供了兩個用於創建事件標志組的函數:

函數 描述
xEventGroupCreate() 使用動態方法創建事件標志組
xEventGroupCreateStatic() 使用靜態方法創建事件標志組

1. 函數 xEventGroupCreate()

  此函數用於創建一個時間標志組,鎖需要的內存通過動態內存管理方法分配。由於內部處理的原因,事件標志組可用的bit數取決於configUSE_16_BIT_TICKS,當configUSE_16_BIT_TICKS為1的時候,事件標志組有8個可用的位(bit0~bit7),當configUSE_16_BIT_TICKS為0的時候,時間標志組有24個可用的位(bit0~bit23)。EventBits_t類型的變量用來存儲事件標志組中的各個事件位,函數原型如下:

EventGroupHandle_t xEventGroupCreate( void )

參數:

  無。

返回值:

  NULL:事件標志組創建失敗。

  其他值:創建成功的事件標志組句柄。

2. 函數xEventGroupCreateStatic()

此函數用於創建一個事件標志組,所需要的內存需要用於自行分配,此函數原型如下:

EventGroupHandle_t xEventGroupCreateStatic( StaticEventGroup_t *pxEventGroupBuffer )

參數:

  pxEventGroupBuffer:參數指向一個StaticEventGroup_t類型的變量,用來保存時間組結構體。

返回值:

  NULL:事件標志組創建失敗。

  其他值:創建成功的事件標志組句柄。

 

設置事件位

  FreeRTOS提供了4個函數用來設置事件標志組中事件位(標志),事件位的設置包括清零和置1兩種操作:

函數 描述
xEventGroupClearBits() 將指定的事件位清零,用在任務中。
xEventGroupClearBitsFromISR() 將指定的事件位清零,用在中斷服務函數中。
xEventGroupSetBits() 將指定的事件位置1,用在任務中。
xEventGroupSetBitsFromISR() 將指定的事件位置1,用在中斷服務函數中。

1. 函數 xEventGroupClearBits()

  將事件標志組中指定事件位清零,此函數只能用在任務中,不能用在中斷服務函數中,中斷服務函數中有其他的API函數。函數原型如下:

EventBits_t xEventGroupClearBits( EventGroupHandle_t xEventGroup, 
const EventBits_t uxBitsToClear )

參數:

  xEventGroup:要操作的事件標志組的句柄。

  uxBitsToClear:要清零的事件位,比如要清除bit3的話就設置為0x08。可以同時清除多個bit,如設置0x09的話就是同時清除bit3和bit0。

返回值:

  任何值:將指定事件位清零之前的事件組值。

2. 函數xEventGroupClearBitsFromISR()

  此函數為xEventGroupClearBits()的中斷級版本,也是將指定的事件位(標志)清零。此函數用在中斷服務函數中,函數原型如下:

BaseType_t xEventGroupClearBitsFromISR( EventGroupHandle_t xEventGroup, 
const EventBits_t uxBitsToSet )

參數:

  xEventGroup:要操作的事件標志組的句柄。

  uxBitsToClear:要清零的事件位,比如要清除bit3的話就設置為0x08。可以同時清除多個bit,如設置0x09的話就是同時清除bit3和bit0。

返回值:

  pdPASS:事件位清零成功。

  pdFALSE:事件位清零失敗。

 

3. 函數 xEventGroupSetBits()

  設置指定的事件位為1,此函數只能用在任務中,不能用於中斷服務函數。此函數原型如下:

EventBits_t xEventGroupSetBits( EventGroupHandle_t xEventGroup, 
const EventBits_t uxBitsToSet )

參數:

  xEventGroup:要操作的事件標志組句柄。

  uxBitsToSet:指定要置1的事件位,比如要將bit3 置1的話就設置為0x08。可以同時將多個bit置1,如設置為0x09的話就是同時將bit3和bit0置1。

返回值:

  任何值:在將指定事件位置1后的事件組值。

 

3. 函數xEventGroupSetBitsFromISR()

  此函數也用於將指定事件位置1,此函數是xEventGroupSetBits()的中斷版本,用在中斷服務函數中,函數原型如下:

BaseType_t xEventGroupSetBitsFromISR( EventGroupHandle_t xEventGroup, 
const EventBits_t uxBitsToSet,
BaseType_t *pxHigherPriorityTaskWoken )

參數:

  xEventGroup:要操作的事件標志組的句柄。

  uxBitsToClear:指定要置1的事件位,比如要將bit3置1的話就設置0x08。可以同時將多個bit置1,如設置為0x09的話就是同時將bit3和bit0置1。

  pxHigherPriorityTaskWoken:標記退出此函數以后是否進行任務切換。這個變量的值,函數會自動設置,用戶不用進行設置,用戶只需要提供一個變量來保存這個值就行了。當此值為pdTRUE的時候在退出中斷服務函數之前一定要進行一次任務切換。

返回值:

  pdPASS:事件位置1成功。

  pdFALSE:事件位置1失敗。

 

獲取事件標志組值

  我們可以通過FreeRTOS提供的API函數來查詢事件標志組值。FreeRTOS一共提供了兩個這樣的API函數。

函數 描述
xEventGroupGetBits() 獲取當前事件標志組的值(各個事件位的值),用在任務中
xEventGroupGetBitsFromISR() 獲取當前事件標志組的值,用在中斷服務函數中。

 

1. 函數xEventGroupGetBits()

  此函數用於獲取當前事件標志組的值,也就是各個事件位的值。此函數用在任務中,不能用在中斷服務函數中。此函數是個宏,真正執行的事函數xEventGroupClearBits(),函數原型如下:

EventBits_t xEventGroupGetBits( EventGroupHandle_t xEventGroup )

參數:

  xEventGroup:要獲取的事件標志組的句柄。

返回值:

  任何值:當前時間標志組的值。

 

2. 函數xEventGroupGetBitsFromISR()

  獲取當前事件標志組的值,此函數是xEventGroupGetBits()的中斷版本,函數原型如下:

EventBits_t xEventGroupGetBitsFromISR( EventGroupHandle_t xEventGroup )

參數:

  xEventGroup:要獲取的事件標志組的句柄。

返回值:

  任何值:當前事件標志組的值。

 

等待指定的事件位

  某個任務可能需要與多個事件進行同步,那么這個任務就需要等待並判斷多個事件位(標志),使用函數 xEventGroupWaitBits()可以完成這個功能。調用函數以后如果任務要等待的事件位還沒有准備好(置1或清零)的話任務就會進入阻塞態,直到阻塞時間達到或者所等待的事件位准備好。函數原型如下:

EventBits_t xEventGroupWaitBits( EventGroupHandle_t xEventGroup, 
const EventBits_t uxBitsToWaitFor,
const BaseType_t xClearOnExit,
const BaseType_t xWaitForAllBits,
TickType_t xTicksToWait )

參數:

  xEventGroup:指定要等待的事件標志組。

  uxBitsToWaitFor:指定要等待的事件位,比如要等待bit0和(或)bit2的時候,此參數就是0x05,如果要等待bit0和(或)bit1和(或)bit2的時候此函數就是0x07,以此類推。

  xClearOnExit:此參數要是pdTRUE的話,那么在退出此函數之前有由參數uxBitsToWaitFor所設置的這些事件位就會清零。如果設置為pdFALSE的話這些事件位就不會改變。

  xWaitForAllBits:此參數如果設置為pdTRUE的話,當uxBitsToWaitFor所設置的這些事件位都置1,或者指定的阻塞時間到的時候函數xEventGroupWaitBits()才會返回。當此參數為pdFALSE的話,只要uxBitsToWaitFor所設置的這些事件位其中的任意一個置1,或者指定的阻塞時間到的話函數xEventGroupWaitBits()就會返回。

  xTicksToWait:設置阻塞時間,單位為節拍數。

返回值:

  任何值:返回當所等待的事件位置1以后的事件標志組的值,或者阻塞時間到。根據這個值我們就知道哪些事件位置1了。如果函數因為阻塞時間到而返回的話,那么這個返回值就不代表任何的含義。

 

事件標志組實驗

創建事件標志組、將相應的事件位置1、等待相應事件位置1的操作。

 

實驗設置三個任務:start_task、eventsetbit_task、eventgroup_task。

start_task:用來創建其他兩個任務,創建時間標志組。

eventsetbit_task:通過不同按鍵值,將事件標志組中相應事件位置1。

eventgroup_task:等待事件標志組中的事件位,當這些事件位都置1,執行相應的處理。

 

EventGroupHandler:創建的事件標志組句柄。使用事件標志組的事件位:bit0 bit1 bit2

 

任務分配:

//任務優先級
#define START_TASK_PRIO        1
//任務堆棧大小    
#define START_STK_SIZE         128  
//任務句柄
TaskHandle_t StartTask_Handler;
//任務函數
void start_task(void *pvParameters);

//任務優先級
#define EVENTSETBIT_TASK_PRIO        2
//任務堆棧大小    
#define EVENTSETBIT_STK_SIZE         50  
//任務句柄
TaskHandle_t EventSetbitTask_Handler;
//任務函數
void eventsetbit_task(void *pvParameters);

//任務優先級
#define EVENTGROUP_TASK_PRIO        3
//任務堆棧大小    
#define EVENTGROUP_STK_SIZE         50  
//任務句柄
TaskHandle_t EventGroupTask_Handler;
//任務函數
void eventgroup_task(void *pvParameters);

EventGroupHandle_t EventGroupHandle;    // 事件標志組句柄

// 定義事件位
#define BIT_0    (1<<0)
#define BIT_1    (1<<1)
#define BIT_2    (1<<2)

 

main() 函數:

int main(void)
{
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//設置系統中斷優先級分組4     
    delay_init();                        //延時函數初始化      
    uart_init(115200);                    //初始化串口
    LED_Init();                              //初始化LED
    KEY_Init();                            // 初始化按鍵
     
    //創建開始任務
    xTaskCreate((TaskFunction_t )start_task,            //任務函數
                (const char*    )"start_task",          //任務名稱
                (uint16_t       )START_STK_SIZE,        //任務堆棧大小
                (void*          )NULL,                  //傳遞給任務函數的參數
                (UBaseType_t    )START_TASK_PRIO,       //任務優先級
                (TaskHandle_t*  )&StartTask_Handler);   //任務句柄              
    vTaskStartScheduler();          //開啟任務調度
}

 

任務函數:

//開始任務任務函數
void start_task(void *pvParameters)
{
    taskENTER_CRITICAL();           //進入臨界區
    
    EventGroupHandle =  xEventGroupCreate();            // 創建事件標志組
    if(EventGroupHandle == NULL)
    {
        printf("EventGroup Create Failed!\r\n");
    }
    
    //創建eventsetbit任務
    xTaskCreate((TaskFunction_t )eventsetbit_task,         
                (const char*    )"eventsetbit_task",       
                (uint16_t       )EVENTSETBIT_STK_SIZE, 
                (void*          )NULL,                
                (UBaseType_t    )EVENTSETBIT_TASK_PRIO,    
                (TaskHandle_t*  )&EventSetbitTask_Handler);   
    //創建eventgroup任務
    xTaskCreate((TaskFunction_t )eventgroup_task,     
                (const char*    )"eventgroup_task",   
                (uint16_t       )EVENTGROUP_STK_SIZE, 
                (void*          )NULL,
                (UBaseType_t    )EVENTGROUP_TASK_PRIO,
                (TaskHandle_t*  )&EventGroupTask_Handler);         
    vTaskDelete(StartTask_Handler); //刪除開始任務
    taskEXIT_CRITICAL();            //退出臨界區
}

//eventsetbit_task任務函數 
void eventsetbit_task(void *pvParameters)
{
    u8 key = 0;
    
    while(1)
    {
        key = KEY_Scan(0);
        switch(key)
        {
            case KEY1_PRES:
                if(EventGroupHandle != NULL)
                {
                    xEventGroupSetBits(EventGroupHandle,BIT_0);    // 設置事件標志組 BIT_0 置1
                }
                break;
            case KEY2_PRES:
                if(EventGroupHandle != NULL)
                {
                    xEventGroupSetBits(EventGroupHandle,BIT_1);    // 設置事件標志組 BIT_0 置1
                }
                break;
        }
        vTaskDelay(10);
    }
}   

//eventgroup_task任務函數
void eventgroup_task(void *pvParameters)
{
    EventBits_t EventBitsVal = 0;
    
    while(1)
    {
        if(EventGroupHandle != NULL)
        {
            EventBitsVal = xEventGroupWaitBits(
                                                EventGroupHandle,        // 要等待的事件標志組
                                                (BIT_0|BIT_1),            // 等待的事件位
                                                pdTRUE,                    // 清零
                                                pdFALSE,                // 只要事件位其一得到就退出
                                                portMAX_DELAY );        // 死等
            
            printf("EventBitsVal = %#x\r\n",EventBitsVal);
        }else{
            vTaskDelay(10);
        }
        
    }
}

 

運行結果:

按下KEY1,輸出 EventBitsVal = 0x1

按下KEY2,輸出  EventBitsVal = 0x2

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM