--- tags: 嵌入式作業系統分析與實作 --- # Lab3-Task_Monitor contributed by <`RusselCK` > ###### tags: `RusselCK` ## 作業要求 ![](https://i.imgur.com/uMfG4ti.png) 給定下列 tasks,從 `pxReadyTasksLists` 或 `pxDelayedTaskList` 找出他們的 TCB ,並將其部分內容在 Console 呈現出來。 | Task Name | Priority | |:----------------------- |:--------:| | `Lab03_Red_LED` | 1 | | `Lab03_Green_LED` | 1 | | `Lab03_Delay_App` | 14 | | `Lab03_TaskMonitor_App` | 2 | ## Pinout & Configuration ![](https://i.imgur.com/eKH4QZA.png) ![](https://i.imgur.com/xaCzfhk.png) ![](https://i.imgur.com/jxwPuAZ.png) ![](https://i.imgur.com/yahAj3q.png) ## UART & TTL ### UART - [ ] [UART (Universal Asynchronous Receiver/Transmitter)](https://zh.wikipedia.org/wiki/UART) Using an USART to USB dongle from the market connected for instance to STM32F407 USART2 available on connector P1 pin 14 (PA2: USART2_TX) and P1 pin 13 (PA3: USART2_RX). ![](https://i.imgur.com/LSaZsfG.png) ![](https://i.imgur.com/sFQsi92.gif) ### USBtoTTL ![](https://i.imgur.com/MSQbaW8.png) ![](https://i.imgur.com/qXZdWEd.png) ## `main.c` ```c /* Private includes ----------------------------------------*/ /* USER CODE BEGIN Includes */ #include "FreeRTOS.h" #include "task.h" /* USER CODE END Includes */ ``` ### Lab03_Red_LED ```c void Red_LED_App(void *pvParameters) { uint32_t Redtimer = 500; while(1){ HAL_GPIO_TogglePin(GPIOD,Red_LED_Pin); vTaskDelay(Redtimer); Redtimer += 1; } } ``` ### Lab03_Green_LED ```c void Green_LED_App(void *pvParameters) { uint32_t Greentimer = 1000; while(1){ HAL_GPIO_TogglePin(GPIOD,Green_LED_Pin); vTaskDelay(Greentimer); Greentimer += 2; } } ``` ### Lab03_Delay_App ```c void Delay_App(void *pvParameters) { while(1){ vTaskDelay(15000); } } ``` ### Lab03_TaskMonitor_App ```c void Taskmonitor(void); void TaskMonitor_App(void *pvParameters) { uint8_t i = 100; for(;;){ Taskmonitor(); i += 1; vTaskDelay(i); if( i == 500) i = 0 ; } } ``` :::warning Lab03 最重要的任務就是完成 `Taskmonitor()` ::: ### Lab03_start ```c void vLab03_start (void *pvParameters) { xTaskCreate(Red_LED_App, "Lab03_Red_LED", 1000, NULL, 1, NULL); xTaskCreate(Green_LED_App, "Lab03_Green_LED", 1000, NULL, 1, NULL); xTaskCreate(Delay_App, "Lab03_Delay_App", 1000, NULL, 14, NULL); xTaskCreate(TaskMonitor_App, "Lab03_TaskMonitor_App", 1000, NULL, 2, NULL); vTaskDelete(NULL); } int main (void) { /* USER CODE BEGIN 2 */ xTaskCreate(vLab03_start, "Lab03_Start", 1000, NULL, 1, NULL); vTaskStartScheduler(); /* USER CODE END 2 */ } ``` ## TCB ### TCB 的位置 #### `pxReadyTaskLists[priority]` ![](https://i.imgur.com/zAxSgTi.png) 每個 priority 會有一條 `pxReadyTaskList` #### `pxDelayedTaskList` `pxDelayedTaskList` 只有一條,且結構與 `pxReadyTaskList` 相同 ### TCB 的結構 `task.c` ```c typrdef struct tskTaskControlBlock { volatile StackType_t * pxTopOfStack; UBaseType_t uxPriority StackType_t * pxStack; char pcTaskName[ configMAX_TASK_NAME_LEN ]; #if ( configUSE_MUTEXES == 1 ) UBaseType_t uxBasePriority; #endif ... } tskTCB; typedef tskTCB TCB_t ``` > 僅列出 Lab03 會用到的項目 ## Lists Macro `list.h` ```c /* default */ #define listLIST_IS_EMPTY( pxList ) ( ( ( pxList )->uxNumberOfItems == ( UBaseType_t ) 0 ) ? pdTRUE : pdFALSE ) #define listGET_OWNER_OF_HEAD_ENTRY( pxList ) ( (&( ( pxList )->xListEnd ))->pxNext->pvOwner ) #define listCURRENT_LIST_LENGTH( pxList ) ( ( pxList )->uxNumberOfItems ) /* add by your own */ #define listGET_ITEM_OF_HEAD_ENTRY( pxList ) ( (&( ( pxList )->xListEnd ))->pxNext ) ``` > 僅列出 Lab03 會用到的部分 **`listGET_OWNER_OF_HEAD_ENTRY( pxList )`** 會直接指向 List 的第一個 `xListItem` 的 TCB * 這樣一來就無法進入 List 的第二個 `xListItem` **`listGET_ITEM_OF_HEAD_ENTRY( pxList )`** 會指向 List 的一個 `xListItem` * 可以保有去 TCB 或下一個 `xListItem` 的選擇彈性 ## `task.c` ```c #include <stdio.h> #include "stm32f4xx_hal.h" ``` ```c UART_HandleTypeDef huart2; // for USART2 ``` ### `Uint32ConvertHex()` ```c void Uint32ConvertHex(volatile StackType_t pStack, char *charTxScanTaskStack) { uint32_t remainder,quotient; int index = 0; quotient = pStack; charTxScanTaskStack[index++] = 48; // ascii number 0 charTxScanTaskStack[index++] = 120; // ascii alphabet x while (quotient != 0) { remainder = quotient & 0xf; // quotient % 16 if (remainder < 10) charTxScanTaskStack[index++] = '0' + remainder; else charTxScanTaskStack[index++] = 55 + remainder; // A = 65; quotient = quotient >> 4; // quotient / 16 } /* reverse */ int end = index-1; for(int reversal = 2;reversal <= end; ++reversal, --end) { charTxScanTaskStack[end] ^= charTxScanTaskStack[reversal]; charTxScanTaskStack[reversal] ^= charTxScanTaskStack[end]; charTxScanTaskStack[end] ^= charTxScanTaskStack[reversal]; } charTxScanTaskStack[index++] = 0; } ``` ### `LongConvertCharArray()` ```c void LongConvertCharArray(UBaseType_t TxScanTaskPriority, char *charTxScanTaskStack) { uint32_t remainder,quotient; int index = 0; quotient = TxScanTaskPriority; if(quotient == 0) charTxScanTaskStack[index++] = '0'; while (quotient != 0){ remainder = quotient % 10; charTxScanTaskStack[index++] = '0' + remainder; quotient = quotient / 10; } /* reverse */ if (index == 1) return; int end = index-1; for(int reversal = 0; reversal <= end; ++reversal, --end) { charTxScanTaskStack[end] ^= charTxScanTaskStack[reversal]; charTxScanTaskStack[reversal] ^= charTxScanTaskStack[end]; charTxScanTaskStack[end] ^= charTxScanTaskStack[reversal]; } charTxScanTaskStack[index++] = 0; } ``` ### `PrintTCBContext()` **簡化版** ```c void PrintTCBContext(TCB_t *taskTCB, char taskState[]) { /* get TCB contexts */ char taskBasePriority[3]; memset(taskBasePriority,'\0',sizeof(taskBasePriority)); LongConvertCharArray(taskTCB->uxBasePriority, taskBasePriority); char taskPriority[3]; memset(taskPriority,'\0',sizeof(taskPriority)); LongConvertCharArray(taskTCB->uxPriority, taskPriority); char taskStack[11]; memset(taskStack,'\0',sizeof(taskStack)); Uint32ConvertHex(taskTCB->pxStack, taskStack); char taskTOS[11]; memset(taskTOS,'\0',sizeof(taskTOS)); Uint32ConvertHex(taskTCB->pxTopOfStack, taskTOS); /* ouput TCB contexts */ char Monitor[150]; memset(Monitor,'\0',sizeof(Monitor)); strcat(Monitor,taskTCB->pcTaskName); int taskNamelen = strlen(taskTCB->pcTaskName); strcat(Monitor,taskBasePriority); strcat(Monitor,taskPriority); strcat(Monitor,taskStack); strcat(Monitor,taskTOS); strcat(Monitor, taskState); strcat(Monitor, "\n\r"); HAL_UART_Transmit(&huart2,(uint8_t *)Monitor,strlen(Monitor),0xffff); } ``` **調整排版** ```c void PrintTCBContext(TCB_t *taskTCB, char taskState[]) { /* get TCB contexts */ char taskBasePriority[3]; memset(taskBasePriority,'\0',sizeof(taskBasePriority)); LongConvertCharArray(taskTCB->uxBasePriority, taskBasePriority); char taskPriority[3]; memset(taskPriority,'\0',sizeof(taskPriority)); LongConvertCharArray(taskTCB->uxPriority, taskPriority); char taskStack[11]; memset(taskStack,'\0',sizeof(taskStack)); Uint32ConvertHex(taskTCB->pxStack, taskStack); char taskTOS[11]; memset(taskTOS,'\0',sizeof(taskTOS)); Uint32ConvertHex(taskTCB->pxTopOfStack, taskTOS); /* ouput TCB contexts */ char Monitor[150]; memset(Monitor,'\0',sizeof(Monitor)); strcat(Monitor,taskTCB->pcTaskName); int taskNamelen = strlen(taskTCB->pcTaskName); for(int t = 0; t < (30-taskNamelen); ++t) strcat(Monitor," "); strcat(Monitor,taskBasePriority); strcat(Monitor, "/"); strcat(Monitor,taskPriority); strcat(Monitor," "); strcat(Monitor,taskStack); strcat(Monitor," "); strcat(Monitor,taskTOS); strcat(Monitor," "); strcat(Monitor, taskState); strcat(Monitor, "\n\r"); HAL_UART_Transmit(&huart2,(uint8_t *)Monitor,strlen(Monitor),0xffff); } ``` ### `Taskmonitor()` ```c void Taskmonitor(void) { /* output Title */ char *str="Name |Piority (Base/Actual) |pxStack |pxTopOfStack |State \n\r"; HAL_UART_Transmit(&huart2,(uint8_t *)str,strlen(str),0xffff); /* traversal ReadyTaskLists */ for (UBaseType_t i = 0; i < configMAX_PRIORITIES; ++i) { if (listLIST_IS_EMPTY( &pxReadyTasksLists[i] ) == pdFALSE) { ListItem_t *tasklist = listGET_ITEM_OF_HEAD_ENTRY( &pxReadyTasksLists[i] ); UBaseType_t tasklistlen = listCURRENT_LIST_LENGTH( &pxReadyTasksLists[i] ); for (UBaseType_t j = 0; j < tasklistlen; tasklist = tasklist->pxNext, ++j) { TCB_t *taskTCB = tasklist->pvOwner; char taskState[6] = "Ready"; PrintTCBContext (taskTCB, taskState); } } } /* traversal DelayedTaskList */ if (listLIST_IS_EMPTY( &pxDelayedTaskList[0] ) == pdFALSE) { ListItem_t *tasklist = listGET_ITEM_OF_HEAD_ENTRY( &pxDelayedTaskList[0] ); UBaseType_t tasklistlen = listCURRENT_LIST_LENGTH( &pxDelayedTaskList[0] ); for (UBaseType_t j = 0; j < tasklistlen; tasklist = tasklist->pxNext, ++j) { TCB_t *taskTCB = tasklist->pvOwner; char taskState[6] = "Delay"; PrintTCBContext (taskTCB, taskState); } } } ```