###### tags: `CPP` `Arduino`
# 09 利用多維陣列結合相關資料
如果不只是亮度要不規律的變化, 連時間也要隨意變化, 例如先稍微亮 0.5 秒、再暗一些 1 秒, 最後全亮 0.2 秒, 可以比照亮度的做法, 另外再定義一個陣列, 紀錄對應時間的亮暗切換次數, 像是這樣:
```cpp=
const int duration = 100; // 單次亮/熄時長 (us)
const int led_pin = 5; // 內建 LED 腳位
const int levels[3] = {30, 5, 100}; // 亮燈時長
const int totals[3] = {5000, 10000, 2000}; // 亮/熄切換次數
void twinkle(int led_pin, int duration, int duration_on, int total) {
for(int count = 0;count < total; count++) {
digitalWrite(led_pin, LOW);
delayMicroseconds(duration_on);
digitalWrite(led_pin, HIGH);
delayMicroseconds(duration - duration_on);
}
}
void setup() {
pinMode(led_pin, OUTPUT);
}
void loop() {
for(int i = 0; i < sizeof(levels)/sizeof(int); i++) {
twinkle(led_pin, duration, levels[i], totals[i]);
}
}
```
第 4 行的陣列就是對應第 3 行陣列的切換次數, 重新上傳程式後就可以看到不同亮度持續時間都不同的效果。
結果雖然正確, 不過卻有個潛在的問題, 因為兩個陣列是分開的, 就可能會發生想增加亮度變化的層次, 但卻忘了在 `totals` 陣列新增對應的切換次數。要解決這個問題, 可以使用**多維陣列 (multidimentional array)**。
## 由陣列構成的陣列
你可以把多維陣列想成是由陣列構成的陣列, 也就是陣列中的每一項資料自己也是一個陣列, 例如:
```cpp
int led_info[3][2];
```
這表示 `led_info` 是一個內含 3 項資料的陣列, 其中的每一項資料都是一個內含 2 項資料的陣列, 也就是說 `led_info` 總共內含 3×2 共 6 項資料。如果要定義多維陣列的內容, 可以用多層的大括號形式, 像是這樣:
```cpp
int led_info[3][2] = {
{30, 5000}, // 相當於 led_info[0]
{5, 10000}, // 相當於 led_info[1]
{100, 2000} // 相當於 led_info[2]
};
```
內層的一對大括號就對應到陣列的一項資料, 你可以看到這每一項資料自己又是一對大括號定義的陣列。如果要取得最內層陣列的資料, 就要使用兩次中括號, 像是這樣:
```cpp
led_info[0][1] // 取得 5000
led_info[1][0] // 取得 5
```
像是這樣的陣列我們就稱它為 **2 維陣列**, **第 1 個維度**有 3 項資料, 每 1 項資料自己又是 1 個 1 維陣列, 這稱為**第 2 維**, 存放宣告陣列時標示型別的資料。多維陣列並不限於 2 維, 若有需要, 還可無限延伸。
如此我們就可以改寫剛剛使用兩個單獨陣列的程式, 把亮燈時長和亮/熄切換次數整合在單一個多維陣列了:
```cpp=
const int duration = 100; // 單次亮/熄時長 (us)
const int led_pin = 5; // 內建 LED 腳位
const int led_info[3][2] = {
{30, 5000}, // 亮燈時長與亮/熄切換次數
{5, 10000}, // 亮燈時長與亮/熄切換次數
{100, 2000} // 亮燈時長與亮/熄切換次數
};
void twinkle(int led_pin, int duration, int duration_on, int total) {
for(int count = 0;count < total; count++) {
digitalWrite(led_pin, LOW);
delayMicroseconds(duration_on);
digitalWrite(led_pin, HIGH);
delayMicroseconds(duration - duration_on);
}
}
void setup() {
pinMode(led_pin, OUTPUT);
}
void loop() {
for(int i = 0; i < sizeof(led_info)/sizeof(led_info[0]); i++) {
twinkle(led_pin, duration, led_info[i][0], led_info[i][1]);
}
}
```
1. 第 3~7 行就是剛剛舉例的陣列, 其實就是把前面例子中的兩個陣列內容整合在一起, 分別是三種亮度的亮燈時長與亮/熄切換次數。
2. 第 23 行我們使用陣列本身的大小與陣列第 1 項資料的大小來計算多維陣列中第 1 維的資料數量。
3. 第 24 行就改用取多維陣列中第 2 維陣列內的資料作為參數。
上傳後和原本的程式效果一樣。