Flocon de neige Arduino DIY : Projet d'affichage LED à 30 LED
Composants et fournitures
| Arduino Nano R3 | × | 1 |
À propos de ce projet
Le flocon de neige se compose de 30 LED regroupées en 17 segments indépendants qui peuvent être contrôlés séparément par le microcontrôleur Arduino Nano. Chaque groupe de LED peut être atténué avec PWM pour créer de belles animations.
Outils
Tout ce dont vous aurez besoin : fer à souder, étain, et pinces.
Construction
Tout d'abord, choisissez un motif. J'ai choisi un joli et simple cristal de flocon de neige et l'ai imprimé à la taille pour faire entrer l'Arduino Nano à l'intérieur de l'hexagone - le cœur du cristal.
La structure de support qui agit aussi comme câblage est créée à partir de tiges de laiton de 0,8 mm soudées ensemble avec de l'étain. J'ai utilisé 2 m de tige au total. Pourquoi du « freeform » ? Parce que je voulais toujours essayer cela et c'est un test de votre patience et de votre habileté.
D'abord, j'ai créé un hexagone central en pliant une seule tige et en soudant les bouts ensemble. En ajoutant 6 autres tiges aux sommets de l'hexagone, le câblage de masse est complet. Toutes les cathodes des LED doivent maintenant y être soudées pour créer le motif de flocon. La partie délicate était l'ajout des LED CMS, mais je me suis aidé avec un gabarit fait de carton et de ruban double face.
Ensuite, il a fallu ajouter le microcontrôleur Arduino Nano sous la structure centrale en laissant assez d'espace entre les deux pour faire passer 3 couches de câblage en tige de laiton qui connecteront les broches du microcontrôleur à toutes les anodes des LED. Cela a demandé une quantité énorme de patience. Non seulement il faut éviter les courts-circuits entre les fils, mais aussi ajouter une résistance de limitation de courant et faire en sorte que ça ait belle allure.
Les LED des feuilles sont connectées séparément chacune à la broche de sortie Arduino la plus proche. Les LED des branches sont groupées par deux et connectées aux broches PWM. Les LED du cœur sont aussi groupées par deux et connectées aux broches restantes. L'Arduino Nano n'a que 18 broches de sortie (A6 et A7 sont entrée seulement) et j'en ai besoin d'une pour le capteur tactile, il ne me restait que 17 broches. Donc les deux paires de LED du cœur sont connectées ensemble pour créer un groupe de 4. J'utilise des résistances de 220 Ω pour limiter le courant traversant chaque broche à environ 8 mA. Cela fait 240 mA au total, ce qui est un peu élevé pour la puce ATmega328 mais ça marche - le maximum sûr est dit être 200 mA.
Capteur tactile
Pour pouvoir interagir avec le flocon, j'ai ajouté une autre tige de laiton pour créer un capteur tactile capacitif. J'ai trouvé une excellente bibliothèque et tutoriel de Paul Stoffregen. Le capteur tactile est utilisé pour interagir avec l'arduinoflake - changer d'animation, allumer/éteindre, scintiller quand on touche, etc.
Note finale
N'oubliez pas de vérifier toutes les diodes avant de souder, il sera très difficile de les échanger si elles sont cassées ou connectées en polarité inversée.
Code
Au départ, je pensais ne pouvoir atténuer que les LED des branches connectées aux broches PWM matérielles. Mais heureusement, il existe une formidable bibliothèque PWM logicielle qui m'a permis d'utiliser toutes les broches comme si elles étaient des PWM matérielles. Cette configuration a créé des possibilités infinies pour les animations ! Regardez le code ci-joint avec certaines des premières animations.
Code
snowflake.ino (Arduino)
#include "SoftPWM.h"
#include
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;
}
Schémas
Schéma de câblage du flocon de neige Arduino
Processus de fabrication
- Comment les goujons (dowel pins) assurent la précision de vos projets : usages en meubles, étagères, machines
- Matériaux des goujons : bois, métal et plastique expliqués
- 5 facteurs clés pour sélectionner les bons goupilles cylindriques
- Le rouleau à pâtisserie : des origines étrusques à l'artisanat moderne
- L'évolution et l'artisanat des quilles de bowling modernes
- Des fibules antiques à la fabrication moderne : l'épingle de sûreté expliquée
- TinyML : les ingénieurs s'unissent pour standardiser l'IA sur systèmes ultra-basse consommation
- Construire un Câble de Déport I/O et un Adaptateur Plugboard pour Raspberry Pi — Guide Étape par Étape
- Ball Grid Array (BGA) : Qu'est-ce que c'est et Pourquoi c'est Important