--- tags: embedded system, arduino --- # Arduino Labs ## Embedded System Knowledge ### 記憶體的種類 ### 開關的上拉與下拉電阻 ## Labs ### Lab 3-1 GPIO Output 將 Arduino pin 10 設為 `OUTPUT` (數位輸出)。將一顆 LED 如電路圖所示接上 pin 10 ,並寫程式讓 LED 每隔 0.5 秒閃爍一次 #### 電路圖 ![](https://i.imgur.com/SWc9M9t.png) #### 程式碼 ```c= #define LED (10) #define DELAY (500) void setup() { // put your setup code here, to run once: pinMode(LED, OUTPUT); } void loop() { // put your main code here, to run repeatedly: digitalWrite(LED, HIGH); delay(DELAY); digitalWrite(LED, LOW); delay(DELAY); } ``` ### Lab 4-1 GPIO Input #### Lab 4-1-1 Pull-down Resistor ##### 電路圖 ![](https://i.imgur.com/24IrriF.png) ##### 程式碼 ```c= #define SWITCH (2) #define LED (6) void setup() { // put your setup code here, to run once: pinMode(SWITCH, INPUT); pinMode(LED, OUTPUT); } void loop() { // put your main code here, to run repeatedly: bool inputVal = digitalRead(SWITCH); digitalWrite(LED, inputVal); } ``` #### Lab 4-1-2 External Pull-up Resistor ##### 電路圖 ![](https://i.imgur.com/BmPEbw2.png) ##### 程式碼 程式碼與 [Lab 4-1-1 Pull-down Resistor](https://hackmd.io/52oGKzOWQFSW__jpLCpMkw?view#%E7%A8%8B%E5%BC%8F%E7%A2%BC) 相同。 #### Lab 4-1-3 Internal Pull-up Resistor 啟用 Arduino 數位接腳的內建上拉電阻。根據 Atmel 公司的技術文件,此內建上拉電阻值為 20K歐姆 ~ 50K歐姆 間。==內建上拉電阻預設沒有啟用,須將接腳設定為 INPUT_PULLUP ,才可啟用內建上拉電阻==。 ##### 電路圖 ![](https://i.imgur.com/dQ39Awh.png) ##### 程式碼 ```c= #define SWITCH (2) #define LED (6) void setup() { // put your setup code here, to run once: pinMode(SWITCH, INPUT_PULLUP); pinMode(LED, OUTPUT); } void loop() { // put your main code here, to run repeatedly: bool inputVal = digitalRead(SWITCH); digitalWrite(LED, inputVal); } ``` ### Lab 4-2 Toggle LED 沿用 [Lab 4-1-1 Pull-down Resistor](https://hackmd.io/52oGKzOWQFSW__jpLCpMkw?view#Lab-4-1-1-Pull-down-Resistor) 的硬體 [電路](https://hackmd.io/52oGKzOWQFSW__jpLCpMkw?view#%E9%9B%BB%E8%B7%AF%E5%9C%961) 。將程式改為: 一開始 LED 滅。之後,按一下開關 LED 亮。再按一下開關 LED 滅。 #### 程式碼 * 全域變數 `ledState` 與 `prevSWState` 為全域變數。 `ledState` 負責記錄 LED 的狀態。初始值為 `LOW` ,也就是熄滅。 `prevSWState` 負責記錄按鈕的前一個狀態。初始值為 `RELEASED ` 。 `swState` 負責記錄按鈕目前的狀態。初始值為 `RELEASED ` 。 * `setup` 將 pin 6 (`LED`) 設定為 `OUTPUT` 。 pin 2 (`SWITCH`) 設定為 `INPUT` 。並且將 LED 設定為熄滅。 * `loop` * 因為 Arduino 板子啟動並執行完 `setup` 後,會不斷地執行 `loop` ,所以 `loop` 不斷地讀入按鈕 (`SWITCH`) 的狀態 (即第 23 行的 `digitalRead(SWITCH)` )。若 `digitalRead(SWITCH)` 讀到的按鈕狀態為 `HIGH` (即按鈕被按下),則將 `swState` 為 `PRESSED` 。否則,將 `swState` 為 `RELEASED` 。 * 假設此時按鈕被按下,第 24 行的敘述會被執行。所以 `swState` 會被設為 `PRESSED` 。 * 接著第 29 行的 `if` 條件句成立, `prevSWState` 會被設定為 `swState` 的值,也就是 `PRESSED` 。 * 由於此時按鈕仍為按下的狀態,所以第 33 行的 `if` 條件不成立。 * 當按鈕被放開後,第 23 行讀到按鈕的狀態為 `LOW` ,所以第 26 行會被執行。 `swState` 被設定為 `RELEASED` 。 * 因為此時 `swState` 為 `RELEASED` ,所以第 29 行的 `if` 條件句不成立,`prevSWState` 仍維持 `PRESSED` 。 * 因為 `swState` 與 `prevSWState` 分別為 `RELEASED` 與 `PRESSED` ,所以第 33 行的 `if` 條件句成立。 * `ledState` 的值被轉換成 `HIGH` 。 (第 34 行) 。然後將新的 LED 狀態寫入 `LED` (即 pin 6) ,點亮 LED。 * 然後將 `prevSWState` 設為 `RELEASED` 。 所以下一個迴圈中 (假設按鈕沒有再被按下) ,第 33 行的 `if` 條件句不成立 (因為 `swState` 與 `prevSwState` 皆為 `RELEASED`)。進而維持 LED 被點亮的狀態。 * 由上列敘述可知,LED 的狀態會在按鈕被釋放時進行轉換。 * 當按鈕再次被按下,然後放開時,LED 就會熄滅。 ```c= #define SWITCH (2) #define LED (6) #define HIGH (1) #define LOW (0) byte ledState = LOW; byte prevSWState = LOW; byte swState = LOW; void setup() { // Setup the GPIO pins. pinMode(SWITCH, INPUT); pinMode(LED, OUTPUT); digitalWrite(LED, ledState); } void loop() { swState = digitalRead(SWITCH); if (swState) { prevSWState = swState; } if (swState != prevSWState) { ledState = !ledState; digitalWrite(LED, ledState); prevSWState = LOW; } } ``` #### 用程式消除開關的彈跳現象 用上述的程式與電路實驗後發現,有時候會發生 LED 該熄滅的時候沒有熄滅,該點亮的時候沒有點亮。這是因為開關的彈跳現象造成的誤動作。可以用程式解決這個問題。 當 Arduino 偵測到開關被按下時,延遲 20 ms ,忽略掉那段訊號不穩定的時間後,再讀一次開關的狀態。確認開關真的被按下後,在進行狀態切換。 ```c= #define SWITCH (2) #define LED (6) #define HIGH (1) #define LOW (0) byte ledState = LOW; byte prevSWState = LOW; byte swState = LOW; void setup() { // Setup the GPIO pins. pinMode(SWITCH, INPUT); pinMode(LED, OUTPUT); digitalWrite(LED, ledState); } void loop() { swState = digitalRead(SWITCH); if (swState) { // Arduino detects that the button has been pressed. // To de-bounce, delay 20 ms. delay(20); // After 20 ms, read the button status again. // If the button status is still pressed, // the status of LED will be changed. byte swTmpState = digitalRead(SWITCH); if (swState == swTmpState) { prevSWState = swState; } } if (swState != prevSWState) { ledState = !ledState; digitalWrite(LED, ledState); prevSWState = LOW; } } ``` ### Lab 4-5 LED 跑馬燈 #### 電路圖 ![](https://i.imgur.com/J9vmn5p.png) #### 程式碼 ```c= #define LED1 (2) #define LED2 (3) #define LED3 (4) #define LED4 (5) #define LED5 (6) const byte firstLed = LED1; const byte lastLed = LED5; byte currLed = firstLed; void setup() { // put your setup code here, to run once: for (int led = LED1; led <= LED5; ++led) { pinMode(led, OUTPUT); digitalWrite(led, LOW); } } void loop() { // put your main code here, to run repeatedly: digitalWrite(currLed, HIGH); delay(200); digitalWrite(currLed, LOW); if (currLed < lastLed) { ++currLed; } else { currLed = firstLed; } } ``` ### Lab 4-6 LED 來回跑馬燈 #### 電路圖 沿用 [Lab 4-5 LED 跑馬燈](https://hackmd.io/@hsuedw/arduino_labs#Lab-4-5-LED-%E8%B7%91%E9%A6%AC%E7%87%88) 的電路。 #### 程式碼 ```c= #define LED1 (2) #define LED2 (3) #define LED3 (4) #define LED4 (5) #define LED5 (6) byte leds[] = {LED1, LED2, LED3, LED4, LED5}; byte numLeds = sizeof(leds) / sizeof(leds[0]); void setup() { // put your setup code here, to run once: for (int i = 0; i < numLeds; ++i) { pinMode(leds[i], OUTPUT); digitalWrite(leds[i], LOW); } } void loop() { for (int i = 0; i < numLeds - 1; ++i) { digitalWrite(leds[i], HIGH); delay(200); digitalWrite(leds[i], LOW); } for (int i = numLeds - 1; i > 0; --i) { digitalWrite(leds[i], HIGH); delay(200); digitalWrite(leds[i], LOW); } } ``` # Reference [Block Circuit EDIT](https://www.block.tw/bce/)