###### tags: `CPP` `Arduino`
# 03 變數 (variables) 與數學運算--變化亮度
在前面的教學中, 有請大家修改閃爍速度, 不過因為要同時修改亮燈和熄燈時個別的暫停時間, 如果漏改了其中一個地方, 就會讓亮/熄的時間不一致, 為了避免這個問題, 我們可以把暫停時間統一管理, 像是這樣:
```cpp=
int duration = 300; // 建立放置整數的變數表示亮/熄燈的持續時間
void setup() {
pinMode(5, OUTPUT);
}
void loop() {
digitalWrite(5, LOW);
delay(duration); // 使用變數的名稱來取用放在變數內的數值
digitalWrite(5, HIGH);
delay(duration); // 使用變數的名稱來取用放在變數內的數值
}
```
在 C++ 中提供有[**變數 (variables)**](https://www.arduino.cc/reference/en/#variables) 機制, 就像是一個可以**放資料**的**具名保管箱**, 之後只要使用保管箱的名稱就可以**取用或是修改**資料。上例中的第 1 行就是建立一個名稱為 `duration` 的變數, 後面的**等號**不是數學的相等符號, 而是將右側的 300 **放入**左邊的變數中**存放**。在建立變數時要在開頭指明會放入[**什麼類型的資料 (data type)**](https://www.arduino.cc/reference/en/), 像是本例的 `int` 就是[**整數 (integer)**](https://www.arduino.cc/reference/en/language/variables/data-types/int/), 這是因為不同類型的資料所需的儲存空間大小不同, 因應類型不同配置適當空間才不會浪費。
有了這個變數後, 之後在程式中出現變數名稱 `duration` 的地方, 就會從變數內取出資料來使用, 像是在第 8、10 行, 實際上就等於是:
```cpp=
int duration = 300; // 持續時間
void setup() {
pinMode(5, OUTPUT);
}
void loop() {
digitalWrite(5, LOW);
delay(300);
digitalWrite(5, HIGH);
delay(300);
}
```
如果我們想要再改變閃爍速度, 就只要修改第 1 行的數值就可以了。
現在請您將 `duration` 改成 1, 重新上傳程式試看看飛快的閃爍效果!
## 數學運算
你應該已經發現將 `duration` 改成 1 飛快地閃爍根本就**看不出閃爍**, 這是因為熄燈的時間太短, 短到我們的眼睛還沒有感受到 LED 熄掉就已經又亮起來了, 整體的感覺就像是 LED 一直是亮著一樣, 這種效果就稱為**視覺暫留**。
如果我們控制好時間, 讓熄掉的時間長一些, 像是這樣:
```cpp=
int duration_on = 1; // 亮燈時間
int duration_off = 25; // 熄燈時間
void setup() {
pinMode(5, OUTPUT);
}
void loop() {
digitalWrite(5, LOW);
delay(duration_on);
digitalWrite(5, HIGH);
delay(duration_off);
}
```
這裡我們使用了兩個變數各自控制亮燈與熄燈的毫秒數, 你可以重新上傳試看看。
你會發現雖然現在看起來好像還是一直亮著, 但似乎**沒有那麼亮**, 而且如果注意看, 可能還可以感受到它似乎有**微微閃爍**, 這表示目前的亮/熄時間已經快要到達人眼可以察覺的程度了。
如果把時間控制得**更細**, 讓**亮/熄的時間差異更大**, 但是**熄掉的時間又短到人眼無法察覺**, 那麼視覺暫留就可以造成**微亮**的效果。但是問題來了, 現在亮燈的時間已經是 1 毫秒, 達到 `delay` 的最低極限, 無法再細分了。
還好, Arduino 提供有另一個暫停的函式 [`delayMicroseconds`](https://www.arduino.cc/reference/en/language/functions/time/delaymicroseconds/), 顧名思義, 它的時間單位是**微秒 (microseconds, 簡寫為 us)**, 比 `delay` 細了 1000 倍, 我們就來試看看效果:
```cpp=
int duration_on = 1; // 亮燈時間
int duration_off = 99; // 熄燈時間
void setup() {
pinMode(5, OUTPUT);
}
void loop() {
digitalWrite(5, LOW);
delayMicroseconds(duration_on);
digitalWrite(5, HIGH);
delayMicroseconds(duration_off);
}
```
在第 9 和 11 行我們都改用 `delayMicroseconds` 來控制亮/熄的時間, 並且將兩個變數的內容改成 1 和 99, 你可以重新上傳執行看看, 很明顯就可以發現 LED 看起來雖然是一直亮著, 但是**亮度暗很多**。這就是因為程式控制每 100us 中只有 1us 是亮的, 其他時間都是不亮, 但 99us 的時間太短, 人眼無法察覺亮/熄交替, 視覺暫留的效果會讓人感覺是很暗的燈。
利用這樣的作法, 只要調整 `duration_on` 和 `duration_off` 的數值, 就可以有 100 階變化的亮度效果。要做到這件事, 其實並不需要兩個變數, 因為這兩個變數互相消長, 但總和不變是 100, 只要變化亮燈的時間, 就可以用算數得出熄燈的時間, 我們可以把程式改成這樣:
```cpp=
int duration_on = 1; // 亮燈時間
void setup() {
pinMode(5, OUTPUT);
}
void loop() {
digitalWrite(5, LOW);
delayMicroseconds(duration_on);
digitalWrite(5, HIGH);
delayMicroseconds(100 - duration_on);
}
```
第 10 行就用減法取得熄燈的時間, 由於 `duration_on` 的值是 1, 所以計算結果就是 100 - 1, 也就是 99。
將程式重新上傳就可以得到一模一樣的效果, 但卻只需要建立單一個變數。在撰寫程式的時候, 就可以像是本例的作法, 利用不同的運算, 計算出所需要的數值, 後續還會看到更多例子。