Guides · 21 min de lecture

Cube LED Arduino : fabriquer un cube 3x3x3 et 4x4x4 avec le code

Fabriquer un cube LED avec Arduino : gabarit de soudure, montage 3x3x3 et 4x4x4, couches pilotées par transistors, résistances, 74HC595 et code d'animation.

Un cube LED est l'un des projets lumineux les plus spectaculaires que tu puisses réaliser avec Arduino : des LED disposées dans une grille en trois dimensions s'allument couche par couche pour dessiner des plans qui tournent, des gouttes de pluie qui tombent et des cubes qui grandissent et rétrécissent dans l'air. Pour ton premier cube LED avec Arduino, le mieux est de commencer par un 3x3x3 (27 LED) ou un 4x4x4 (64 LED) ; à cette taille, les broches d'un Arduino Uno, quelques transistors et un peu de patience au fer à souder suffisent. L'astuce consiste à ne pas donner une broche à chaque LED, mais à utiliser le multiplexage couches-colonnes : tu pilotes 27 LED avec 12 broches, et 64 LED avec seulement 7 broches grâce à deux puces 74HC595.

Dans ce guide, tu vas apprendre comment fonctionne un cube LED, comment fabriquer un gabarit de soudure, comment assembler les couches étape par étape, pourquoi les couches doivent être pilotées par des transistors et comment calculer les résistances. Tu trouveras ensuite un code Arduino qui joue des animations stockées dans des tableaux sur un cube 3x3x3, le passage à un cube 4x4x4 avec le 74HC595, des versions pour ESP32 et Raspberry Pi Pico (MicroPython), l'alternative WS2812B pour un cube en couleur et les solutions aux erreurs de montage les plus courantes, comme une LED inversée ou une soudure froide.

LED de 5 mm pour un cube LED
La brique de base d'un cube LED est la LED de 5 mm : la patte longue est l'anode (+), la patte courte et le méplat du boîtier indiquent la cathode (−).

Qu'est-ce qu'un cube LED et comment fonctionne-t-il ?

Un cube LED est formé de couches horizontales de LED régulièrement espacées, empilées les unes sur les autres. Dans chaque couche, les pattes de cathode (−) de toutes les LED sont soudées ensemble : chaque couche possède ainsi une seule ligne de cathode commune. Les pattes d'anode (+) des LED placées les unes au-dessus des autres sont soudées verticalement et forment les colonnes. Un cube 3x3x3 compte 3 couches et 9 colonnes, un cube 4x4x4 compte 4 couches et 16 colonnes. Chaque LED se trouve exactement au croisement d'une couche et d'une colonne : pour allumer une LED, tu appliques une tension positive sur sa colonne et tu relies sa couche au GND.

Tu peux repérer chaque LED du cube avec trois coordonnées : x (de gauche à droite), y (de l'avant vers l'arrière) et z (de bas en haut). Dans le code de cet article, le numéro de colonne se calcule avec c = y × 3 + x (c = y × 4 + x pour un 4x4x4), et z est le numéro de couche. Comme un pixel sur un écran, un point lumineux du cube s'appelle un voxel (pixel de volume). Créer une animation revient en fait à décider quels voxels s'allument à quel moment.

Comment fonctionne le multiplexage couches-colonnes ?

Si tu allumes plusieurs couches en même temps, la tension positive d'une colonne allume une LED dans chaque couche active de cette colonne, et tu ne peux pas dessiner le motif voulu. C'est pourquoi le cube est balayé couche par couche : l'Arduino éteint d'abord toutes les couches, écrit sur les broches le motif de colonnes de la première couche, allume uniquement cette couche pendant quelques millisecondes, puis l'éteint et passe à la deuxième. Quand cette boucle se répète plus de cent fois par seconde, l'œil garde la lumière un court instant (persistance rétinienne) et tu vois toutes les couches allumées en même temps.

Calculer la vitesse de balayage est simple : fréquence de rafraîchissement = 1 / (nombre de couches × durée par couche). Si tu laisses chaque couche d'un cube 3x3x3 allumée 3 ms, un tour dure 9 ms et le cube se rafraîchit environ 110 fois par seconde. Sur un 4x4x4 avec 2 ms par couche, le tour dure 8 ms, soit 125 Hz. En dessous de 50–60 Hz, l'œil perçoit un scintillement ; au-dessus de 100 Hz, il paraît parfaitement stable à l'œil et les bandes sont moins visibles à la caméra d'un téléphone. Le prix à payer est la luminosité : comme chaque couche n'est allumée que 1/3 du temps (1/4 sur un 4x4x4), le courant moyen d'une LED tombe à cette fraction de son courant instantané.

CubeLEDColonnes + couchesBroches en commande directeBroches avec 74HC595Broches sans multiplexage
3x3x3279 + 3123 + 3 = 627
4x4x46416 + 4203 + 4 = 764
5x5x512525 + 5303 + 5 = 8125
8x8x851264 + 8723 + 8 = 11512

Liste du matériel

MatérielCube 3x3x3Cube 4x4x4 (avec 74HC595)
LED de 5 mm (une seule couleur, diffusante de préférence)27 + 3 de rechange64 + 6 de rechange
Résistance de colonne9 × 220 Ω16 × 330 Ω (bleu, blanc) ou 470 Ω (rouge, jaune)
Transistor NPN (couche)3 × 2N2222A ou BC3374 × 2N2222A ou BC337
Résistance de base3 × 470 Ω4 × 470 Ω
Registre à décalageInutile2 × 74HC595 (74HCT595 pour ESP32 et Pico) + 100 nF chacun
Carte de commandeArduino Uno ou NanoArduino Uno, Nano, ESP32 ou Pico
MontagePlaque à pastilles, fil rigide finPlaque à pastilles, fil de cuivre étamé de 0,5–0,8 mm
OutilsFer à souder, étain, pince coupante, pince plate, foret de 5 mmMêmes outils + cales de même hauteur
Arduino Uno
Arduino Uno
220 Ω
220 Ω
Breadboard
Breadboard
Jumper
Jumper

Fabriquer un gabarit de soudure

Le secret d'un cube bien droit, c'est le gabarit. Si tu soudes les LED en les tenant à la main, les écarts varient, les couches penchent et le cube paraît tordu. Le gabarit est une planche percée de trous régulièrement espacés dans lesquels les LED se posent tête en bas, dôme vers le bas. L'écart dépend de la longueur de la patte de cathode : sur la plupart des LED de 5 mm, la patte courte mesure environ 25 mm, mais mesure tes propres LED à la règle. Quand tu plies la patte à 90° à 2–3 mm du boîtier, la partie horizontale restante doit chevaucher la patte de la LED voisine sur 2–3 mm ; c'est pourquoi un écart de 20 mm est un bon point de départ.

  1. Trace à la règle une grille de 3x3 (ou 4x4) sur du contreplaqué, du MDF ou un carton épais, avec 20 mm entre les points et au moins 2 cm de marge par rapport aux bords.
  2. Marque d'abord chaque point avec un clou, puis perce-le bien droit avec un foret de 5 mm. La LED doit tenir dans le trou mais en sortir sans forcer ; si elle est trop serrée, agrandis légèrement le trou.
  3. Dessine sur un bord du gabarit une flèche qui indique le sens de la cathode ; la patte courte de toutes les LED pointera dans la même direction.
  4. Prépare quatre cales de même hauteur, adaptées à l'écart entre les couches, qui porteront la couche supérieure pendant l'assemblage ; des chutes de tasseau ou du carton plié font l'affaire.
Avant de souder, teste les LED une par une : il suffit de poser la patte longue sur le plus et la patte courte sur le moins d'une pile bouton CR2032 de 3 V. Le mode test diode du multimètre allume aussi faiblement une LED. Dessouder une LED défectueuse au milieu d'un cube est très difficile. Pour le rendu, choisis des LED diffusantes ; les LED transparentes concentrent la lumière dans une direction, et le cube brille de façon irrégulière quand on le regarde de côté. Tu peux dépolir le dôme des LED transparentes avec un papier abrasif fin.

Montage pas à pas : couches et colonnes

  1. Plie les pattes : Plie à 90° à l'horizontale la patte courte (cathode) de chaque LED, à 2–3 mm du boîtier, en direction de la flèche du gabarit. La patte longue (anode) reste verticale.
  2. Place la première couche : Mets les LED dans les trous, dôme vers le bas. Chaque patte de cathode d'une rangée doit toucher la patte de cathode de la LED suivante ; celle de la dernière LED de la rangée peut rester libre.
  3. Soude les cathodes : Soude chaque point de contact en 2–3 secondes maximum avec le fer à 320–350 °C. Soude ensuite un fil droit (une patte de résistance coupée ou du fil de cuivre étamé) en travers des extrémités des rangées pour les relier. La couche devient à la fois une seule ligne électrique et un cadre solide ; sur un 4x4x4, un fil à chaque extrémité la rigidifie encore davantage.
  4. Teste la couche : Sans sortir la couche du gabarit, relie la ligne de cathode au GND et touche chaque patte d'anode avec 5 V à travers une résistance de 220 Ω. Si une LED ne s'allume pas, remplace-la maintenant.
  5. Prépare les autres couches : Recommence jusqu'à obtenir 3 (ou 4) couches. Garde les pattes de cathode orientées dans le même sens sur chaque couche pour que les colonnes tombent exactement les unes au-dessus des autres.
  6. Assemble les couches : Laisse une couche dans le gabarit et aligne la suivante juste au-dessus, posée sur les cales. Fais un petit coude de 2 mm au bout de chaque patte d'anode tournée vers le haut des LED du dessous, pour qu'elle passe à côté du boîtier de la LED du dessus et s'appuie contre sa patte d'anode. Soude d'abord les quatre coins, vérifie l'alignement, puis termine les autres colonnes.
  7. Sors les fils de couche : Soude un fil sur la ligne de cathode de chaque couche et fais-le descendre le long d'un côté du cube. Ces fils ne doivent toucher ni les autres fils ni les colonnes ; laisse quelques millimètres entre eux.
  8. Monte le cube sur sa base : Retourne le cube ; les pattes d'anode libres de la dernière couche ajoutée pointent maintenant vers le bas, et cette couche devient la plus proche de la base, c'est-à-dire la couche du bas (z = 0). Passe les pattes et les fils de couche à travers une plaque à pastilles, soude-les et place les résistances de colonne à côté de chaque colonne.
L'erreur de montage la plus coûteuse est une seule LED inversée. Elle ne se contente pas de rester éteinte : quand une broche de colonne est à LOW, elle ouvre un chemin de courant en sens inverse depuis la ligne de couche vers cette colonne, et des LED fantômes peuvent s'allumer sur des couches qui devraient être éteintes. Vérifie que la patte courte (le méplat du boîtier) pointe vers la flèche chaque fois que tu poses une LED dans le gabarit, et teste toujours chaque couche avant de l'assembler.

Piloter les couches avec des transistors

Transistor NPN
Le courant d'une couche passe par un transistor NPN, pas par la broche de l'Arduino : le 2N2222A (E-B-C) ou le BC337 (C-B-E) sont de bons choix.

Une broche de colonne n'alimente qu'une seule LED, mais quand une couche est allumée, le courant de toutes ses LED retourne au GND par la même ligne de cathode. Sur un cube 3x3x3, cela fait 9 LED × 12,7 mA ≈ 115 mA, et sur le cube 4x4x4 avec 74HC595, 16 LED × 5 mA ≈ 80 mA. La limite recommandée pour une broche d'Arduino Uno est de 20 mA et le maximum absolu de 40 mA : tu ne peux donc pas relier une ligne de couche directement à une broche. La solution est un transistor NPN sous chaque couche : le collecteur va à la ligne de couche, l'émetteur au GND et la base à une broche de l'Arduino à travers une résistance. Quand la broche passe à HIGH, le transistor se sature et tire la couche au GND. Pour que le transistor conduise pleinement, choisis un courant de base d'environ 1/10 à 1/20 du courant de collecteur : pour 115 mA, il faut 6–12 mA, et (5 V − 0,7 V) / 470 Ω ≈ 9 mA tombe pile dans cette plage. Pour les détails, consulte Qu'est-ce qu'un transistor ?, et pour les brochages l'outil transistors.

TransistorIC continuOrdre des pattes (face marquée devant)Usage dans un cube LED
BC547100 mAC-B-ESeulement pour les cubes à faible courant ; les 115 mA d'un 3x3x3 dépassent sa limite
2N2222A600 mAE-B-CIdéal pour 3x3x3 et 4x4x4
BC337800 mAC-B-EIdéal pour 3x3x3 et 4x4x4
IRLZ44N (MOSFET niveau logique)Des dizaines d'ampèresG-D-SGrands cubes comme le 8x8x8 ; 220 Ω vers la grille, 10 kΩ entre grille et GND

Calcul des résistances : colonnes et bases

La résistance de colonne est le seul composant qui limite le courant de la LED, et il y en a une par colonne ; inutile d'en mettre une par LED, car une seule LED par colonne est allumée à la fois. La formule vient de la loi d'Ohm : R = (Valim − VLED − VCE(sat)) / ILED. Avec une alimentation de 5 V, une LED rouge de 2,0 V de tension directe et un transistor qui chute d'environ 0,2 V en saturation, viser 12 mA donne R = (5 − 2,0 − 0,2) / 0,012 ≈ 233 Ω. La valeur normalisée la plus proche, 220 Ω, laisse passer environ 12,7 mA dans la LED. Avec une LED bleue de 3,1 V, les mêmes 220 Ω donnent environ 7,7 mA, une luminosité encore bien visible en multiplexage.

Couleur de LEDTension directe (VF)3x3x3, en direct sur l'Arduino (5 V)4x4x4, 74HC595 (5 V)
Rouge, jaune1,8–2,2 V220 Ω (≈12–13 mA)470 Ω (≈5–6 mA)
Vert pur, bleu2,9–3,3 V180–220 Ω (≈8–9 mA)330 Ω (≈4–5 mA)
Blanc2,9–3,4 V180–220 Ω (≈7–9 mA)330 Ω (≈4–5 mA)

Sur le cube à 74HC595, on choisit volontairement des résistances plus fortes : au total, 70 mA au maximum peuvent traverser la broche VCC ou GND de cette puce, et quand une couche est allumée, ses huit sorties peuvent toutes s'allumer en même temps. 8 × 5,5 mA ≈ 44 mA laissent une marge sûre. Le courant moyen de la LED, qui fixe la luminosité perçue, correspond au courant instantané divisé par le nombre de couches : 12,7 / 3 ≈ 4,2 mA sur un 3x3x3 et 5,5 / 4 ≈ 1,4 mA sur un 4x4x4. Les LED efficaces d'aujourd'hui restent bien visibles en intérieur avec ces courants, mais dans une pièce très lumineuse un cube 4x4x4 peut sembler un peu terne. Pour calculer avec les valeurs de ta propre LED, utilise les outils résistance de LED et tensions des LED.

Schéma de câblage du cube LED 3x3x3

LiaisonArduino Uno / NanoRemarque
Colonnes 0–8 (anodes)D2–D10Résistance série de 220 Ω sur chaque colonne
Couche du bas (z = 0)A0Vers la base du transistor 1 via 470 Ω
Couche du milieu (z = 1)A1Vers la base du transistor 2 via 470 Ω
Couche du haut (z = 2)A2Vers la base du transistor 3 via 470 Ω
Collecteurs des transistors—Chacun vers le fil de cathode de sa couche
Émetteurs des transistorsGNDLes trois vers un GND commun
Vue de dessusx = 0x = 1x = 2
y = 2 (arrière)Colonne 6 → D8Colonne 7 → D9Colonne 8 → D10
y = 1 (milieu)Colonne 3 → D5Colonne 4 → D6Colonne 5 → D7
y = 0 (avant)Colonne 0 → D2Colonne 1 → D3Colonne 2 → D4
N'utilise pas D0 et D1 pour les colonnes : ces broches sont partagées avec le téléversement par USB et le moniteur série, et des LED branchées dessus peuvent faire échouer le téléversement. C'est pourquoi le cube 3x3x3 utilise D2–D10 et A0–A2 ; les broches A0–A5 fonctionnent comme des sorties numériques ordinaires avec digitalWrite(). Le courant total reste lui aussi dans les limites : quand les neuf colonnes tirent 12,7 mA, l'Arduino fournit environ 115 mA, sous la limite totale de 200 mA de l'ATmega328P. Tu peux voir l'emplacement des broches sur la carte avec l'outil brochage.

Code Arduino du cube LED 3x3x3 : animations avec des tableaux

Chaque image de l'animation est stockée sous la forme d'un nombre par couche. Une couche 3x3x3 compte 9 LED, une valeur de 9 bits suffit donc ; on la stocke dans un uint16_t, et le bit c correspond à la colonne c. Les images sont écrites en mémoire flash avec PROGMEM, si bien que même des animations de plusieurs centaines d'images ne remplissent pas les 2 Ko de RAM du Uno. Le code ci-dessous ne nécessite aucune bibliothèque supplémentaire.

C++ (Arduino IDE)
1// 3x3x3 LED küp: katman çoklama ve dizilerle animasyon / 3x3x3 LED cube: layer multiplexing and array animations
2const byte colPins[9]   = {2, 3, 4, 5, 6, 7, 8, 9, 10};   // sütun anotları, 220 ohm ile / column anodes via 220 ohm
3const byte layerPins[3] = {A0, A1, A2};                     // alt, orta, üst katman transistörü / bottom, middle, top layer transistor
4
5// Her kare 3 katman, her katman 9 bit: bit c = sütun c (c = y*3 + x)
6// Each frame has 3 layers of 9 bits: bit c = column c (c = y*3 + x)
7const uint16_t frames[][3] PROGMEM = {
8  {0b111111111, 0b000000000, 0b000000000},  // 0: alt katman / bottom layer
9  {0b000000000, 0b111111111, 0b000000000},  // 1: orta katman / middle layer
10  {0b000000000, 0b000000000, 0b111111111},  // 2: üst katman / top layer
11  {0b000000000, 0b000010000, 0b000000000},  // 3: yalnız merkez / centre only
12  {0b111101111, 0b101000101, 0b111101111},  // 4: tel kafes, 12 kenar / wireframe, 12 edges
13  {0b010010010, 0b010010010, 0b010010010},  // 5: dönen düzlem, 1. konum / rotating plane, step 1
14  {0b100010001, 0b100010001, 0b100010001},  // 6: dönen düzlem, 2. konum / rotating plane, step 2
15  {0b000111000, 0b000111000, 0b000111000},  // 7: dönen düzlem, 3. konum / rotating plane, step 3
16  {0b001010100, 0b001010100, 0b001010100},  // 8: dönen düzlem, 4. konum / rotating plane, step 4
17  {0b111111111, 0b111111111, 0b111111111}   // 9: hepsi açık / all on
18};
19
20void setup() {
21  for (byte c = 0; c < 9; c++) pinMode(colPins[c], OUTPUT);
22  for (byte z = 0; z < 3; z++) pinMode(layerPins[z], OUTPUT);  // LOW: katmanlar kapalı / LOW: layers off
23}
24
25// Bir kareyi verilen süre boyunca katman katman tarar / scans one frame layer by layer for the given time
26void showFrame(byte f, unsigned int ms) {
27  unsigned long start = millis();
28  while (millis() - start < ms) {
29    for (byte z = 0; z < 3; z++) {
30      uint16_t bits = pgm_read_word(&frames[f][z]);         // katman verisini oku / read the layer data
31      for (byte c = 0; c < 9; c++) digitalWrite(colPins[c], bitRead(bits, c));
32      digitalWrite(layerPins[z], HIGH);                      // katmanı aç / layer on
33      delay(3);                                              // 3 ms göster / show for 3 ms
34      digitalWrite(layerPins[z], LOW);                       // sütunlar değişmeden önce kapat / off before the columns change
35    }
36  }
37}
38
39void loop() {
40  for (byte f = 0; f <= 4; f++) showFrame(f, 500);           // katmanlar, merkez, kafes / layers, centre, wireframe
41  for (byte turn = 0; turn < 4; turn++)                      // düzlemi 4 tur döndür / spin the plane 4 times
42    for (byte f = 5; f <= 8; f++) showFrame(f, 120);
43  showFrame(9, 800);                                         // hepsi açık / all on
44}

Le cœur du code est la fonction showFrame(). Pour chaque couche, elle écrit d'abord le motif des colonnes sur les broches, allume ensuite uniquement le transistor de cette couche pendant 3 ms et éteint la couche avant que les colonnes changent. Cet ordre est important : si tu changes les colonnes pendant qu'une couche est allumée, le motif de la couche précédente apparaît un instant sur la nouvelle couche et crée un effet fantôme (ghosting). bitRead(bits, c) renvoie le bit c du nombre sous forme de 0 ou 1, et pgm_read_word() lit la valeur de 16 bits en flash. loop() affiche d'abord les couches une à une, puis le centre et les 12 arêtes du cube, et fait ensuite tourner un plan vertical sur quatre positions pour créer un effet de moulinet.

Créer tes propres animations

Pour dessiner une nouvelle image, regarde le cube du dessus et imagine chaque couche comme une feuille quadrillée de 3x3. Repère les colonnes à allumer et écris le nombre binaire après 0b de gauche à droite, du bit 8 au bit 0. Les quatre coins, par exemple, sont les colonnes 0, 2, 6 et 8, ce qui donne 0b101000101. En écrivant la même valeur dans les trois couches, tu obtiens des barres verticales aux quatre coins ; en l'écrivant seulement dans la couche du milieu, quatre points flottent dans l'air. Si les nombres binaires te sont étrangers, l'article Systèmes de numération et opérations sur les bits explique tout cela en détail. Quelques techniques utiles pour programmer :

  • Décalage de bits : En décalant la valeur d'une couche de 3 bits vers la gauche sur un 3x3x3, ou de 4 bits sur un 4x4x4, le motif recule d'une rangée ; en effaçant les bits qui débordent avec &, tu obtiens des vagues et du texte défilant.
  • Copie de couches : Copier le tableau des couches d'un cran vers le bas ou vers le haut donne des effets de pluie, de bulles qui montent et d'ascenseur.
  • Hasard : Des voxels choisis avec random() qui clignotent brièvement créent un ciel étoilé ou des étincelles.
  • Inversion : L'opérateur ~ transforme une image en son négatif, et alterner rapidement entre les deux produit un flash bien visible.

Cube LED 4x4x4 : agrandir avec le 74HC595

Un cube 4x4x4 compte 16 colonnes et 4 couches ; le piloter en direct demande 20 broches, c'est-à-dire toutes celles du Uno, D0 et D1 compris. Si tu pilotes plutôt les colonnes avec deux registres à décalage 74HC595 chaînés, les 16 colonnes ne coûtent que 3 broches (données, horloge et latch) ; avec 4 broches de plus pour les couches, on arrive à 7 broches au total. La sortie Q7' (broche 9) de la première puce va à l'entrée DS de la seconde, tandis que les lignes d'horloge et de latch sont communes aux deux puces. Les colonnes 0–7 (les deux rangées avant) se branchent sur les sorties Q0–Q7 de la première puce, et les colonnes 8–15 (les deux rangées arrière) sur la seconde. La même méthode passe à 4 puces pour un cube 5x5x5 et à 8 puces pour un 8x8x8.

LiaisonArduino UnoESP32Raspberry Pi Pico
DS (14), première puceD11GPIO 23GP19
SH_CP (11), commun aux deux pucesD13GPIO 18GP18
ST_CP (12), commun aux deux pucesD10GPIO 5GP17
OE (13) / MR (10)GND / 5VGND / 5VGND / VBUS
VCC (16) / GND (8)5V / GND5V / GNDVBUS / GND
Q7' (9) → DS (14) de la seconde puceChaînageChaînageChaînage
Transistors des couches 0–3 (via 470 Ω)D2, D3, D4, D5GPIO 25, 26, 27, 32GP10, GP11, GP12, GP13
Type de puce74HC59574HCT59574HCT595
Au total, 70 mA au maximum peuvent traverser la broche VCC ou GND du 74HC595. Avec de petites résistances comme 220 Ω, une couche entièrement allumée tire 80–100 mA par puce ; la puce chauffe, sa tension de sortie chute et elle finit par lâcher. Utilise les valeurs de 330–470 Ω du tableau des résistances et place un condensateur de 100 nF entre les broches VCC et GND de chaque puce, le plus près possible des pattes.
C++ (Arduino IDE)
1// 4x4x4 LED küp: 2 adet 74HC595 (16 sütun) + 4 transistörlü katman / 4x4x4 LED cube: two 74HC595s (16 columns) + 4 transistor layers
2const byte DATA_PIN  = 11;                 // 74HC595 DS (14)
3const byte CLOCK_PIN = 13;                 // 74HC595 SH_CP (11)
4const byte LATCH_PIN = 10;                 // 74HC595 ST_CP (12)
5const byte layerPins[4] = {2, 3, 4, 5};    // alttan üste katman transistörleri, 470 ohm ile / layer transistors bottom to top, via 470 ohm
6
7uint16_t cube[4];                          // ekrandaki görüntü: katman başına 16 bit / current image: 16 bits per layer
8
9// Hazır kareler: bit c = sütun c (c = y*4 + x) / ready-made frames: bit c = column c (c = y*4 + x)
10const uint16_t frames[][4] PROGMEM = {
11  {0xFFFF, 0x0000, 0x0000, 0x0000},        // alt katman / bottom layer
12  {0x0000, 0xFFFF, 0x0000, 0x0000},
13  {0x0000, 0x0000, 0xFFFF, 0x0000},
14  {0x0000, 0x0000, 0x0000, 0xFFFF},        // üst katman / top layer
15  {0x9009, 0x0000, 0x0000, 0x9009},        // 8 köşe / 8 corners
16  {0xF99F, 0x9009, 0x9009, 0xF99F},        // tel kafes / wireframe
17  {0x0000, 0x0660, 0x0660, 0x0000}         // içteki 2x2x2 küp / inner 2x2x2 cube
18};
19const byte FRAME_COUNT = sizeof(frames) / sizeof(frames[0]);
20
21void write16(uint16_t v) {                 // 16 biti iki entegreye gönder / send 16 bits to both chips
22  digitalWrite(LATCH_PIN, LOW);
23  shiftOut(DATA_PIN, CLOCK_PIN, MSBFIRST, highByte(v));  // önce uzaktaki entegre / far chip first
24  shiftOut(DATA_PIN, CLOCK_PIN, MSBFIRST, lowByte(v));
25  digitalWrite(LATCH_PIN, HIGH);           // çıkışlara aktar / copy to the outputs
26}
27
28void refresh() {                           // her 2 ms'de sıradaki katmana geç / move to the next layer every 2 ms
29  static byte z = 0;
30  static unsigned long last = 0;
31  if (micros() - last < 2000) return;
32  last = micros();
33  digitalWrite(layerPins[z], LOW);         // eski katmanı kapat / old layer off
34  z = (z + 1) % 4;
35  write16(cube[z]);                        // yeni katmanın sütunları / columns of the new layer
36  digitalWrite(layerPins[z], HIGH);        // yeni katmanı aç / new layer on
37}
38
39void holdFor(unsigned int ms) {            // beklerken küpü yenilemeye devam et / keep refreshing while waiting
40  unsigned long start = millis();
41  while (millis() - start < ms) refresh();
42}
43
44void clearCube() {
45  for (byte z = 0; z < 4; z++) cube[z] = 0;
46}
47
48void setVoxel(byte x, byte y, byte z) {    // tek LED yak, x/y/z = 0..3 / light one LED, x/y/z = 0..3
49  bitSet(cube[z], y * 4 + x);
50}
51
52void loadFrame(byte f) {                   // PROGMEM'deki kareyi yükle / load a frame from PROGMEM
53  for (byte z = 0; z < 4; z++) cube[z] = pgm_read_word(&frames[f][z]);
54}
55
56void sweep() {                             // dikey düzlemi x ekseninde kaydır / sweep a vertical plane along x
57  for (byte x = 0; x < 4; x++) {
58    clearCube();
59    for (byte y = 0; y < 4; y++)
60      for (byte z = 0; z < 4; z++) setVoxel(x, y, z);
61    holdFor(150);
62  }
63}
64
65void rain(byte steps) {                    // yağmur: damlalar yukarıdan düşer / rain: drops fall from the top
66  clearCube();
67  for (byte s = 0; s < steps; s++) {
68    for (byte z = 0; z < 3; z++) cube[z] = cube[z + 1];   // her şeyi bir kat indir / move everything down a layer
69    cube[3] = bit(random(16)) | bit(random(16));         // üstte 1-2 yeni damla / 1-2 new drops on top
70    holdFor(120);
71  }
72}
73
74void setup() {
75  pinMode(DATA_PIN, OUTPUT);
76  pinMode(CLOCK_PIN, OUTPUT);
77  pinMode(LATCH_PIN, OUTPUT);
78  for (byte z = 0; z < 4; z++) pinMode(layerPins[z], OUTPUT);
79  randomSeed(analogRead(A0));              // boştaki A0'dan rastgele tohum / random seed from the unconnected A0
80}
81
82void loop() {
83  for (byte f = 0; f < FRAME_COUNT; f++) {
84    loadFrame(f);
85    holdFor(500);
86  }
87  for (byte i = 0; i < 3; i++) sweep();
88  rain(80);
89}

Dans cette version, le balayage se fait dans la fonction refresh() de façon non bloquante : à chaque appel, elle vérifie avec micros() si 2 ms se sont écoulées ; si oui, elle éteint l'ancienne couche, envoie les 16 bits de la nouvelle couche aux deux puces et allume la nouvelle couche. Ainsi, le code d'animation se contente de modifier le tableau cube[] sans se soucier du rafraîchissement. holdFor() continue d'appeler refresh() pendant l'attente : n'utilise donc jamais de long delay() dans le programme. setVoxel(x, y, z) te permet d'allumer une LED par ses coordonnées ; sweep() s'en sert pour faire glisser un plan vertical à travers le cube, et rain() recopie les couches d'un cran vers le bas puis ajoute des gouttes au hasard en haut. Tu trouveras la différence entre delay() et millis() dans millis() et delay(), et comment confier le balayage à une interruption de timer dans Les interruptions Arduino.

Cube LED avec l'ESP32

Les broches de l'ESP32 fournissent 3,3 V. Cela ne suffit pas pour piloter directement des LED bleues et blanches, dont la tension directe tourne autour de 3 V ; après la chute dans la résistance et le transistor, il ne reste presque rien. Sur l'ESP32, la solution la plus propre est donc de piloter les colonnes via un 74HCT595 alimenté en 5 V : la famille HCT considère déjà 2 V comme HIGH et lit sans problème les signaux de 3,3 V, tandis que les LED sont alimentées en 5 V. Garde 470 Ω sur la base des transistors de couche ; (3,3 − 0,7) / 470 ≈ 5,5 mA suffisent pour un courant de couche de 80 mA. Le code 4x4x4 ci-dessus compile tel quel sur l'ESP32 ; il suffit de remplacer les constantes de broches par les valeurs du tableau (23, 18, 5 et 25, 26, 27, 32). Si tu veux, tu peux aussi utiliser le Wi-Fi de l'ESP32 pour choisir les animations depuis une page web sur ton téléphone ; pour débuter, consulte Qu'est-ce que l'ESP32 ?.

Cube LED avec le Raspberry Pi Pico et MicroPython

Le Pico est lui aussi une carte en 3,3 V, et avec le réglage par défaut ses broches ne fournissent que quelques milliampères : tu utilises donc le même circuit à 74HCT595. Alimente les puces et les LED par VBUS (broche 40), qui transporte les 5 V de l'USB. En MicroPython, les 16 bits sont envoyés en SPI matériel : les broches GP18 (SCK) et GP19 (MOSI) de SPI0 pilotent l'horloge et les données, et GP17 le latch. Le code suit la même logique : show() balaie une image couche par couche pendant la durée indiquée, et dans l'effet de pluie le découpage de liste (cube[1:]) fait descendre chaque couche d'un cran. Pour l'installation et les premiers pas, consulte Qu'est-ce que le Raspberry Pi Pico ?.

MicroPython
1# Pico + 2 adet 74HCT595 ile 4x4x4 LED küp / 4x4x4 LED cube with a Pico + two 74HCT595s
2from machine import Pin, SPI
3import time
4import random
5
6# GP18 = SCK -> SH_CP, GP19 = MOSI -> DS; GP16 (MISO) boş kalır / GP16 (MISO) stays unconnected
7spi = SPI(0, baudrate=1000000, polarity=0, phase=0, sck=Pin(18), mosi=Pin(19))
8latch = Pin(17, Pin.OUT, value=0)                                # ST_CP
9layers = [Pin(n, Pin.OUT, value=0) for n in (10, 11, 12, 13)]    # alttan üste, 470 ohm ile / bottom to top, via 470 ohm
10
11def write16(v):
12    latch.value(0)
13    spi.write(bytes((v >> 8, v & 0xFF)))    # önce uzaktaki entegre / far chip first
14    latch.value(1)                          # çıkışlara aktar / copy to the outputs
15
16def show(frame, ms):
17    # kareyi ms boyunca katman katman tara / scan the frame layer by layer for ms
18    end = time.ticks_add(time.ticks_ms(), ms)
19    while time.ticks_diff(end, time.ticks_ms()) > 0:
20        for z in range(4):
21            write16(frame[z])
22            layers[z].value(1)              # katmanı aç / layer on
23            time.sleep_us(2000)
24            layers[z].value(0)              # sütunlar değişmeden kapat / off before the columns change
25
26FRAMES = [
27    [0x9009, 0x0000, 0x0000, 0x9009],       # 8 köşe / 8 corners
28    [0xF99F, 0x9009, 0x9009, 0xF99F],       # tel kafes / wireframe
29    [0x0000, 0x0660, 0x0660, 0x0000],       # içteki küp / inner cube
30]
31
32while True:
33    for f in FRAMES:
34        show(f, 600)
35    cube = [0, 0, 0, 0]
36    for _ in range(60):                     # yağmur: her şey bir kat iner / rain: everything drops a layer
37        drop = (1 << random.getrandbits(4)) | (1 << random.getrandbits(4))
38        cube = cube[1:] + [drop]
39        show(cube, 120)

Cubes plus grands : 5x5x5 et 8x8x8

Quand le cube grandit, deux problèmes grandissent avec lui. Le premier est le courant : un cube 8x8x8 compte 64 LED par couche, et à 10 mA par LED le courant de couche atteint 640 mA ; ce n'est plus le travail d'un petit transistor TO-92 mais d'un MOSFET à niveau logique. Le second est le temps de balayage : pour garder 100 Hz avec 8 couches, il reste 1,25 ms par couche, et il faut envoyer 64 bits (8 octets) à chaque couche ; shiftOut() est trop lent pour cela, le SPI matériel devient indispensable. En plus, chaque LED n'est allumée que 1/8 du temps, donc la luminosité baisse ; les grands cubes demandent des pilotes de colonnes plus puissants et une alimentation externe de 5 V au lieu de l'USB (voir Alimenter un Arduino). C'est pourquoi ton premier cube devrait être un 3x3x3 ou un 4x4x4 : tu maîtriseras la technique avant de souder 512 LED.

Alternative : un cube LED en couleur avec des WS2812B

LED RGB adressable WS2812B
Chaque LED WS2812B possède sa propre puce de commande ; un cube de 64 LED se pilote avec une seule broche de données.

Si tu préfères choisir la couleur de chaque LED individuellement plutôt que de construire un cube d'une seule couleur, tu peux utiliser des LED adressables comme la WS2812B. Chacune de ces LED a sa propre puce de commande : plus besoin de multiplexage, de transistors ni de résistances de colonne. Les 64 LED sont chaînées avec le 5 V, le GND et une ligne de données, et pilotées par une seule broche. Pour un cube, on utilise des LED adressables de 5 mm à 4 pattes (comme la PL9823 ou l'APA106) ou des morceaux découpés d'un ruban WS2812B. Le prix à payer est le courant : environ 60 mA par LED en blanc maximal, soit 3,8 A pour 64 LED. Utilise donc une alimentation 5 V de 4 A, ajoute un condensateur de 1000 µF sur l'alimentation et une résistance de 330 Ω sur la ligne de données, et limite la luminosité par logiciel. Le code utilise la bibliothèque Adafruit NeoPixel.

C++ (Arduino IDE)
1// WS2812B ile 4x4x4 RGB LED küp / 4x4x4 RGB LED cube with WS2812B
2#include <Adafruit_NeoPixel.h>
3
4const byte DATA_PIN = 6;                   // 330 ohm ile ilk LED'in DIN ucuna / to the first LED's DIN via 330 ohm
5const byte N = 4;
6Adafruit_NeoPixel cube(N * N * N, DATA_PIN, NEO_GRB + NEO_KHZ800);
7
8uint16_t idx(byte x, byte y, byte z) {     // koordinattan zincirdeki sıraya / coordinate to position in the chain
9  return z * 16 + y * 4 + x;               // düz (zikzaksız) kablolama varsayılır / assumes straight, non-zigzag wiring
10}
11
12void setup() {
13  cube.begin();
14  cube.setBrightness(40);                  // parlaklığı ve akımı sınırla (0-255) / limit brightness and current (0-255)
15}
16
17void loop() {
18  static uint16_t hue = 0;
19  for (byte z = 0; z < N; z++)
20    for (byte y = 0; y < N; y++)
21      for (byte x = 0; x < N; x++)         // her katman farklı tonda / each layer gets a different hue
22        cube.setPixelColor(idx(x, y, z), cube.gamma32(cube.ColorHSV(hue + z * 8192U)));
23  cube.show();
24  hue += 256;                              // gökkuşağını kaydır / shift the rainbow
25  delay(20);
26}

La fonction idx() du code convertit une coordonnée x, y, z en position dans la chaîne et suppose que tu as câblé chaque rangée dans le même sens. Si tu as fait le câblage en zigzag, il faut utiliser 3 − x au lieu de x sur les rangées impaires. Certaines LED adressables de 5 mm attendent les couleurs dans l'ordre RGB ; si tu vois du vert au lieu du rouge, remplace NEO_GRB par NEO_RGB. setBrightness(40) réduit la luminosité à environ 16 %, si bien que même dans le pire des cas le courant reste autour de 0,6 A.

CaractéristiqueCube LED monochromeCube LED WS2812B
CouleurUne seule (celle de la LED)16 millions de couleurs, LED par LED
Broches utilisées (4x4x4)7 (avec 74HC595)1
Composants en plusTransistors, résistances, 74HC595Condensateur, résistance de données, alimentation costaude
Travail de soudure2 pattes par LED4 pattes par LED, plus de fils
Réglage de luminositéMarche/arrêt (PWM par LED difficile)256 niveaux pour chaque LED
Courant (4x4x4)Environ 100 mA, l'USB suffitJusqu'à ≈3,8 A, alimentation externe obligatoire
Ce qu'on apprendMultiplexage, transistors, opérations sur les bitsAdressage, teinte, gestion de l'énergie

Idées de projets avec un cube LED

  • Cube qui danse sur la musique : Augmente le nombre de couches allumées selon le niveau sonore mesuré avec un capteur de son pour créer un égaliseur en trois dimensions.
  • Snake en 3D : Dirige le serpent sur les trois axes d'un cube 4x4x4 avec un joystick et un bouton ; pour d'autres idées de jeux, consulte Projets de jeux Arduino.
  • Cube dé : Quand tu appuies sur un bouton, les voxels se mélangent rapidement et le cube affiche un nombre de 1 à 6 sous forme de points.
  • Projet pour une fête de la science : Explique la persistance rétinienne en allongeant la durée par couche avec un potentiomètre pour montrer l'instant où le scintillement apparaît ; pour d'autres idées, consulte Idées de projets scientifiques.
  • Choisir l'animation depuis le téléphone : Chaque lettre envoyée avec un module Bluetooth HC-05 lance une animation différente.
  • Veilleuse colorée : Programme des transitions de couleurs lentes sur un cube WS2812B ; avec un ESP32, pilote les effets depuis ton téléphone grâce à WLED.

Erreurs fréquentes et solutions

SymptômeCause probableSolution
Une LED ne s'allume jamaisLED inversée ou morte, ou soudure d'une patte casséeVérifie le sens de la cathode, teste la LED avec une pile bouton et remplace-la si besoin
Des LED censées être éteintes luisent faiblement (fantôme)Les colonnes changent pendant qu'une couche est allumée, ou le cube contient une LED inverséeÉteins d'abord la couche, puis écris les colonnes ; si le code est bon, cherche la LED inversée
Les LED clignotent ou s'éteignent quand on touche le cubeSoudure froide : un joint mat, granuleux, en forme de bouleRéchauffe le joint avec une panne propre et ajoute un peu d'étain neuf
Une couche entière reste éteintePattes du transistor inversées (E-B-C confondu avec C-B-E) ou résistance de base débranchéeVérifie l'ordre des pattes dans la fiche technique et mesure la liaison de base
Une colonne entière reste éteinteLa colonne n'est pas soudée à la base, ou la résistance ou la broche est fausseMesure la colonne d'un bout à l'autre au multimètre et vérifie le tableau de broches du code
Le cube scintilleDurée par couche trop longue, ou Serial.print() ou delay() dans la boucle de balayageRègle la durée par couche sur 2–3 ms et supprime le code qui bloque le balayage
Le cube est très peu lumineuxRésistances trop fortes, LED bleues pilotées en 3,3 V ou trop de couchesRecalcule la résistance ; sur les cartes en 3,3 V, alimente le 74HCT595 en 5 V
Le croquis ne se téléverse pasUne LED est branchée sur D0 ou D1Fais commencer les colonnes à D2 ou débranche ces fils pendant le téléversement
La meilleure façon de chercher une panne est de balayer le cube avec un programme de test : écris une petite boucle qui allume chaque LED à tour de rôle pendant 200 ms. Une LED qui reste éteinte ou qui s'allume au mauvais endroit révèle aussitôt une soudure cassée ou une colonne mélangée. Une soudure froide paraît mate et granuleuse au lieu de brillante ; une bonne soudure ressemble à un cône brillant, légèrement concave, qui enveloppe la patte. Pour réviser ta technique, jette un œil à Comment souder.

Le cube LED fait partie des rares projets qui enseignent à la fois la soudure, les transistors, le calcul des résistances, le multiplexage et les opérations sur les bits. Commence par un 3x3x3, puis, une fois le code et la logique des animations maîtrisés, passe à un 4x4x4 avec le 74HC595, ou aux WS2812B si tu veux de la couleur. Si tu préfères d'abord tester l'idée d'allumer des LED à la suite sur une simple rangée, le chenillard et l'effet K2000 avec Arduino est un bon échauffement. Dans l'application BlueGrays, tu trouveras des projets de chenillard, d'effet K2000, d'animations WS2812B et de matrices LED, avec schémas de câblage et code pas à pas.

Questions fréquentes

Combien de LED et de broches faut-il pour un cube LED ?

Un cube 3x3x3 demande 27 LED et un cube 4x4x4 en demande 64 ; mieux vaut en prévoir quelques-unes de rechange. Avec le multiplexage couches-colonnes, le 3x3x3 se contente de 9 colonnes et 3 couches, soit 12 broches. Un 4x4x4 demande 20 broches en commande directe, mais si tu pilotes les colonnes avec deux 74HC595, le total tombe à 7 broches.

Quelle résistance utiliser dans un cube LED ?

On place une résistance par colonne ; pour un cube 3x3x3 piloté directement par l'Arduino en 5 V, 220 Ω est une valeur courante et sûre. Sur un cube à 74HC595, utilise 330 Ω pour les LED bleues et blanches et 470 Ω pour les rouges et jaunes afin de ne pas dépasser la limite totale de 70 mA de la puce. Pour ta propre valeur, applique R = (Valim − VLED − 0,2 V) / ILED.

Pourquoi piloter les couches d'un cube LED avec des transistors ?

Quand une couche est allumée, le courant de toutes ses LED retourne au GND par une seule ligne ; sur un cube 3x3x3, cela dépasse 100 mA. Comme la limite recommandée d'une broche d'Arduino est de 20 mA, la ligne de couche est tirée au GND par un transistor NPN comme le 2N2222A ou le BC337. Une résistance de base de 470 Ω suffit.

Pourquoi mon cube LED scintille-t-il ?

Le scintillement apparaît quand la vitesse de balayage est trop faible. La fréquence de rafraîchissement vaut 1 / (nombre de couches × durée par couche) et doit dépasser 100 Hz : garde donc une durée de 2–3 ms par couche et ne mets ni long delay() ni Serial.print() dans la boucle de balayage. Si le cube ne scintille que lorsqu'on le touche, le coupable est très probablement une soudure froide.

Pourquoi des LED s'allument-elles alors qu'elles devraient être éteintes ?

C'est l'effet fantôme (ghosting), qui a deux causes principales. Modifier les colonnes pendant qu'une couche est allumée transporte un instant le motif précédent sur la nouvelle couche ; éteins d'abord la couche, puis écris les colonnes. Si le code est correct, une LED inversée dans le cube ouvre peut-être un chemin de courant vers d'autres couches.

Peut-on faire un cube LED 8x8x8 avec un Arduino Uno ?

Oui, mais les broches ne suffisent pas à elles seules : il faut une chaîne de 74HC595 ou des pilotes similaires pour les 64 colonnes, des MOSFET à niveau logique pour les 8 couches et du SPI matériel pour un balayage rapide. Souder 512 LED prend aussi plusieurs jours. Le mieux est de maîtriser d'abord la technique sur un cube 3x3x3 ou 4x4x4.

Voir tous les projets
Chenillard à LED
#5Intermédiaire

Chenillard à LED

Des lumières qui s'allument l'une après l'autre, comme si elles couraient. L'Arduino allume six LED une par une ; chacune brille un court instant puis s'éteint, et la lumière parcourt la rangée du déb

4.6(85)
207
Chenillard K2000 à LED
#6Intermédiaire

Chenillard K2000 à LED

Le fameux balayage lumineux : un point de lumière glisse d'un bout à l'autre de six LED, puis revient. L'Arduino allume chaque LED un dixième de seconde avant de passer à la suivante, fait demi-tour à

4.8(106)
202
Chenillard K2000 à vitesse réglable
#8Intermédiaire

Chenillard K2000 à vitesse réglable

Une lumière court d'un bout à l'autre de six LED, fait demi-tour et repart. En tournant le bouton du potentiomètre, tu changes aussitôt la vitesse de sa course : bouton d'un côté, la lumière file pres

4.5(60)
120
Utilisation du ruban LED WS2812B
#69Intermédiaire
Premium

Utilisation du ruban LED WS2812B

Tu découvres un ruban LED intelligent dont chaque lumière peut prendre sa propre couleur. L'Arduino allume d'abord les cinq premières LED en rouge, une seconde plus tard les cinq autres en bleu, puis

4.8(54)
70
WS2812B Animation 1
#75Intermédiaire
Premium

WS2812B Animation 1

Sur un ruban de 56 LED, toutes les couleurs de l'arc-en-ciel s'alignent côte à côte et défilent sans jamais s'arrêter, comme une rivière de lumière qui glisserait le long du ruban. Chaque LED brille d

4.9(69)
89
WS2812B Animation 2
#76Intermédiaire
Premium

WS2812B Animation 2

Installe dans ta chambre un spectacle lumineux qui change de couleurs tout seul. L'Arduino fait défiler les couleurs sans arrêt sur un ruban de 30 LED et passe toutes les quelques secondes à une nouve

4.8(65)
84
Serpent à pixels Matrice 8x8
#88Avancé
Premium

Serpent à pixels Matrice 8x8

Construis de tes mains le jeu classique du serpent et joue. Sur une matrice lumineuse colorée de 8x8, tu guides un serpent vert avec un joystick et tu manges des pommes rouges ; à chaque pomme, le ser

4.7(39)
57
Matrice LED 4x 32x8 - Pack de 6 animations
#91Intermédiaire
Premium

Matrice LED 4x 32x8 - Pack de 6 animations

Quatre panneaux LED 32x8 empilés forment un écran carré sur lequel six animations se succèdent : une pluie numérique qui tombe, une spirale qui grandit, des cellules qui naissent et meurent toutes seu

4.5(35)
48