🌏 English version: 4×4×4 LED Cube with Arduino Mega2560: Sound- and Motion-Reactive Multiplexing
本 DIY 專案為「4×4×4 共 64 顆 LED 的互動式立方體」:以 Arduino Mega2560 作為控制核心,外接聲音感測器與 PIR 人體感測器,燈光圖案隨環境聲音與周遭人員的移動而變化。
製作立方體:雷射切割焊接治具
LED 立方體最困難的部分並非電路,而是讓 64 顆 LED 排成筆直、等距的格子。徒手焊接容易歪斜,因此以雷射切割 MDF 板製作簡易治具:板上開有 4×4 的孔位,間距與 LED 間距相同。每層 16 顆 LED 倒插入孔中,彎折接腳後焊接相連,完成的一層取出後即保持方正。四層相同的結構再堆疊接合。
電路組成
- 控制器:Arduino Mega2560,搭配 RobotWolf Group 的插接式擴充板,立方體直接安裝於擴充板上
- LED:64 顆藍色 LED,排列為 4×4×4
- 感測器:聲音感測模組、PIR 人體感測器
採用多工而非直接佔用 64 個腳位的原因
64 顆 LED 若各自佔用一個 IO,需要 64 個腳位。LED 立方體的標準解法是多工掃描(multiplexing):同一垂直柱上 4 顆 LED 的陽極焊接在一起(共 16 柱),同一水平層 16 顆 LED 的陰極焊接在一起(共 4 層)。任一瞬間只點亮一層,由 16 條柱線決定該層哪些 LED 亮起;將 4 層每秒輪流掃描數百次,人眼的視覺暫留即讀成「64 顆同時亮」——與螢幕逐行刷新的原理相同。
因此腳位需求由 64 降至 16+4=20,Mega2560 仍保留充足腳位可接感測器。實務上需注意兩點:
- 電流:一層最多同時流過 16 顆 LED 的電流,超出單一 IO 腳位可承受的範圍。常見解法是每層加一顆電晶體(或採用 ULN2003 驅動陣列),由電晶體將該層接地。
- 亮度:每層只有 1/4 的時間點亮,多工驅動的亮度低於直接驅動。可略微調低柱線的限流電阻作為補償。
範例程式:層掃描結合聲音與人體感測
以下為示範此技巧的範例程式(層掃描+兩種感測器),供製作類似立方體時參考,並非原始專案的程式碼。腳位編號僅為示意,請依實際接線調整。
/*
* 4x4x4 LED 立方體:層掃描 + 聲音感測器 + PIR(範例程式)
* 16 柱(陽極)→ COL_PIN[],各串一顆限流電阻
* 4 層(陰極)→ 電晶體/ULN2003,由 LAYER_PIN[] 控制
* 聲音感測器類比輸出 → A0
* PIR 感測器輸出 → D2(偵測到移動時為 HIGH)
*/
const uint8_t COL_PIN[16] = {22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37};
const uint8_t LAYER_PIN[4] = {38,39,40,41}; // HIGH = 該層導通
const uint8_t PIR_PIN = 2;
bool cube[4][16]; // cube[層][柱]
uint8_t layer = 0;
void setup() {
for (uint8_t c = 0; c < 16; c++) pinMode(COL_PIN[c], OUTPUT);
for (uint8_t z = 0; z < 4; z++) pinMode(LAYER_PIN[z], OUTPUT);
pinMode(PIR_PIN, INPUT);
}
void updatePattern() {
static uint32_t last = 0;
uint32_t now = millis();
if (now - last < 30) return; // 每 30ms 更新一次圖案
last = now;
int sound = analogRead(A0);
uint8_t level = constrain(map(sound, 300, 700, 0, 4), 0, 4); // 依模組實際讀值校正
bool motion = digitalRead(PIR_PIN);
uint32_t t = now / 150;
for (uint8_t z = 0; z < 4; z++)
for (uint8_t c = 0; c < 16; c++) {
if (motion) cube[z][c] = ((c + z + t) % 4 == 0); // 偵測到人:流動的波紋
else cube[z][c] = (z < level); // 其餘時間:音量柱
}
}
void loop() {
updatePattern();
// 掃描:先關閉目前的層,再設定柱線,最後開啟下一層
digitalWrite(LAYER_PIN[layer], LOW);
layer = (layer + 1) & 3;
for (uint8_t c = 0; c < 16; c++) digitalWrite(COL_PIN[c], cube[layer][c] ? HIGH : LOW);
digitalWrite(LAYER_PIN[layer], HIGH);
delayMicroseconds(500); // 4 層 x 0.5ms = 每幀 2ms(約 500 fps)
}
此範例有兩個值得保留的習慣:切換柱線之前先關閉目前的層,可避免「殘影」(前一層圖案的微弱重影);感測改為定時執行,而非每次進入 loop() 都讀取,較慢的 analogRead 便不會拉長某一層的點亮時間而造成閃爍。
調試時常見的問題
- 隨機閃爍:幾乎都是立方體、驅動電晶體與感測器之間未共地。
- 肉眼可見的閃爍:4 層完整掃描一輪須遠低於 20ms(高於 50Hz),掃描路徑中不應放入耗時的工作。
- 整柱或整層不亮:檢查該柱或該層的焊點——64 顆 LED 之中,一處冷焊就是最常見的原因。
- PIR 一直維持觸發:多數 PIR 模組板上設有調整靈敏度與保持時間的可變電阻;保持時間過長,立方體便顯得反應遲鈍。
結語
LED 立方體一次涵蓋電子學的三項核心:多工、電流、時序。64 顆 LED 依靠掃描速度而非腳位數量運作——人眼無法分辨每秒數百次的層掃描,感受到的是一個完整的立體圖案。雷射切割治具則是整個專案中最有價值的一環:少了治具,格子不可能排得筆直。
沒有留言:
張貼留言