Construire un cube LED RGB 8x8x8 avec Arduino – Guide DIY
Composants et fournitures
| Composant | Quantité | Notes |
|---|---|---|
| LED RGB diffuse anode commune | 512 | |
| Pilote LED DM13A | 12 | |
| Décodeur 74HC138 3 vers 8 lignes | 1 | |
| MOSFET P-channel IRF9640 | 8 | |
| Arduino UNO | 1 | Version breadboard possible avec ATmega328, quartz 16MHz, 2x 22pF |
| Alimentation 5V 2,5A à découpage (Digilent) | 1 | |
| Résistance 10k Ω | 8 | |
| Résistance 1k Ω | 8 | |
| Résistance 100 Ω | 8 |
Applications et services en ligne
- Arduino IDE
À propos du projet
Vidéo
Vidéo de démonstration disponible.
Construction
Cette construction a été inspirée par le cube RGB de Kevin Darrah.
En regardant la construction de Kevin, sa patience doit être sans limites - malheureusement la mienne ne l'est pas. J'ai décidé de remplacer les 24 registres à décalage, 192 transistors et 640 résistances par 12 pilotes LED DM13A (environ 1 $ US pièce sur eBay).
Le cube lui-même a été construit comme décrit par Kevin dans la vidéo suivante :
Une fois le cube fait, j'ai créé un circuit imprimé avec la méthode au toner pour accueillir les puces DM13A et le cube. Plutôt que de payer un circuit commercial avec métalisation traversante, j'ai choisi de câbler à la main chaque connexion LED vers la broche DM13A appropriée avec du fil wrap. Les fichiers Eagle inclus contiennent la version câblée à la main ainsi qu'une version à routage automatique (non testée).
La carte microprocesseur et anodes contient aussi un MSGEQ7 - Égaliseur graphique 7 bandes et préampli micro que je prévois d'expérimenter plus tard. Pour l'instant, ils ne sont pas utilisés. Si vous voulez utiliser une carte UNO ou Nano commerciale, tout ce dont vous avez besoin est le décodeur 74HC138 3 vers 8 lignes et les 8 MOSFET P-channel avec leurs résistances associées. Vous pouvez simplement les câbler sur une plaque d'essai.
L'alimentation 5V 20W a été achetée sur eBay. J'ai fait le boîtier en pin dressé 40mm x 9mm.
J'ai ajouté quelques animations au logiciel du cube de Kevin mais il reste essentiellement inchangé.
Conclusion
Vous devriez pouvoir acheter 600 LEDs RGB 5mm anode commune diffuse sur eBay pour environ 30 $ US. Même en simplifiant l'électronique, la construction du cube a été très chronophage mais au final, gratifiante.
Code
Cube_8x8x8_V1.ino (C/C++)
/* The 8x8x8 RGB LED Cube by John Bradnam based on work by Kevin Darrah
* Latest V12 04/17/2013
* Release Notes:
* V11 - Fixed bug with BAM timing - Moved Blank pin setup to ISR so pins are dead until they are written to
* V12 bitwise operation to set pins LOW was incorrect should be PORTx &= ~(1< 250 kHz
TIMSK1 = B00000010; // Interruption sur match OCR1A
OCR1A = 30; // Interruption tous les (30+1)*4us = 124us -> ~8 kHz multiplex
pinMode(LATCH_PIN, OUTPUT);
pinMode(DATA_PIN, OUTPUT);
pinMode(CLOCK_PIN, OUTPUT);
pinMode(LAYER_A, OUTPUT);
pinMode(LAYER_B, OUTPUT);
pinMode(LAYER_C, OUTPUT);
digitalWrite(LAYER_A, LOW);
digitalWrite(LAYER_B, LOW);
digitalWrite(LAYER_C, LOW);
pinMode(SWITCH_PGM, INPUT);
pinMode(SWITCH_SEQ, INPUT);
SPI.begin();
interrupts();
}
void loop() {
if (digitalRead(SWITCH_PGM) == HIGH) test_leds();
else {
clean();
animation++;
switch (animation) {
case 1: rainVersionTwo(20); break;
case 2: folder(10); break;
case 3: sinwaveTwo(15); break;
case 4: randomColor(10); break;
case 5: wipe_out(10); break;
case 6: bouncyvTwo(15); break;
case 7: color_wheelTWO(10); break;
case 8: harlem_shake(); break;
case 9: ripples(10); break;
case 10: animation = 0; break;
}
}
}
void LED(int level, int row, int column, byte red, byte green, byte blue) {
// Routine de mise à jour d'une LED avec position et luminosité RVB (0-15)
level = constrain(level, 0, CUBE_MAX);
row = constrain(row, 0, CUBE_MAX);
column = constrain(column, 0, CUBE_MAX);
red = constrain(red, 0, 15);
green = constrain(green, 0, 15);
blue = constrain(blue, 0, 15);
int wholebyte = (level * LEDS_PER_LEVEL) + (row * CUBE_SIZE) + column;
int whichbyte = int(wholebyte / 8);
int whichbit = (wholebyte & 7);
// Écriture des 4 bits de chaque couleur dans les 4 tableaux correspondants
bitWrite(red0[whichbyte], whichbit, bitRead(red, 0));
bitWrite(red1[whichbyte], whichbit, bitRead(red, 1));
bitWrite(red2[whichbyte], whichbit, bitRead(red, 2));
bitWrite(red3[whichbyte], whichbit, bitRead(red, 3));
bitWrite(green0[whichbyte], whichbit, bitRead(green, 0));
bitWrite(green1[whichbyte], whichbit, bitRead(green, 1));
bitWrite(green2[whichbyte], whichbit, bitRead(green, 2));
bitWrite(green3[whichbyte], whichbit, bitRead(green, 3));
bitWrite(blue0[whichbyte], whichbit, bitRead(blue, 0));
bitWrite(blue1[whichbyte], whichbit, bitRead(blue, 1));
bitWrite(blue2[whichbyte], whichbit, bitRead(blue, 2));
bitWrite(blue3[whichbyte], whichbit, bitRead(blue, 3));
}
// Routine d'interruption Timer1 : Multiplexage + BAM
ISR(TIMER1_COMPA_vect) {
PORTD |= 1 << BLANK_PIN; // Éteindre toutes les LEDs
if (BAM_Counter == (CUBE_SIZE * 1)) BAM_Bit++;
else if (BAM_Counter == (CUBE_SIZE * 3)) BAM_Bit++;
else if (BAM_Counter == (CUBE_SIZE * 7)) BAM_Bit++;
BAM_Counter++;
int bytes_per_level = LEDS_PER_LEVEL / 8;
int shift_max = level + bytes_per_level;
switch (BAM_Bit) {
case 0:
for (int shift_out = level; shift_out < shift_max; shift_out++) SPI.transfer(blue0[shift_out]);
for (int shift_out = level; shift_out < shift_max; shift_out++) SPI.transfer(green0[shift_out]);
for (int shift_out = level; shift_out < shift_max; shift_out++) SPI.transfer(red0[shift_out]);
break;
case 1:
for (int shift_out = level; shift_out < shift_max; shift_out++) SPI.transfer(blue1[shift_out]);
for (int shift_out = level; shift_out < shift_max; shift_out++) SPI.transfer(green1[shift_out]);
for (int shift_out = level; shift_out < shift_max; shift_out++) SPI.transfer(red1[shift_out]);
break;
case 2:
for (int shift_out = level; shift_out < shift_max; shift_out++) SPI.transfer(blue2[shift_out]);
for (int shift_out = level; shift_out < shift_max; shift_out++) SPI.transfer(green2[shift_out]);
for (int shift_out = level; shift_out < shift_max; shift_out++) SPI.transfer(red2[shift_out]);
break;
case 3:
for (int shift_out = level; shift_out < shift_max; shift_out++) SPI.transfer(blue3[shift_out]);
for (int shift_out = level; shift_out < shift_max; shift_out++) SPI.transfer(green3[shift_out]);
for (int shift_out = level; shift_out < shift_max; shift_out++) SPI.transfer(red3[shift_out]);
if (BAM_Counter == (CUBE_SIZE * 15)) { BAM_Counter = 0; BAM_Bit = 0; }
break;
}
digitalWrite(LAYER_A, bitRead(anodeLevel, 0));
digitalWrite(LAYER_B, bitRead(anodeLevel, 1));
digitalWrite(LAYER_C, bitRead(anodeLevel, 2));
PORTD |= 1 << LATCH_PIN; // Latch HIGH
PORTD &= ~(1 << LATCH_PIN); // Latch LOW
PORTD &= ~(1 << BLANK_PIN); // Blank LOW -> LEDs ON
anodeLevel = (anodeLevel + 1) & CUBE_MAX;
level = (level + bytes_per_level) & (LEDS_PER_LEVEL - 1);
pinMode(BLANK_PIN, OUTPUT);
}
// ... Animations (rainVersionTwo, folder, sinwaveTwo, randomColor, wipe_out, bouncyvTwo, color_wheelTWO, harlem_shake, ripples)
// Le code complet est très long, voir le fichier source ou GitHub.
Le code complet a été tronqué pour l'affichage. Téléchargez le fichier source pour la version intégrale.
Schémas
eagle_files_WfqPEUP7Mp.zip
Processus de fabrication
- Alerte Soif Plante Intelligente – Capteur DIY pour une Hydratation Optimale
- Construire un superbe cube LED 5x5x5 avec Arduino Mega
- Horloge à Mots Italienne avec Arduino Nano, NeoPixel, LCD et RTC
- Compteur kWh Sigfox fiable avec Arduino MKR Fox 1200
- Mélangeur de couleurs RVB Arduino – Projet DIY débutant
- Moniteur de température Bluetooth avec Arduino Nano
- Projecteurs RGB LED extérieurs DMX – Abordables et haute performance
- Circuit d'entrée analogique isolée pour Arduino : Protection contre les parasites industriels
- Test Précis de Temps de Réaction avec Arduino UNO