2、FreeRTOS任務相關API函數
阿新 • • 發佈:2018-04-01
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,
- 動態創建任務:使用前先判斷 #if( configSUPPORT_STATIC_ALLOCATION == 1 ) 是否成立,如果不成立需要在FreeRTOSConfig.h 文件中添加;
#include "FreeRTOS.h" #include "
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函數