owned this note
owned this note
Published
Linked with GitHub
---
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 秒閃爍一次
#### 電路圖

#### 程式碼
```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
##### 電路圖

##### 程式碼
```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
##### 電路圖

##### 程式碼
程式碼與 [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 ,才可啟用內建上拉電阻==。
##### 電路圖

##### 程式碼
```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 跑馬燈
#### 電路圖

#### 程式碼
```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/)