# ThreadX demo ## 晶圓廠自動化運輸模擬 #### OHT: 空中走行式無人搬運車 #### Load Port: 晶圓裝卸機 #### Foup: 晶圓傳送盒 #### Sensor*2: Present sensor and Placement sensor ```mermaid flowchart TB %% 等待 Sensor 觸發部分 subgraph "等待Sensor觸發" direction TB LP1["Load Port 1\n(Sensor1 & Sensor2)"] LP2["Load Port 2\n(Sensor1 & Sensor2)"] LP3["Load Port 3\n(Sensor1 & Sensor2)"] LP4["Load Port 4\n(Sensor1 & Sensor2)"] LP5["Load Port 5\n(Sensor1 & Sensor2)"] end %% 將所有 LP 指向 CheckLimit LP1 --> CheckLimit["<b>兩個Sensor同時觸發</b>\n判定LP上有Foup\n請求OHT傳送"] LP2 --> CheckLimit LP3 --> CheckLimit LP4 --> CheckLimit LP5 --> CheckLimit %% CheckLimit 的結果處理 CheckLimit -->|允許| OHTRequest["發送 OHT 傳送請求"] CheckLimit -->|請求達到上限三台| WaitQueue["加入等待隊列"] %% 循環等待 WaitQueue --> CheckLimit %% 結束傳送 OHTRequest --> Complete["傳送完成"] Complete --> Reset["返回等待 Sensor 觸發"] %% 備註部分 Note1["<b>備註:</b> 系統最多允許3台 Load Port 同時請求 OHT 傳送"] Note1 -.- CheckLimit ``` ## ThreadX API Services used ### ### #### thread tx_thread_create #### event flags (LP Sensor狀態) tx_event_flags_create tx_event_flags_set tx_event_flags_get #### semaphore (控管OHT使用量) tx_semaphore_create tx_semaphore_get tx_semaphore_put #### queue (Foup傳輸數量計數) tx_queue_create tx_queue_send tx_queue_receive #### timer (製造Sensor假訊號) tx_timer_create --- ### event flags使用(LP Sensor狀態) ![image](https://hackmd.io/_uploads/Bk1H0omwyl.png) #### app_azure_rtos.c ```c= #include "app_azure_rtos.h" #define THREAD_STACK_SIZE 1024 #define THREAD_COUNT 10 #define QUEUE_SIZE 10 uint8_t thread_stack[THREAD_COUNT][THREAD_STACK_SIZE]; ULONG queue_storage[QUEUE_SIZE]; TX_THREAD thread_0, thread_1, thread_2, thread_3, thread_4, thread_5, thread_6, thread_7, thread_8, thread_9, counter_thread; VOID time_display(ULONG initial_input); VOID LoadPort_1(ULONG initial_input); VOID LoadPort_2(ULONG initial_input); VOID LoadPort_3(ULONG initial_input); VOID LoadPort_4(ULONG initial_input); VOID LoadPort_5(ULONG initial_input); VOID timer_callback(ULONG input); VOID lpCounter(ULONG initial_input); TX_EVENT_FLAGS_GROUP loadportST; TX_SEMAPHORE vehicleST; TX_TIMER sensorSignal; TX_QUEUE counter_queue; VOID tx_application_define(VOID *first_unused_memory) { tx_thread_create(&thread_6, "Time Display", time_display, 0, thread_stack[6], THREAD_STACK_SIZE, 3, 3, TX_NO_TIME_SLICE, TX_AUTO_START); tx_thread_create(&thread_0, "LoadPort_1", LoadPort_1, 0, thread_stack[0], THREAD_STACK_SIZE, 5, 5, TX_NO_TIME_SLICE, TX_AUTO_START); tx_thread_create(&thread_1, "LoadPort_2", LoadPort_2, 0, thread_stack[1], THREAD_STACK_SIZE, 7, 7, 5, TX_AUTO_START); tx_thread_create(&thread_2, "LoadPort_3", LoadPort_3, 0, thread_stack[2], THREAD_STACK_SIZE, 9, 9, 5, TX_AUTO_START); tx_thread_create(&thread_3, "LoadPort_4", LoadPort_4, 0, thread_stack[3], THREAD_STACK_SIZE, 11, 11, 5, TX_AUTO_START); tx_thread_create(&thread_4, "LoadPort_5", LoadPort_5, 0, thread_stack[4], THREAD_STACK_SIZE, 13, 13, 5, TX_AUTO_START); tx_event_flags_create(&loadportST, "loadportST"); tx_semaphore_create(&vehicleST, "vehicleST", 3); tx_timer_create(&sensorSignal, "sensorSignal", timer_callback, 0, 1, TX_TIMER_TICKS_PER_SECOND, TX_AUTO_ACTIVATE); tx_queue_create(&counter_queue, "Counter Queue", TX_1_ULONG, queue_storage, QUEUE_SIZE * sizeof(VOID *)); tx_thread_create(&counter_thread, "lpCounter", lpCounter, 0, thread_stack[5], THREAD_STACK_SIZE, 15, 15, TX_NO_TIME_SLICE, TX_AUTO_START); } ``` #### app_threadx.c ```c= #include "app_threadx.h" #include "tx_api.h" #include <stdio.h> #include "main.h" #include "stm32f4xx_hal_rtc.h" extern TX_EVENT_FLAGS_GROUP loadportST; extern TX_SEMAPHORE vehicleST; extern TX_QUEUE counter_queue; extern RTC_HandleTypeDef hrtc; UINT pr = 0, pl = 0; UINT lp_counters[5] = { 0 }; VOID time_display(ULONG initial_input) { while (1) { RTC_TimeTypeDef sTime = { 0 }; RTC_DateTypeDef sDate = { 0 }; // 獲取目前時間 HAL_RTC_GetTime(&hrtc, &sTime, RTC_FORMAT_BIN); // 獲取目前日期 HAL_RTC_GetDate(&hrtc, &sDate, RTC_FORMAT_BIN); // 顯示時間和日期 printf("------------------\n"); printf("Time: %02d:%02d:%02d\n", sTime.Hours, sTime.Minutes, sTime.Seconds); tx_thread_sleep(100); // 休眠 100 ticks } } VOID LoadPort_1(ULONG initial_input) { ULONG current_flags; // 用於存放事件標誌當前值 while (1) { // 檢測條件,設置事件標誌 if (pr == 1) { tx_event_flags_set(&loadportST, 0x01, TX_OR); // 設置事件標誌 bit 0 } if (pl == 3) { tx_event_flags_set(&loadportST, 0x02, TX_OR); // 設置事件標誌 bit 1 } // 檢查事件標誌是否滿足條件 if (tx_event_flags_get(&loadportST, 0x03, TX_AND_CLEAR, &current_flags, TX_NO_WAIT) == TX_SUCCESS) { printf("LP1 requesting\n"); // 獲取車輛資源信號量 tx_semaphore_get(&vehicleST, TX_WAIT_FOREVER); printf("LP1 request success\n"); // 模擬處理時間 tx_thread_sleep(600); printf("OHT takes Cassette from LP1\n"); UINT lp_ct = 0; // LP1 的索引 // 將 LP1 的索引送入隊列 tx_queue_send(&counter_queue, &lp_ct, TX_NO_WAIT); // 釋放車輛資源信號量 tx_semaphore_put(&vehicleST); } tx_thread_sleep(10); // 休眠 10 ticks } } VOID LoadPort_2(ULONG initial_input) { ULONG current_flags; // 用於存放事件標誌當前值 while (1) { // 檢測條件,設置事件標誌 if (pr == 2) { tx_event_flags_set(&loadportST, 0x04, TX_OR); // 設置事件標誌 bit 2 } if (pl == 4) { tx_event_flags_set(&loadportST, 0x08, TX_OR); // 設置事件標誌 bit 3 } // 檢查事件標誌是否滿足條件 if (tx_event_flags_get(&loadportST, 0x0c, TX_AND_CLEAR, &current_flags, TX_NO_WAIT) == TX_SUCCESS) { printf("LP2 requesting\n"); // 獲取車輛資源信號量 tx_semaphore_get(&vehicleST, TX_WAIT_FOREVER); printf("LP2 request success\n"); // 模擬處理時間 tx_thread_sleep(600); printf("OHT takes Cassette from LP2\n"); UINT lp_ct = 1; // LP2 的索引 // 將 LP2 的索引送入隊列 tx_queue_send(&counter_queue, &lp_ct, TX_NO_WAIT); // 釋放車輛資源信號量 tx_semaphore_put(&vehicleST); } tx_thread_sleep(10); // 休眠 10 ticks } } VOID LoadPort_3(ULONG initial_input) { ULONG current_flags; // 用於存放事件標誌當前值 while (1) { // 檢測條件,設置事件標誌 if (pr == 3) { tx_event_flags_set(&loadportST, 0x10, TX_OR); // 設置事件標誌 bit 4 } if (pl == 5) { tx_event_flags_set(&loadportST, 0x20, TX_OR); // 設置事件標誌 bit 5 } // 檢查事件標誌是否滿足條件 if (tx_event_flags_get(&loadportST, 0x30, TX_AND_CLEAR, &current_flags, TX_NO_WAIT) == TX_SUCCESS) { printf("LP3 requesting\n"); // 獲取車輛資源信號量 tx_semaphore_get(&vehicleST, TX_WAIT_FOREVER); printf("LP3 request success\n"); // 模擬處理時間 tx_thread_sleep(600); printf("OHT takes Cassette from LP3\n"); UINT lp_ct = 2; // LP3 的索引 // 將 LP3 的索引送入隊列 tx_queue_send(&counter_queue, &lp_ct, TX_NO_WAIT); // 釋放車輛資源信號量 tx_semaphore_put(&vehicleST); } tx_thread_sleep(10); // 休眠 10 ticks } } VOID LoadPort_4(ULONG initial_input) { ULONG current_flags; // 用於存放事件標誌當前值 while (1) { // 檢測條件,設置事件標誌 if (pr == 4) { tx_event_flags_set(&loadportST, 0x40, TX_OR); // 設置事件標誌 bit 6 } if (pl == 6) { tx_event_flags_set(&loadportST, 0x80, TX_OR); // 設置事件標誌 bit 7 } // 檢查事件標誌是否滿足條件 if (tx_event_flags_get(&loadportST, 0xc0, TX_AND_CLEAR, &current_flags, TX_NO_WAIT) == TX_SUCCESS) { printf("LP4 requesting\n"); // 獲取車輛資源信號量 tx_semaphore_get(&vehicleST, TX_WAIT_FOREVER); printf("LP4 request success\n"); // 模擬處理時間 tx_thread_sleep(600); printf("OHT takes Cassette from LP4\n"); UINT lp_ct = 3; // LP4 的索引 // 將 LP4 的索引送入隊列 tx_queue_send(&counter_queue, &lp_ct, TX_NO_WAIT); // 釋放車輛資源信號量 tx_semaphore_put(&vehicleST); } tx_thread_sleep(10); // 休眠 10 ticks } } VOID LoadPort_5(ULONG initial_input) { ULONG current_flags; // 用於存放事件標誌當前值 while (1) { // 檢測條件,設置事件標誌 if (pr == 5) { tx_event_flags_set(&loadportST, 0x100, TX_OR); // 設置事件標誌 bit 8 } if (pl == 7) { tx_event_flags_set(&loadportST, 0x200, TX_OR); // 設置事件標誌 bit 9 } // 檢查事件標誌是否滿足條件 if (tx_event_flags_get(&loadportST, 0x300, TX_AND_CLEAR, &current_flags, TX_NO_WAIT) == TX_SUCCESS) { printf("LP5 requesting\n"); // 獲取車輛資源信號量 tx_semaphore_get(&vehicleST, TX_WAIT_FOREVER); printf("LP5 request success\n"); // 模擬處理時間 tx_thread_sleep(600); printf("OHT takes Cassette from LP5\n"); UINT lp_ct = 4; // LP5 的索引 // 將 LP5 的索引送入隊列 tx_queue_send(&counter_queue, &lp_ct, TX_NO_WAIT); // 釋放車輛資源信號量 tx_semaphore_put(&vehicleST); } tx_thread_sleep(10); // 休眠 10 ticks } } VOID lpCounter(ULONG initial_input) { UINT lp_ct; // 用於接收隊列中的 LP 索引 while (1) { // 從隊列中接收 LP 索引 if (tx_queue_receive(&counter_queue, &lp_ct, TX_NO_WAIT) == TX_SUCCESS) { lp_counters[lp_ct]++; // 更新對應 LP 的計數器 } // 如果按鈕被按下,顯示所有 LP 的計數器值 if (HAL_GPIO_ReadPin(GPIOD, PB_0_Pin) == GPIO_PIN_SET) { printf("All LP counters: "); for (UINT i = 0; i < 5; i++) { printf("LP%u: %u ", i + 1, lp_counters[i]); tx_thread_sleep(2); // 避免顯示過快 } printf("\n"); } if (HAL_GPIO_ReadPin(GPIOD, PB_1_Pin) == GPIO_PIN_SET){ memset(lp_counters, 0, sizeof(lp_counters)); } tx_thread_sleep(10); // 休眠 10 ticks } } VOID timer_callback(ULONG input) { pr++; // 遞增 pr 值 pl++; // 遞增 pl 值 if (pr == 8) { pr = 1; // 重置 pr 為 1 pl = 1; // 重置 pl 為 1 } } ```