Salju Arduino DIY: Proyek Tampilan LED 30-LED
Komponen dan Perlengkapan
Tentang Proyek Ini
Salju terdiri dari 30 LED yang dikelompokkan menjadi 17 segmen independen yang dapat dikontrol secara terpisah oleh mikrokontroler Arduino Nano. Setiap grup LED dapat diatur kecerahannya dengan PWM untuk menciptakan animasi yang indah.
Alat
Semua yang Anda butuhkan adalah paku las, timah, dan alat tangkap.
Konstruksi
Pertama-tama pilih beberapa pola. Saya memilih kristal salju yang sederhana dan mencetaknya dengan ukuran yang pas untuk Arduino Nano di dalam heksagon - inti kristal.
Struktur pendukung yang juga bertindak sebagai kabeling dibuat dari tiang metalik 0,8 mm yang dilas bersama dengan timah. Saya telah menggunakan 2 meter tiang secara keseluruhan. Mengapa bebas bentuk? Karena saya selalu ingin mencoba itu dan itu adalah uji kesabaran dan keterampilan Anda.
Pertama saya membuat heksagon inti dengan membengkokkan satu tiang dan memasangnya dengan las di ujungnya. Dengan menambahkan 6 tiang lagi ke puncak heksagon, kabeling tanah selesai, semua kawat katoda LED sekarang perlu dilas ke dalamnya untuk menciptakan pola salju. Bagian yang sulit adalah menambahkan LED SMD tetapi saya membantu diri sendiri dengan cetakan yang dibuat dari karton dan lem dua sisi.
Selanjutnya saatnya untuk menambahkan mikrokontroler Arduino Nano di bawah struktur inti dengan meninggalkan cukup ruang di antaranya untuk memasang 3 lapisan kabeling tiang metalik yang akan menghubungkan pin mikrokontroler ke semua kawat anoda LED. Ini membutuhkan kesabaran yang luar biasa. Anda tidak hanya perlu menghindari rangkaian pendek di antara kabel tetapi juga menambahkan resistor pembatas arus dan membuatnya terlihat rapi.
LED daun terhubung terpisah masing-masing ke pin output terdekat Arduino. LED cabang dikelompokkan oleh dua dan terhubung ke pin PWM. LED inti juga dikelompokkan oleh dua dan terhubung ke pin yang tersisa. Arduino NANO hanya memiliki 18 pin output (A6 dan A7 hanya input) dan saya membutuhkan satu pin untuk sensor sentuh, yang membuat saya hanya memiliki 17 pin jadi dua pasang LED inti terhubung bersama untuk menciptakan grup 4. Saya menggunakan resistor 220Ω untuk membatasi arus yang mengalir melalui setiap pin sekitar 8mA. Ini berarti 240mA secara keseluruhan yang cukup tinggi untuk chip ATmega328 tetapi berfungsi - batas aman dikatakan adalah 200mA.
Sensor Sentuh
Untuk dapat berinteraksi dengan salju, saya menambahkan tiang metalik lain untuk membuat sensor sentuh kapasitif. Saya menemukan pustaka dan tutorial yang bagus oleh Paul Stoffregen. Sensor sentuh digunakan untuk berinteraksi dengan arduinoflake - mengubah animasi, menyala/mematikan, bersinar saat disentuh, dan sebagainya...
Catatan Akhir
Jangan lupa untuk memeriksa semua dioda sebelum memasangnya dengan las, akan cukup sulit untuk menukarnya jika rusak atau terhubung dengan polaritas terbalik.
Kode
Pada awalnya saya pikir saya hanya akan dapat melembutkan LED cabang yang terhubung ke pin PWM hardware. Namun, untungnya terdapat pustaka PWM perangkat lunak yang luar biasa yang memungkinkan saya menggunakan semua pin seolah-olah mereka PWM hardware. Pengaturan ini menciptakan kemungkinan tak terbatas untuk animasi! Periksa kode yang dilampirkan di bawah ini dengan beberapa animasi pertama.
Kode
snowflake.ino
#include "SoftPWM.h"
#include <ADCTouchSensor.h>
byte edgeLedPins[] = {13, A4, A5, 2, 8, 12};
byte middleLedPins[] = {10, 6, 3, 5, 9, 11};
byte innerLedPins[] = {A2, A3, A1, 4, 7, A1};
ADCTouchSensor touchSensor = ADCTouchSensor(A0, 1);
void setup() {
Serial.begin(115200);
SoftPWMBegin();
}
byte animation = 0;
long touchAt = 0;
void loop() {
switch (animation) {
case 0: _fill(100); break;
case 1: shinyAnimation(); break;
case 2: circleAnimation(); break;
case 3: loopAnimation(); break;
case 4: fireworkAnimation(); fireworkAnimation(); fireworkAnimation(); fireworkAnimation(); fireworkAnimation(); fireworkAnimation(); animation ++; break;
case 5: smileAnimation(); break;
default: animation = 0; break;
}
int touchValue = touchSensor.read();
if (touchAt + 2000 < millis() && touchValue > 1000) {
touchAt = millis();
animation ++; _fill(0);
}
}
void fireworkAnimation() {
for (int i = 0; i < 4; i++) { SoftPWMSet(innerLedPins[i], 100); delay(100); }
SoftPWMSet(innerLedPins[4], 100);
for (int i = 0; i < 6; i++) { SoftPWMSet(middleLedPins[i], 255); }
delay(50);
for (int i = 0; i < 6; i++) { SoftPWMSet(innerLedPins[i], 0); SoftPWMSet(edgeLedPins[i], 255); }
delay(50);
for (int i = 0; i < 6; i++) { SoftPWMSet(middleLedPins[i], 0); }
delay(50);
_fill(0);
}
void smileAnimation() {
SoftPWMSet(innerLedPins[1], 100); SoftPWMSet(innerLedPins[3], 100);
SoftPWMSet(middleLedPins[0], 255); SoftPWMSet(middleLedPins[5], 255);
SoftPWMSet(edgeLedPins[2], 255); SoftPWMSet(edgeLedPins[3], 255);
delay(2000);
SoftPWMSet(innerLedPins[1], 0); SoftPWMSet(innerLedPins[3], 0); delay(100);
SoftPWMSet(innerLedPins[1], 100); SoftPWMSet(innerLedPins[3], 100); delay(100);
SoftPWMSet(innerLedPins[1], 0); SoftPWMSet(innerLedPins[3], 0); delay(100);
}
byte circleState[] = {100, 55, 10};
byte circleStateAnimation[] = {1, 1, 1};
void circleAnimation() {
for (int i = 0; i < 3; i++) {
if (circleState[i] >= 100) circleStateAnimation[i] = -1;
else if (circleState[i] <= 10) circleStateAnimation[i] = 1;
circleState[i] += circleStateAnimation[i];
}
for (int i = 0; i < 6; i++) {
SoftPWMSet(innerLedPins[i], circleState[0]);
SoftPWMSet(middleLedPins[i], circleState[1]);
SoftPWMSet(edgeLedPins[i], circleState[2]);
}
delay(5);
}
byte waveState[] = {100, 55, 10, 10, 55, 100};
byte waveStateAnimation[] = {1, 1, 1, -1, -1, -1};
void waveAnimation() {
for (int i = 0; i < 6; i++) {
if (waveState[i] >= 100) waveStateAnimation[i] = -1;
else if (waveState[i] <= 10) waveStateAnimation[i] = 1;
waveState[i] += waveStateAnimation[i];
}
for (int i = 0; i < 6; i+=2) {
SoftPWMSet(innerLedPins[i], waveState[0]);
SoftPWMSet(middleLedPins[i], waveState[1]);
SoftPWMSet(edgeLedPins[i], waveState[2]);
SoftPWMSet(innerLedPins[i + 1], waveState[3]);
SoftPWMSet(middleLedPins[i + 1], waveState[4]);
SoftPWMSet(edgeLedPins[i + 1], waveState[5]);
}
delay(10);
}
byte loopCounter = 0; byte loopState = 150;
void loopAnimation() {
SoftPWMSet(innerLedPins[loopCounter], loopState);
SoftPWMSet(middleLedPins[loopCounter], loopState);
SoftPWMSet(edgeLedPins[loopCounter], loopState);
loopCounter = _nextIndex(loopCounter, 1);
if (loopCounter == 0) loopState = (loopState == 150 ? 0 : 150);
delay(100);
}
byte slowOnCounter = 0; byte slowOnState = 150;
void slowOnAnimation() {
byte randomLed = random(0, 18);
if (randomLed < 6) SoftPWMSet(innerLedPins[randomLed], slowOnState);
else if (randomLed < 12) SoftPWMSet(middleLedPins[randomLed - 6], slowOnState);
else SoftPWMSet(edgeLedPins[randomLed - 12], slowOnState);
slowOnCounter++;
if (slowOnCounter >= 50) { slowOnCounter = 0; slowOnState = (slowOnState == 150 ? 0 : 150); }
delay(50);
}
byte shinyState[] = {0, 100, 0, 100, 0, 100};
byte shinyStateAnimation[] = {1, 1, 1, 1, 1, 1};
byte shinyCounter = 0;
void shinyAnimation() {
for (int i = 0; i < 6; i++) {
if (shinyState[i] >= 100) shinyStateAnimation[i] = -1;
else if (shinyState[i] <= 0) shinyStateAnimation[i] = 1;
shinyState[i] += shinyStateAnimation[i];
SoftPWMSet(edgeLedPins[i], shinyState[i]);
}
shinyCounter++;
if (shinyCounter > 10) {
shinyCounter = 0;
for (byte r = random(1, 3); r > 0; r--) {
byte randomLed = random(0, 12);
if (randomLed < 6) SoftPWMSet(innerLedPins[random(0, 6)], 255);
else SoftPWMSet(middleLedPins[random(0, 6)], 255);
}
} else {
for (int i = 0; i < 6; i++) {
SoftPWMSet(innerLedPins[i], 20);
SoftPWMSet(middleLedPins[i], 20);
}
}
delay(30);
}
byte fadingState[] = {0, 100, 0, 100, 0, 100};
byte fadingStateAnimation[] = {1, 1, 1, 1, 1, 1};
void fadingAnimation() {
for (int i = 0; i < 6; i++) {
if (fadingState[i] >= 100) fadingStateAnimation[i] = -1;
else if (fadingState[i] <= 0) fadingStateAnimation[i] = 1;
fadingState[i] += fadingStateAnimation[i];
SoftPWMSet(edgeLedPins[i], fadingState[i]);
SoftPWMSet(middleLedPins[_nextIndex(i, 1)], fadingState[i]);
SoftPWMSet(innerLedPins[i], 50);
}
delay(20);
}
void _fill(byte value) {
for (int i = 0; i < 6; i++) {
SoftPWMSet(edgeLedPins[i], value);
SoftPWMSet(middleLedPins[i], value);
SoftPWMSet(innerLedPins[i], value);
}
}
byte _prevIndex(short index, byte step) {
index -= step;
while (index < 0) index += 6;
return index;
}
byte _nextIndex(short index, byte step) {
index += step;
while (index > 5) index -= 6;
return index;
}
Skematik
Diagram rangkaian tersedia dalam dokumentasi proyek.