2023 嵌入式作業系統分析與實做 Lab1 report === ###### tags: `FreeRTOS` ### Lab要求 * Must use MultiTask, e.g. One for LED , other for Button. * Inter process communication (IPC). * LED have two state * The green LED lights up for 5 seconds, then turns to a red LED lights up for 5 seconds (green LED off), and then switches back to the green LED lights up for 5 seconds (red LED off), and so on. * The red LED blinking. * If the button is pressed, the LED will switch to another state. * Debounce. * Edge detection. #### 實做流程 ##### Step.1 因為是透過**FreeRTOS**來實做所以要先 ```cpp= #include "FreeRTOS.h" #include "task.h" ``` 兩者得include的順序不能對調,否則會報錯。 ##### Step.2 **Bounce** 所謂的 Bounce 是指我們在按下電源開關時,電壓不會從 0 伏直接升到 VDD 伏。而是在 0 及 VDD 間震盪好幾次,最後才在 VDD 端穩定下來。 一個電子產品若有彈跳現象的話,最常見到的「症狀」是按下一個開關,結果數字跳好幾下。 ![Bounce](https://upload.wikimedia.org/wikipedia/commons/a/ac/Bouncy_Switch.png) ==導致電路將這類開關脈衝誤以為是資料流==。 **Debounce** * Hardware debouncing: * 在輸入的IO pin接一顆小電容到GND,等同於按鍵旁並聯一顆電容,因為電容的充放電需要時間,輸入pin上面的電壓不會瞬間變化。透過上拉電阻(Pull-up),與電容的選擇可以決定電容充放電的時間。所以當電容充放電的時間大於**Bounce持續的時間**,此時按鍵彈跳現象就被消除了!而上拉電阻、與下拉電阻是用來抗干擾與預設默認電平,干擾是因為pin腳懸空再加上電磁干擾就會產生這種不穩地的訊號。 ```cpp= void vTaskPressversion2(void){ for(;;){ if(HAL_GPIO_ReadPin(Blue_Button_GPIO_Port,GPIO_PIN_0)) HAL_Delay(10);//debounce } } ``` 透過第`4`行讓它的擷取時間延後大於Bounce Time。 ##### Step.3 長按按鈕的話有可能會傳送一次以上的訊號,與Lab要求不合。 ```cpp= void vTaskPressversion2(void){ for(;;) { if(HAL_GPIO_ReadPin(Blue_Button_GPIO_Port,GPIO_PIN_0)) { HAL_Delay(10);//debounce while(HAL_GPIO_ReadPin(Blue_Button_GPIO_Port,GPIO_PIN_0)) {;} } } } ``` 透過第`7,8`可以檢查按鈕是否長按,以確保長按按鈕被誤會成要執行一次以上的操作。 ##### Step.4 要用**message queue**讓task之間可以做溝通,所以要 ```cpp= #include "queue.h" ``` ```cpp= QueueHandle_t MsgQueue = NULL; int main(void){ MsgQueue = xQueueCreate(1,sizeof(unsigned int)); while (1) { /* ... */ } } ``` 透過xQueueCreate產生MsgQueue,這樣task之間就可以利用xQueueSend,將資料傳入MsgQueue,或是透過xQueueReceive,讀出MsgQueue中的資料。 ##### Step.5 定義偵測button按壓的task ```cpp= void vTaskPressversion2(void){ unsigned int task = 0; unsigned int count = 0; for(;;){ if(HAL_GPIO_ReadPin(Blue_Button_GPIO_Port,GPIO_PIN_0)){ HAL_Delay(10);//debounce while(HAL_GPIO_ReadPin(Blue_Button_GPIO_Port,GPIO_PIN_0)) {;} ++count ; if(count & 0x01) task = 1; else task = 0; xQueueSend(MsgQueue,(int * ) &task,1); taskYIELD(); } } } ``` * 第`5-6`行:是檢查Pin腳有無訊號傳入,且做Software debouncing。 * 第`9-13`行:計算接收到了幾次訊號,每次接受到訊號都要做task的切換。 * 第`14`行:透過MsgQueue通知其他task現在應該執行的動作。 * 第`15`行:主動釋放處理器,使得其他在ready list中的task能快一點被執行。 定義兩個LED狀態切換的task ```cpp= void LEDTask_App(void *pvParameters) { unsigned int light = 1; for(;;) { while(light==0){ HAL_GPIO_WritePin(led_orange_GPIO_Port, GPIO_PIN_13, GPIO_PIN_SET); vTaskDelay(1000); xQueueReceive(MsgQueue,&light, 0); HAL_GPIO_WritePin(led_orange_GPIO_Port, GPIO_PIN_13, GPIO_PIN_RESET); vTaskDelay(1000); if(light==1) break; } while(light==1){ HAL_GPIO_WritePin(led_green_GPIO_Port, GPIO_PIN_12, GPIO_PIN_SET); vTaskDelay(2000); xQueueReceive(MsgQueue,&light, 0); HAL_GPIO_WritePin(led_green_GPIO_Port, GPIO_PIN_12, GPIO_PIN_RESET); vTaskDelay(2000); HAL_GPIO_WritePin(led_red_GPIO_Port, GPIO_PIN_14, GPIO_PIN_SET); vTaskDelay(2000); xQueueReceive(MsgQueue,&light, 0); HAL_GPIO_WritePin(led_red_GPIO_Port, GPIO_PIN_14, GPIO_PIN_RESET); vTaskDelay(2000); if(light==0) break; } } * } ``` * 第`7`行:開啟橘燈。 * 第`9`行:跟MsgQueue要資料,如果MsgQueue的內容是空的,則此task會進入block state等待1000個Tick。若收到資料或是等待超過1000Tick則task會重新進入到ready state。 * 第`10`行:關掉橘燈 * 第`12`行:檢查是否要做狀態切換。 * 第`16`行:開啟綠燈。 * 第`18`行:跟MsgQueue要資料,如果MsgQueue的內容是空的,則此task會進入block state等待2000個Tick。若收到資料或是等待超過2000Tick則task會重新進入到ready state。 * 第`19`行:關掉綠燈 * 第`21`行:開啟紅燈。 * 第`23`行:跟MsgQueue要資料,如果MsgQueue的內容是空的,則此task會進入block state等待2000個Tick。若收到資料或是等待超過2000Tick則task會重新進入到ready state。 * 第`24`行:關掉紅燈 * 第`26`行:檢查是否要做狀態切換。 ##### Step.6 初始化task ```cpp= int main(void) { /* ... */ xTaskCreate(vTaskPressversion2,"change Task",1000,NULL,1,NULL); xTaskCreate(traffic_light,"switch between red and green",1000,NULL,1,NULL); vTaskStartScheduler(); while (1) { /* ... */ } } ``` 兩個task的priority都設成相同,因為沒有要對task做其他的操作,所以task handler可以設成NULL。 ##### Step.7 Demo [Github video](https://user-images.githubusercontent.com/48405514/224000585-fed0cc8b-83c4-4591-9b81-ad8049d7540d.mp4)