想著做個輪腿的機器人玩玩,但是如果光用PID做演算法,對於輪子加腿的結構似乎效果並不好,為了實現輪腿本身能夠飛坡在一定高度下能夠跳躍,我想著上個模擬模型來調試和學習LQR演算法 機器人模擬的軟體似乎挺多,我查到比較常用的有ROS套件的一個,還有就是webots 本著界面簡單,開源(還有校園網方便下載)的 ...
4.2.13 繼續任務--vTaskResume
介面:
void vTaskResume( TaskHandle_t xTaskToResume )
形參1:xTaskToResume ,想要繼續的任務handle;
首先是vTaskResume調用的一個內部函數:static BaseType_t prvTaskIsTaskSuspended( const TaskHandle_t xTask ),用於檢查任務是否是掛起狀態,只有掛起的任務才能繼續,否則是等待事件、通知等處於阻塞態,那就不能放到就緒列表,必須繼續等待。這個介面邏輯非常簡單,就直接看代碼即可。
1 static BaseType_t prvTaskIsTaskSuspended( const TaskHandle_t xTask ) 2 { 3 BaseType_t xReturn = pdFALSE; 4 const TCB_t * const pxTCB = xTask; 5 6 /* Accesses xPendingReadyList so must be called from a critical 7 * section. */ 8 9 /* It does not make sense to check if the calling task is suspended. */ 10 configASSERT( xTask ); 11 12 /* Is the task being resumed actually in the suspended list? */ 13 /* 檢查任務是否在掛起列表, 不在則說明任務未掛起 */ 14 if( listIS_CONTAINED_WITHIN( &xSuspendedTaskList, &( pxTCB->xStateListItem ) ) != pdFALSE ) 15 { 16 /* Has the task already been resumed from within an ISR? */ 17 /* 任務在掛起列表裡, 但在調度器暫停時被移至等待就緒列表中, 則說明任務未掛起 */ 18 if( listIS_CONTAINED_WITHIN( &xPendingReadyList, &( pxTCB->xEventListItem ) ) == pdFALSE ) 19 { 20 /* Is it in the suspended list because it is in the Suspended 21 * state, or because it is blocked with no timeout? */ 22 /* 任務在掛起列表裡, 但在等待事件, 則說明任務未掛起 */ 23 if( listIS_CONTAINED_WITHIN( NULL, &( pxTCB->xEventListItem ) ) != pdFALSE ) 24 { 25 #if ( configUSE_TASK_NOTIFICATIONS == 1 ) 26 { 27 BaseType_t x; 28 29 /* The task does not appear on the event list item of 30 * and of the RTOS objects, but could still be in the 31 * blocked state if it is waiting on its notification 32 * rather than waiting on an object. If not, is 33 * suspended. */ 34 /* 任務在掛起列表裡, 且未等待事件, 那麼如果在等待通知則未掛起, 否則掛起 */ 35 xReturn = pdTRUE; 36 37 for( x = ( BaseType_t ) 0; x < ( BaseType_t ) configTASK_NOTIFICATION_ARRAY_ENTRIES; x++ ) 38 { 39 if( pxTCB->ucNotifyState[ x ] == taskWAITING_NOTIFICATION ) 40 { 41 xReturn = pdFALSE; 42 break; 43 } 44 } 45 } 46 #else /* if ( configUSE_TASK_NOTIFICATIONS == 1 ) */ 47 { 48 xReturn = pdTRUE; 49 } 50 #endif /* if ( configUSE_TASK_NOTIFICATIONS == 1 ) */ 51 } 52 else 53 { 54 mtCOVERAGE_TEST_MARKER(); 55 } 56 } 57 else 58 { 59 mtCOVERAGE_TEST_MARKER(); 60 } 61 } 62 else 63 { 64 mtCOVERAGE_TEST_MARKER(); 65 } 66 67 /* 總結下來就是任務若在掛起列表裡, 如果不是在等待事件或通知, 則是掛起狀態, 否則不是 */ 68 69 return xReturn; 70 }prvTaskIsTaskSuspended
1 void vTaskResume( TaskHandle_t xTaskToResume ) 2 { 3 TCB_t * const pxTCB = xTaskToResume; 4 5 /* It does not make sense to resume the calling task. */ 6 configASSERT( xTaskToResume ); 7 8 #if ( configNUMBER_OF_CORES == 1 ) 9 /* The parameter cannot be NULL as it is impossible to resume the 10 * currently executing task. */ 11 if( ( pxTCB != pxCurrentTCB ) && ( pxTCB != NULL ) ) 12 #endif 13 { 14 taskENTER_CRITICAL(); 15 { 16 if( prvTaskIsTaskSuspended( pxTCB ) != pdFALSE ) 17 { 18 /* The ready list can be accessed even if the scheduler is 19 * suspended because this is inside a critical section. */ 20 /* 只有任務處於掛起狀態才能繼續 */ 21 ( void ) uxListRemove( &( pxTCB->xStateListItem ) ); 22 prvAddTaskToReadyList( pxTCB ); 23 24 /* This yield may not cause the task just resumed to run, 25 * but will leave the lists in the correct state for the 26 * next yield. */ 27 /* 保證各任務列表處於正常的狀態 */ 28 taskYIELD_ANY_CORE_IF_USING_PREEMPTION( pxTCB ); 29 } 30 else 31 { 32 mtCOVERAGE_TEST_MARKER(); 33 } 34 } 35 taskEXIT_CRITICAL(); 36 } 37 else 38 { 39 mtCOVERAGE_TEST_MARKER(); 40 } 41 }vTaskResume
4.2.14 啟動調度--vTaskStartScheduler
這個介面會創建空閑任務和軟定時器任務,之後就是允許第一個任務,這個介面永遠也不會返回,也是main中調用的最後一個介面。
1 void vTaskStartScheduler( void ) 2 { 3 BaseType_t xReturn; 4 5 /* 創建空閑任務 */ 6 xReturn = prvCreateIdleTasks(); 7 8 #if ( configUSE_TIMERS == 1 ) 9 { 10 if( xReturn == pdPASS ) 11 { 12 xReturn = xTimerCreateTimerTask(); // 創建軟定時器任務 13 } 14 else 15 { 16 mtCOVERAGE_TEST_MARKER(); 17 } 18 } 19 #endif /* configUSE_TIMERS */ 20 21 if( xReturn == pdPASS ) 22 { 23 /* Interrupts are turned off here, to ensure a tick does not occur 24 * before or during the call to xPortStartScheduler(). The stacks of 25 * the created tasks contain a status word with interrupts switched on 26 * so interrupts will automatically get re-enabled when the first task 27 * starts to run. */ 28 /* 關閉中斷, 保證在調用xPortStartScheduler前不會發生tick中斷, 所有創建 29 * 的任務的棧中都包含一個中斷開啟的狀態字, 所以第一個任務運行時, 中斷 30 * 會自動開啟 */ 31 /* 暫時沒看懂這個註釋的意思, 但這個介面只是設置了中斷優先順序屏蔽寄存器, 32 * 實際的中斷並未關閉, 系統中斷被屏蔽了 */ 33 portDISABLE_INTERRUPTS(); 34 35 xNextTaskUnblockTime = portMAX_DELAY; 36 xSchedulerRunning = pdTRUE; 37 xTickCount = ( TickType_t ) configINITIAL_TICK_COUNT; 38 39 /* If configGENERATE_RUN_TIME_STATS is defined then the following 40 * macro must be defined to configure the timer/counter used to generate 41 * the run time counter time base. NOTE: If configGENERATE_RUN_TIME_STATS 42 * is set to 0 and the following line fails to build then ensure you do not 43 * have portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() defined in your 44 * FreeRTOSConfig.h file. */ 45 portCONFIGURE_TIMER_FOR_RUN_TIME_STATS(); 46 47 /* Setting up the timer tick is hardware specific and thus in the 48 * portable interface. */ 49 50 /* The return value for xPortStartScheduler is not required 51 * hence using a void datatype. */ 52 /* 真正的啟動調度器, 即啟動了第一個任務 */ 53 ( void ) xPortStartScheduler(); 54 55 /* In most cases, xPortStartScheduler() will not return. If it 56 * returns pdTRUE then there was not enough heap memory available 57 * to create either the Idle or the Timer task. If it returned 58 * pdFALSE, then the application called xTaskEndScheduler(). 59 * Most ports don't implement xTaskEndScheduler() as there is 60 * nothing to return to. */ 61 } 62 else 63 { 64 /* This line will only be reached if the kernel could not be started, 65 * because there was not enough FreeRTOS heap to create the idle task 66 * or the timer task. */ 67 configASSERT( xReturn != errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY ); 68 } 69 70 /* Prevent compiler warnings if INCLUDE_xTaskGetIdleTaskHandle is set to 0, 71 * meaning xIdleTaskHandles are not used anywhere else. */ 72 ( void ) xIdleTaskHandles; 73 74 /* OpenOCD makes use of uxTopUsedPriority for thread debugging. Prevent uxTopUsedPriority 75 * from getting optimized out as it is no longer used by the kernel. */ 76 ( void ) uxTopUsedPriority; 77 }vTaskStartScheduler
4.2.15 停止調度--vTaskEndScheduler
這個介面和上一個相對,而且這個介面一定是在某個任務中調用的,因為系統不會主動停止調度器,而正常運行中始終只有某個任務和系統在運行,所以必然是某個任務主動調用的。
1 void vTaskEndScheduler( void ) 2 { 3 #if ( INCLUDE_vTaskDelete == 1 ) 4 { 5 BaseType_t xCoreID; 6 7 #if ( configUSE_TIMERS == 1 ) 8 { 9 /* Delete the timer task created by the kernel. */ 10 /* 刪除軟定時器任務 */ 11 vTaskDelete( xTimerGetTimerDaemonTaskHandle() ); 12 } 13 #endif /* #if ( configUSE_TIMERS == 1 ) */ 14 15 /* Delete Idle tasks created by the kernel.*/ 16 for( xCoreID = 0; xCoreID < ( BaseType_t ) configNUMBER_OF_CORES; xCoreID++ ) 17 { 18 vTaskDelete( xIdleTaskHandles[ xCoreID ] ); // 刪除空閑任務 19 } 20 21 /* Idle task is responsible for reclaiming the resources of the tasks in 22 * xTasksWaitingTermination list. Since the idle task is now deleted and 23 * no longer going to run, we need to reclaim resources of all the tasks 24 * in the xTasksWaitingTermination list. */ 25 /* 本應由空閑任務回收待刪除任務的資源, 但現在空閑任務被刪除了, 就在這裡處理 */ 26 prvCheckTasksWaitingTermination(); 27 } 28 #endif /* #if ( INCLUDE_vTaskDelete == 1 ) */ 29 30 /* Stop the scheduler interrupts and call the portable scheduler end 31 * routine so the original ISRs can be restored if necessary. The port 32 * layer must ensure interrupts enable bit is left in the correct state. */ 33 /* 這跟啟動調度器時關中斷一樣的疑問 */ 34 portDISABLE_INTERRUPTS(); 35 xSchedulerRunning = pdFALSE; 36 37 /* This function must be called from a task and the application is 38 * responsible for deleting that task after the scheduler is stopped. */ 39 vPortEndScheduler(); 40 }vTaskEndScheduler
好了,下一篇講xTaskAbortDelay和xTaskIncrementTick介面,這兩個介面較為複雜。
下篇再見。