1. 程式人生 > >2、FreeRTOS任務相關API函數

2、FreeRTOS任務相關API函數

ret get 相關 main eat 定時器 ref ati 安全

1.任務相關的API函數

函數存在於task.c中,主要的函數有:

  • xTaskCreate():使用動態的方法創建一個任務;
  • xTaskCreatStatic():使用靜態的方法創建一個任務(用的非常少);
  • xTaskCreateRestricted():創建一個使用MPU進行限制的任務;
  • vTaskDelete():刪除一個任務;
  • vTaskSuspend():掛起一個任務;
  • vTaskResume():恢復一個任務的運行;
  • vTaskResumeFromISR():中斷服務函數中恢復一個任務的運行;
  • portENABLE_INTERRUPTS():打開FreeRTOS中斷;
  • portDISABLE_INTERRUPTS():關閉freeRTOS中斷;

2.動態創建任務

  • xTaskCreate()函數原型:
     BaseType_t xTaskCreate(
                                  TaskFunction_t pvTaskCode,
                                  const char * const pcName,
                                  uint16_t usStackDepth,
                                  
    void *pvParameters, UBaseType_t uxPriority, TaskHandle_t *pvCreatedTask );
  • 動態創建任務:使用前先判斷 #if( configSUPPORT_STATIC_ALLOCATION == 1 ) 是否成立,如果不成立需要在FreeRTOSConfig.h 文件中添加;
    #include "FreeRTOS.h"
    #include "
    task.h" //start_task 任務 void start_task(void *pvParameters); // 任務函數 #define start_task_zise 50 // 任務堆棧的大小 #define start_task_prio 1 // 任務優先級 TaskHandle_t start_task_handler; // 任務句柄 //led1_task 任務 void led1_task(void *pvParameters); // 任務函數 #define led1_task_zise 50 // 任務堆棧的大小 #define led1_task_prio 2 // 任務優先級 TaskHandle_t led1_task_handler; // 任務句柄
    int main(void) { NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); uart_init(115200); delay_init(); LED_Init(); // 創建一個任務 xTaskCreate(任務函數, 任務名, 任務堆棧的大小, 傳遞給任務函數的參數, 任務優先級, 任務句柄); xTaskCreate( start_task, "start_stask", start_task_zise, NULL, start_task_prio, &start_task_handler); vTaskStartScheduler(); // 開啟任務調度 return 0; } void start_task( void * pvParameters ) { taskENTER_CRITICAL(); // 創建臨界區 // 創建led1任務 xTaskCreate(led1_task, "led1_task", start_task_zise, NULL, led1_task_prio, &led1_task_handler); vTaskDelete(start_task_handler); //刪除開始任務 taskEXIT_CRITICAL(); // 退出臨界區 } //LED1任務函數 void led1_task( void * pvParameters ) { for( ;; ) { LED0 = ~LED0; vTaskDelay(1000); } }

3.靜態創建任務

  • xTaskCreatStatic()函數原型:
    TaskHandle_t xTaskCreateStatic(    TaskFunction_t pxTaskCode,
                                        const char * const pcName,
                                        const uint32_t ulStackDepth,
                                        void * const pvParameters,
                                        UBaseType_t uxPriority,
                                        StackType_t * const puxStackBuffer,
                                        StaticTask_t * const pxTaskBuffer ) 
  • 靜態創建任務:使用前先判斷 #if( configSUPPORT_STATIC_ALLOCATION== 1 ) 是否成立,如果不成立需要在FreeRTOSConfig.h 文件中添加;
  • 在FreeRTOSConfig.h 文件中添加中添加宏後,編譯報錯:
    .\Objects\freeRTOS_sCreate_task.axf: Error: L6218E: Undefined symbol vApplicationGetIdleTaskMemory(referred from tasks.o).
    .\Objects\freeRTOS_sCreate_task.axf: Error: L6218E: Undefined symbol vApplicationGetTimerTaskMemory (referred from timers.o).
  • 由於把靜態創建的宏給打開了,所以這兩個數需要我們自己去實現
    // 空閑任務
    static StackType_t IdleTaskStack[configMINIMAL_STACK_SIZE];
    static StaticTask_t IdleTaskTCB;
    // 定時器任務
    static StackType_t TimerTaskStack[configTIMER_TASK_STACK_DEPTH];
    static StaticTask_t TimerTaskTCB;
    
    // 空閑任務所需內存
    void vApplicationGetIdleTaskMemory( StaticTask_t **ppxIdleTaskTCBBuffer, 
                                        StackType_t **ppxIdleTaskStackBuffer, 
                                        uint32_t *pulIdleTaskStackSize )
    {
        *ppxIdleTaskTCBBuffer = &IdleTaskTCB;
        *ppxIdleTaskStackBuffer = IdleTaskStack;
        *pulIdleTaskStackSize = configMINIMAL_STACK_SIZE;
    }
    // 定時器任務所需內存
    void vApplicationGetTimerTaskMemory( StaticTask_t **ppxTimerTaskTCBBuffer, 
                                        StackType_t **ppxTimerTaskStackBuffer, 
                                        uint32_t *pulTimerTaskStackSize )
    {
        *ppxTimerTaskTCBBuffer = &TimerTaskTCB;
        *ppxTimerTaskStackBuffer = TimerTaskStack;
        *pulTimerTaskStackSize = configTIMER_TASK_STACK_DEPTH;
    }
  • 靜態創建任務
    //start_task 任務
    void start_task(void *pvParameters);    // 任務函數
    #define start_task_zise 50                // 任務堆棧的大小
    #define start_task_prio 1                // 任務優先級
    StackType_t start_task_stack[start_task_zise];    // 任務控制塊大小
    StaticTask_t start_task_TCB;            // 任務堆棧大小
    TaskHandle_t start_task_handler;        // 任務句柄
    
    //led1_task 任務
    void led1_task(void *pvParameters);        // 任務函數
    #define led1_task_zise 50                // 任務堆棧的大小
    #define led1_task_prio 2                // 任務優先級
    StackType_t led1_task_stack[start_task_zise];    // 任務控制塊大小
    StaticTask_t led1_task_TCB;                // 任務堆棧大小
    TaskHandle_t led1_task_handler;            // 任務句柄
    
    //led2_task 任務
    void led2_task(void *pvParameters);        // 任務函數
    #define led2_task_zise 50                // 任務堆棧的大小
    #define led2_task_prio 3                // 任務優先級
    StackType_t led2_task_stack[start_task_zise];    // 任務控制塊大小
    StaticTask_t led2_task_TCB;                // 任務堆棧大小
    TaskHandle_t led2_task_handler;            // 任務句柄
    
    int main(void)
    {
        NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
        uart_init(115200);
        delay_init();
        LED_Init();
        
        // 創建一個開始任務
        start_task_handler = xTaskCreateStatic( (TaskFunction_t    )start_task,
                                                (char              *)"start_task",
                                                (uint32_t         )start_task_zise,
                                                (void *            )NULL,
                                                (UBaseType_t    )start_task_prio,
                                                (StackType_t *    )start_task_stack,    // 任務控制塊大小
                                                (StaticTask_t *    )&start_task_TCB );    // 任務堆棧大小
    
        vTaskStartScheduler();        // 開啟任務調度
        return 0;
    }
    
    void start_task( void * pvParameters )
    {
        led1_task_handler = xTaskCreateStatic( (TaskFunction_t    )led1_task,
                                                (char              *)"led1_task",
                                                (uint32_t         )led1_task_zise,
                                                (void *            )NULL,
                                                (UBaseType_t    )led1_task_prio,
                                                (StackType_t *    )led1_task_stack,    // 任務控制塊大小
                                                (StaticTask_t *    )&led1_task_TCB );    // 任務堆棧大小
                                                
        led2_task_handler = xTaskCreateStatic( (TaskFunction_t    )led2_task,
                                                (char              *)"led2_task",
                                                (uint32_t         )led2_task_zise,
                                                (void *            )NULL,
                                                (UBaseType_t    )led2_task_prio,
                                                (StackType_t *    )led2_task_stack,    // 任務控制塊大小
                                                (StaticTask_t *    )&led2_task_TCB );    // 任務堆棧大小
        vTaskDelete(start_task_handler);
    }
    void led1_task( void * pvParameters )
    {
        for( ;; )
        {
            LED0 = ~LED0;
            vTaskDelay(200);
        }
    }
    void led2_task( void * pvParameters )
    {
        for( ;; )
        {
            LED1 = ~LED1;
            vTaskDelay(1000);
        }
    }

4.刪除任務

  • void vTaskDelete( TaskHandle_t xTaskToDelete ) PRIVILEGED_FUNCTION;

5.任務掛起

  • void vTaskSuspend( TaskHandle_t xTaskToSuspend ) PRIVILEGED_FUNCTION;

6.任務恢復

  • void vTaskResume( TaskHandle_t xTaskToResume ) PRIVILEGED_FUNCTION;
  • 掛起、恢復代碼如下:
    //key_task 任務
    void key_task(void *pvParameters);        // 任務函數
    #define key_task_zise 50                // 任務堆棧的大小
    #define key_task_prio 4                // 任務優先級
    TaskHandle_t key_task_handler;            // 任務句柄
    
    void start_task( void * pvParameters )
    {
        taskENTER_CRITICAL();    // 創建臨界區
        
        // 創建按鍵檢查任務
        xTaskCreate((TaskFunction_t    )key_task,
                    (const char *     )"key_task",
                    (uint16_t        )key_task_zise,
                    (void *            )NULL,
                    (UBaseType_t    )key_task_prio,
                    (TaskHandle_t * )&key_task_handler);
            ......
        vTaskDelete(start_task_handler); //刪除開始任務
        taskEXIT_CRITICAL();    // 退出臨界區
    }
    
    //key任務函數 
    void key_task( void * pvParameters )
    {
        char key;
        for( ;; )
        {
            key = KEY_Scan(0);
            switch(key)
            {
                case KEY0_PRES:
                    vTaskSuspend(led1_task_handler);
                    printf("led1_task Suspended.\n");
                    break;
                case KEY1_PRES:
                    vTaskResume(led1_task_handler);
                    printf("led1_task Resumed.\n");
                    break;
                case KEY2_PRES:
                    vTaskSuspend(led2_task_handler);
                    printf("led2_task Suspended.\n");
                    break;
                case WKUP_PRES:
                    vTaskResume(led2_task_handler);
                    printf("led2_task Resumed.\n");
                    break;
            }
            vTaskDelay(10);            //延時10ms 
        }
    }

7.FreeRTOS開關中斷

  • freeRTOS管理的中斷優先級為 5~15,這是在freeRTOSConfig.h中設置的。
    #ifdef __NVIC_PRIO_BITS
        #define configPRIO_BITS               __NVIC_PRIO_BITS
    #else
        #define configPRIO_BITS               4                  
    #endif
    
    #define configLIBRARY_LOWEST_INTERRUPT_PRIORITY            15                      //中斷最低優先級
    #define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY    5                       //系統可管理的最高中斷優先級
    #define configKERNEL_INTERRUPT_PRIORITY         ( configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
    #define configMAX_SYSCALL_INTERRUPT_PRIORITY     ( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) 
  • 設置好宏後,低於configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY優先級的中斷可以安全的調用FreeRTOS的API函數(xxFromISR()函數);
  • 高於configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY優先級的中斷不能被FreeRTOS禁止,中斷服務函數也不能調用FreeRTOS的API函數。技術分享圖片
  • 由於高於configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY的優先級不會被FreeRTOS內核屏蔽,因此那些對實時性要求嚴格的任務可以使用這些優先級(0~4),比如四軸飛行器中的避障檢測;
    //start_task 任務
    void start_task(void *pvParameters);    // 任務函數
    #define start_task_zise 50                // 任務堆棧的大小
    #define start_task_prio 1                // 任務優先級
    TaskHandle_t start_task_handler;        // 任務句柄
    
    //interrupt_task 任務
    void interrupt_task(void *pvParameters);        // 任務函數
    #define interrupt_task_zise 50                // 任務堆棧的大小
    #define interrupt_task_prio 2                // 任務優先級
    TaskHandle_t interrupt_task_handler;            // 任務句柄
    
    int main(void)
    {
        NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
        uart_init(115200);
        delay_init();
        LED_Init();
        TIM3_Int_Init(10000-1,7200-1);    //設置定時器3的搶占優先級為 4
        TIM5_Int_Init(10000-1,7200-1);    //設置定時器5的搶占優先級為 5
        
        // 創建一個任務
        xTaskCreate((TaskFunction_t    )start_task,            // 任務函數    
                    (const char *     )"start_stask",            // 任務名    
                    (uint16_t        )start_task_zise,        // 任務堆棧的大小
                    (void *            )NULL,                    // 傳遞給任務函數的參數
                    (UBaseType_t    )start_task_prio,        // 任務優先級
                    (TaskHandle_t * )&start_task_handler);    // 任務句柄
        
        vTaskStartScheduler();        // 開啟任務調度
        return 0;
    }
    
    void start_task( void * pvParameters )
    {
        taskENTER_CRITICAL();    // 創建臨界區
        // 創建led1任務
        xTaskCreate((TaskFunction_t    )interrupt_task,
                    (const char *     )"interrupt_task",
                    (uint16_t        )interrupt_task_zise,
                    (void *            )NULL,
                    (UBaseType_t    )interrupt_task_prio,
                    (TaskHandle_t * )&interrupt_task_handler);
        
        // 創建led2任務            
    
        vTaskDelete(start_task_handler); //刪除開始任務
        taskEXIT_CRITICAL();    // 退出臨界區
    }
    //interrupt任務函數 
    void interrupt_task( void * pvParameters )
    {
        int i = 0;
        for( ;; )
        {
            if(i == 5)
            {
                printf("關閉中斷!!!.\n");
                portDISABLE_INTERRUPTS();
                delay_xms(5000);            // delay_xms執行的時候不會執行任何任務調度
                printf("開中斷!!!.\n");
                portENABLE_INTERRUPTS();
            }
            printf("interrupt task is %d runing.\n", i);
            LED0 = ~LED0;
            vTaskDelay(1000);
            i++;
        }
    }

8.臨界段

  • 臨界段是指:那些必須完整運行,不能被打斷的代碼段,比如有的外設的初始化需要嚴格的時序,初始化過程中不能被打斷。FreeRTOS在進入臨界段代碼的時候需要關閉中斷,當處理完臨界段代碼以後再打開中斷。
  • FreeRTOS中與臨界段有關的函數有4個,定義於task.h中:
    #define taskENTER_CRITICAL()        portENTER_CRITICAL()
    #define taskENTER_CRITICAL_FROM_ISR() portSET_INTERRUPT_MASK_FROM_ISR()
    
    #define taskEXIT_CRITICAL()            portEXIT_CRITICAL()
    #define taskEXIT_CRITICAL_FROM_ISR( x ) portCLEAR_INTERRUPT_MASK_FROM_ISR( x )
  • taskENTER_CRITICAL():進入任務級的臨界區;  
  • taskEXIT_CRITICAL():退出任務級的臨界區;
    void start_task( void * pvParameters )
    {
        taskENTER_CRITICAL();    // 進入臨界區
        // 創建led1任務
        xTaskCreate((TaskFunction_t    )interrupt_task,
                    (const char *     )"interrupt_task",
                    (uint16_t        )interrupt_task_zise,
                    (void *            )NULL,
                    (UBaseType_t    )interrupt_task_prio,
                    (TaskHandle_t * )&interrupt_task_handler);
        
        // 創建led2任務            
    
        vTaskDelete(start_task_handler); //刪除開始任務
        taskEXIT_CRITICAL();    // 退出臨界區
    }
  • taskEXIT_CRITICAL_FROM_ISR():進入中斷級臨界區;
  • taskENTER_CRITICAL_FROM_ISR():退出中斷級臨界區;
    //定時器3中斷服務程序
    void TIM3_IRQHandler(void)   //TIM3中斷
    {
        int status_value;
        if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET)      //檢查TIM3更新中斷發生與否
            {
                status_value = taskENTER_CRITICAL_FROM_ISR();    //進入臨界區
                printf("定時器3發生中斷.\n");
                LED1=!LED1;
                TIM_ClearITPendingBit(TIM3, TIM_IT_Update  );    //清除TIMx更新中斷標誌     
                taskEXIT_CRITICAL_FROM_ISR(status_value);    //退出臨界區
            }
    }
    
    //定時器3中斷服務程序
    void TIM5_IRQHandler(void)   //TIM3中斷
    {
        int status_value;
        if (TIM_GetITStatus(TIM5, TIM_IT_Update) != RESET)      //檢查TIM5更新中斷發生與否
            {    
                status_value = taskENTER_CRITICAL_FROM_ISR();    //進入臨界區
                printf("定時器5發生中斷.\n");
                LED1=!LED1;
                TIM_ClearITPendingBit(TIM5, TIM_IT_Update  );    //清除TIMx更新中斷標誌 
                taskEXIT_CRITICAL_FROM_ISR(status_value);    //退出臨界區
            }
    }

2、FreeRTOS任務相關API函數