您好,登錄后才能下訂單哦!
這篇文章主要介紹“FreeRTOS實時操作系統空閑任務的阻塞延時怎么實現”的相關知識,小編通過實際案例向大家展示操作過程,操作方法簡單快捷,實用性強,希望這篇“FreeRTOS實時操作系統空閑任務的阻塞延時怎么實現”文章能幫助大家解決問題。
RTOS中的延時叫阻塞延時,即任務需要延時時,任務會放棄cpu使用權,cpu轉而去做其他的事,當任務延時時間到后,任務重新請求獲得cpu使用權。
但當所有的任務都處于阻塞后,為了不讓cpu空閑沒事干就需要一個空閑任務讓cpu干活。
空閑任務實現和創建普通任務沒區別,空閑任務在調用vTaskStartScheduler
函數內部創建,如下
//定義空閑棧 #define configMINIMAL_STACK_SIZE ( ( unsigned short ) 128 ) StackType_t IdleTaskStack[configMINIMAL_STACK_SIZE]; //空閑任務任務控制塊 TCB_t IdleTaskTCB; //設置空閑任務的參數 void vApplicationGetIdleTaskMemory( TCB_t **ppxIdleTaskTCBBuffer, StackType_t **ppxIdleTaskStackBuffer, uint32_t *pulIdleTaskStackSize ) { *ppxIdleTaskTCBBuffer=&IdleTaskTCB; *ppxIdleTaskStackBuffer=IdleTaskStack; *pulIdleTaskStackSize=configMINIMAL_STACK_SIZE; } void vTaskStartScheduler(void) { TCB_t *pxIdleTaskTCBBuffer = NULL;//空閑任務控制塊指針 StackType_t *pxIdleTaskStackBuffer = NULL;//空閑任務棧指針 uint32_t ulIdleTaskStackSize; //空閑任務棧大小 //設置空閑任務參數 vApplicationGetIdleTaskMemory(&pxIdleTaskTCBBuffer, &pxIdleTaskStackBuffer, &ulIdleTaskStackSize); //創建空閑任務 xIdleTaskHandle = xTaskCreateStatic((TaskFunction_t)prvIdleTask, (char *)"IDLE", (uint32_t)ulIdleTaskStackSize, (void*)NULL, (StackType_t*)pxIdleTaskStackBuffer, (TCB_t*)pxIdleTaskTCBBuffer); //將空閑任務添加到就緒列表 vListInsertEnd(&(pxReadyTasksLists[0]),&(((TCB_t *)pxIdleTaskTCBBuffer)->xStateListItem)); //手動指定第一個要運行的任務 pxCurrentTCB = &Task1TCB; //啟動調度器 if(xPortStartScheduler()!=pdFALSE) { //啟動成功則不會運行到這里 } }
阻塞延時需要用xTicksToDelay
,這個時TCB中的一個成員,用于記錄還要阻塞多久。
typedef struct tskTaskControlBlock { volatile StackType_t * pxTopOfStack; ListItem_t xStateListItem; StackType_t * pxStack; · char pcTaskName[configMAX_TASK_NAME_LEN]; TickType_t xTicksToDelay; //用于延時 }tskTCB;
所以阻塞延時就是這樣實現
void vTaskDelay(const TickType_t xTicksToDelay) { TCB_t *pxTCB = NULL; pxTCB = pxCurrentTCB; //設置延時時間 pxTCB->xTicksToDelay = xTicksToDelay; //進行一次任務切換 taskYIELD(); }
由于引入了阻塞延時,所以任務切換函數需要改寫,因為當所有任務阻塞后,需要切換至空閑任務運行
void vTaskSwitchContext( void ) { //如果當前時空閑任務,嘗試去執行任務1或任務2,如果他們延時時間都沒到則繼續執行空閑任務 if( pxCurrentTCB == &IdleTaskTCB ) { if(Task1TCB.xTicksToDelay == 0) { pxCurrentTCB =&Task1TCB; } else if(Task2TCB.xTicksToDelay == 0) { pxCurrentTCB =&Task2TCB; } else { return; } } else //當前任務不是空閑任務會執行到這里 { //當前任務時任務1或任務2的話,檢查另一個任務 //如果另外的任務不在延時中,會切換到該任務 //否則,判斷當前任務是否在延時中,是則切換到空閑任務, //否則,不進行任何切換 if (pxCurrentTCB == &Task1TCB) { if (Task2TCB.xTicksToDelay == 0) { pxCurrentTCB =&Task2TCB; } else if (pxCurrentTCB->xTicksToDelay != 0) { pxCurrentTCB = &IdleTaskTCB; } else { return; } } else if (pxCurrentTCB == &Task2TCB) { if (Task1TCB.xTicksToDelay == 0) { pxCurrentTCB =&Task1TCB; } else if (pxCurrentTCB->xTicksToDelay != 0) { pxCurrentTCB = &IdleTaskTCB; } else { return; } } } }
vTaskDelay中設置了xTicksToDelay成員后,是通過SystTick中斷來實現遞減操作的
void xPortSysTickHandler( void ) { int x = portSET_INTERRUPT_MASK_FROM_ISR(); xTaskIncrementTick(); portCLEAR_INTERRUPT_MASK_FROM_ISR(x); } void xTaskIncrementTick( void ) { TCB_t *pxTCB = NULL; BaseType_t i = 0; const TickType_t xConstTickCount = xTickCount + 1; xTickCount = xConstTickCount; for (i=0; i<configMAX_PRIORITIES; i++) { pxTCB = ( TCB_t * ) listGET_OWNER_OF_HEAD_ENTRY( ( &pxReadyTasksLists[i] ) ); if (pxTCB->xTicksToDelay > 0) { pxTCB->xTicksToDelay --; //這里遞減 } } portYIELD(); }
//systick控制寄存器 #define portNVIC_SYSTICK_CTRL_REG (*((volatile uint32_t *) 0xe000e010 )) //systick重裝載寄存器 #define portNVIC_SYSTICK_LOAD_REG (*((volatile uint32_t *) 0xe000e014 )) //systick時鐘源選擇 #ifndef configSYSTICK_CLOCK_HZ #define configSYSTICK_CLOCK_HZ configCPU_CLOCK_HZ #define portNVIC_SYSTICK_CLK_BIT ( 1UL << 2UL ) #else #define portNVIC_SYSTICK_CLK_BIT ( 0 ) #endif #define portNVIC_SYSTICK_INT_BIT ( 1UL << 1UL ) #define portNVIC_SYSTICK_ENABLE_BIT ( 1UL << 0UL ) void vPortSetupTimerInterrupt( void ) { //重裝載計數器值 portNVIC_SYSTICK_LOAD_REG = ( configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ ) - 1UL; //設置systick時鐘使用內核時鐘 //使能systick定時器中斷 //使能systick定時器 portNVIC_SYSTICK_CTRL_REG = ( portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT | portNVIC_SYSTICK_ENABLE_BIT ); }
在FreeRTOSConfig.h
中
#define configCPU_CLOCK_HZ (( unsigned long ) 25000000) #define configTICK_RATE_HZ (( TickType_t ) 100)
configSYSTICK_CLOCK_HZ是沒有定義的,所以configSYSTICK_CLOCK_HZ使用的是configCPU_CLOCK_HZ
portCHAR flag1; portCHAR flag2; TaskHandle_t Task1_Handle; StackType_t Task1Stack[128]; TCB_t Task1TCB; TaskHandle_t Task2_Handle; StackType_t Task2Stack[128]; TCB_t Task2TCB; void Task1_Fntry(void *arg) { while(1) { flag1=1; vTaskDelay( 2 ); flag1=0; vTaskDelay( 2 ); } } void Task2_Fntry(void *arg) { while(1) { flag2=1; vTaskDelay( 2 ); flag2=0; vTaskDelay( 2 ); } } int main(void) { prvInitialiseTaskLists(); Task1_Handle = xTaskCreateStatic(Task1_Fntry,"task1",128,NULL,Task1Stack,&Task1TCB); vListInsertEnd(&pxReadyTasksLists[1],&((&Task1TCB)->xStateListItem)); Task2_Handle = xTaskCreateStatic(Task2_Fntry,"task2",128,NULL,Task2Stack,&Task2TCB); vListInsertEnd(&pxReadyTasksLists[2],&((&Task2TCB)->xStateListItem)); vTaskStartScheduler(); for(;;) {} }
可以看到2個task是同步運行的,且延時是20ms
關于“FreeRTOS實時操作系統空閑任務的阻塞延時怎么實現”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識,可以關注億速云行業資訊頻道,小編每天都會為大家更新不同的知識點。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。