Cube LED RVB 8x8x8
Composants et fournitures
| Anode commune diffuse RVB | | × | 512 | |
| | × | 12 | |
| 74HC138 3 à 8 lignes de décodage | | × | 1 | |
| | × | 8 | |
| | × | 1 | |
| Alimentation à découpage Digilent 5V 2.5A | | × | 1 | |
| | × | 8 | |
| | × | 8 | |
| | × | 8 | |
Applications et services en ligne
À propos de ce projet
Vidéo
Construire
Cette construction a été inspirée par le cube Kevin Darrah RGB.
En regardant la carrure de Kevin, sa patience ne doit pas avoir de limites - malheureusement la mienne en a.
J'ai décidé de remplacer les 24 registres à décalage, 192 transistors et 640 résistances par 12 drivers LED DM13a (environ 1 $ US chacun sur eBay).
Le cube lui-même a été construit comme Kevin le décrit dans la vidéo suivante :
Une fois le cube fabriqué, j'ai créé une carte de circuit imprimé en utilisant la méthode Toner pour contenir les puces de pilote DM13A et le cube lui-même. Plutôt que de payer le coût d'une carte fabriquée dans le commerce avec un placage traversant, j'ai décidé de câbler chaque connexion LED à la broche DM13A appropriée à l'aide d'un fil enroulé. Les fichiers Eagle inclus contiennent la version câblée à la main ainsi qu'une version routée automatiquement (non testée).
Le microprocesseur et la carte d'anode contiennent également un MSGEQ7 - un égaliseur graphique à sept bandes et un préampli de microphone que je prévois d'expérimenter à l'avenir. À l'heure actuelle, ils ne sont pas utilisés. Si vous souhaitez utiliser une carte UNO ou Nano commerciale, tout ce dont vous avez besoin est le décodeur 74HC138 3 à 8 lignes et les MOSFET 8 canaux P et les résistances associées. Vous pouvez simplement les câbler sur une proto-carte si vous le souhaitez.
L'alimentation 5V 20W a été achetée sur eBay. J'ai fait le boîtier en pin habillé de 40 mm x 9 mm.
J'ai ajouté quelques animations au logiciel Kevin's Cube, mais elles restent pratiquement inchangées.
Conclusion
Vous devriez pouvoir acheter des LED RVB à anode commune 600 x 5 mm sur eBay pour environ 30 $ US. Même après avoir simplifié l'électronique, la construction du cube a pris beaucoup de temps mais au final, gratifiante.
Code
Cube_8x8x8_V1.inoC/C++
/* Le cube LED RVB 8x8x8 de John Bradnam basé sur le travail de Kevin DarrahLatestV12 17/04/2013Release Notes :V11- Correction d'un bug avec la synchronisation BAM- Déplacement de la configuration des broches vierges vers ISR afin que les broches soient mortes jusqu'à ce qu'elles soient écrites dans l'opération V12 bits à définir les broches LOW étaient incorrectes devraient être PORTx &=~(1<// Bibliothèque SPI utilisé pour synchroniser les données vers les registres à décalage#define LATCH_PIN 2 //peut utiliser n'importe quelle broche que vous souhaitez verrouiller les registres à décalage#define BLANK_PIN 4 // idem, peut utiliser n'importe quelle broche que vous voulez pour cela, assurez-vous simplement de tirer via a 1k à 5V#define DATA_PIN 11 // utilisé par SPI, doit être la broche 11#define CLOCK_PIN 13 // utilisé par SPI, doit être 13#define LAYER_A 5 //74138 A Input#define LAYER_B 6 //74138 A Input# define LAYER_C 7 //74138 A Input#define SWITCH_PGM 10 //PB2#define SWITCH_SEQ 9 //PB1#define CUBE_SIZE 8 //Nombre de colonnes, de lignes ou de niveaux dans le cube#define CUBE_MAX (CUBE_SIZE - 1) //Max cube dans dex#define LEDS_PER_LEVEL (CUBE_SIZE * CUBE_SIZE) //Nombre de LEDS par niveau//***variables***variables***variables***variables***variables***variables***variables***variables //Ces variables sont utilisées par le multiplexage et le code de modulation d'angle binaire//C'est ainsi que la luminosité de chaque LED est stockée, //Chaque LED n'a besoin que d'un "bit" pour savoir si elle doit être allumée ou éteinte, donc 64 octets donnent vous 512 bits =512 LED//Comme nous modulons les LED, en utilisant une résolution de 4 bits, chaque couleur a 4 tableaux contenant 64 bits chaque octet red0[LEDS_PER_LEVEL], red1[LEDS_PER_LEVEL], red2[LEDS_PER_LEVEL], red3[LEDS_PER_LEVEL];byte blue0[LEDS_PER_LEVEL], blue1[LEDS_PER_LEVEL], blue2[LEDS_PER_LEVEL], blue3[LEDS_PER_LEVEL];byte green0[LEDS_PER_LEVEL], green1[LEDS_PER_LEVEL], green2[LEDS_PER_LEVEL], green3[LEDS_PER_LEVEL] ; la résolution augmentera plus[LEDS_PER_LEVEL] ; plus de votre précieux RAMint level=0 ; // garde une trace du niveau auquel nous déplaçons les données vers anodeLevel=0 ; // cela s'incrémente à travers les niveaux d'anodeint BAM_Bit , BAM_Counter=0; // Variables de modulation d'angle binaire pour garder une trace des chosesint animation =0; //Garde une trace de l'animation dans la boucle principale//****setup****setup****setup****setup****setup****setup****setup**** setup****setup****setup****setup****setup****setupvoid setup(){ SPI.setBitOrder(MSBFIRST);//Bit le plus significatif en premier SPI.setDataMode(SPI_MODE0) ; // Mode 0 Front montant des données, gardez l'horloge basse SPI.setClockDivider(SPI_CLOCK_DIV2);//Exécutez les données à 16MHz/2 - 8MHz //Serial.begin(115200); // si vous en avez besoin ? noInterrupts();// tue les interruptions jusqu'à ce que tout le monde soit configuré //Nous utilisons la minuterie 1 pour rafraîchir le cube TCCR1A =B00000000 ;//Register A tous les 0 puisque nous ne basculons aucune broche TCCR1B =B00001011 ;//bit 3 défini à placer en mode CTC, appellera une interruption sur une correspondance de compteur // les bits 0 et 1 sont définis pour diviser l'horloge par 64, donc 16MHz/64=250kHz TIMSK1 =B000000010;//bit 1 défini pour appeler l'interruption sur un OCR1A correspond à OCR1A=30 ; // vous pouvez jouer avec ça, mais je l'ai mis à 30, ce qui signifie ://notre horloge tourne à 250kHz, soit 1/250kHz =4us //avec OCR1A réglé sur 30, cela signifie que l'interruption sera appelée tous les ( 30+1)x4us=124us, // ce qui donne une fréquence de multiplexage d'environ 8 kHz // enfin configurer le pinMode de sorties (LATCH_PIN, OUTPUT); // Latch pinMode (DATA_PIN, OUTPUT); // MOSI DATA pinMode (CLOCK_PIN, SORTIE ); // SPI Clock pinMode (LAYER_A, OUTPUT); // 74138 A Input pinMode (LAYER_B, OUTPUT); // 74138 B Input pinMode (LAYER_C, OUTPUT); // 74138 C Input digitalWrite (LAYER_A, LOW); digitalWrite(LAYER_B, LOW); digitalWrite(LAYER_C, LOW); pinMode(SWITCH_PGM, INPUT);//PGM 1 / PGM 2 Switch pinMode(SWITCH_SEQ, INPUT);//SEQ/COLOR Switch //pinMode(BLANK_PIN, OUTPUT);//Output Enable important de le faire en dernier, donc les LED le font ne clignote pas au démarrage SPI.begin();//démarre les interruptions de la bibliothèque SPI ();//laisse le show commencer, cela permet au multiplexage de démarrer}//***start loop***start loop*** start loop***start loop***start loop***start loop***start loop***start loop***start loopvoid loop(){ //Chaque animation située dans une sous-routine // Pour contrôler un LED, vous simplement :// LED(niveau que vous voulez 0-CUBE_MAX, rangée que vous voulez 0-CUBE_MAX, colonne que vous voulez 0-CUBE_MAX, luminosité rouge 0-15, luminosité verte 0-15, luminosité bleue 0-15); if (digitalRead(SWITCH_PGM) ==HIGH) test_leds(); else { nettoyer (); animation =animation + 1 ; switch (animation) { cas 1 :rainVersionTwo(20); Pause; cas 2 :dossier (10); Pause; cas 3 :sinwaveTwo(15); Pause; cas 4:randomColor(10); Pause; cas 5 :wipe_out(10) ; Pause; cas 6 :rebondirVTwo(15); Pause; cas 7 :color_wheelTWO(10) ; Pause; cas 8 :harlem_shake(); Pause; cas 9 :ondulations(10) ; Pause; cas 10 :animation =0; Pause; } }}//****LED Routine****LED Routine****LED Routine****LED Routinevoid LED(int level, int row, int column, byte red, byte green, byte blue){ // C'est là que tout commence // Cette routine est la façon dont les LED sont mises à jour, avec les entrées pour l'emplacement de la LED et ses niveaux de luminosité RG et B // Tout d'abord, vérifiez et assurez-vous que rien n'a dépassé les limites, fixez simplement les choses à soit 0 ou 7 pour l'emplacement, et 0 ou 15 pour le niveau de luminosité =contrainte(niveau, 0, CUBE_MAX); ligne =contrainte (ligne, 0, CUBE_MAX); colonne =contrainte(colonne, 0, CUBE_MAX); rouge =contrainte(rouge, 0, 15); vert =contraindre (vert, 0, 15); bleu =contraindre (bleu, 0, 15); //Il y a des LED (CUBE_SIZE * CUBE_SIZE * CUBE_SIZE) dans le cube, donc lorsque nous écrivons au niveau 2, colonne 5, ligne 4, cela doit être traduit en un nombre de 0 à (CUBE_SIZE * CUBE_SIZE * CUBE_SIZE) - 1 //Les voyants du premier niveau sont les premiers dans la séquence, puis le 2ème niveau, puis le troisième, et ainsi de suite //Pour un cube 4 x 4 x 4 le (niveau * (4 * 4)) est ce qui indexe le point de départ du niveau, donc le niveau 0 correspond aux LED 0 - 15, le niveau 1 correspond aux LED 16 - 31, et ainsi de suite // si vous avez regardé le cube en bas et que vous n'avez regardé que le niveau inférieur // 00 01 02 03 // 04 05 06 07 / / 08 09 10 11 // 12 13 14 15 //Pour un cube 8 x 8 x 8 le (niveau * (8 * 8)) est ce qui indexe le point de départ du niveau, donc le niveau 0 sont les LED 0 - 63, niveau 1 sont des LED 64 - 127, et ainsi de suite // si vous avez regardé le cube en bas et que vous n'avez regardé que le niveau inférieur // 00 01 02 03 04 05 06 07 // 08 09 10 11 12 13 14 15 // 16 17 18 19 20 21 22 23 // 24 25 26 27 28 29 30 31 // 32 33 34 35 36 37 38 39 // 40 41 42 43 44 45 46 47 // 48 49 50 51 52 53 54 55 // 56 57 5 8 59 60 61 62 63 //Ensuite, si vous incrémentiez le niveau, le coin supérieur droit de la grille ci-dessus commencerait à (CUBE_SIZE * CUBE_SIZE) //La raison de cela est que vous n'ayez pas à mémoriser un nombre pour chaque LED, vous permettant d'utiliser le niveau, la ligne, la colonne // Maintenant, qu'en est-il de la division par 8 là-dedans ? //... eh bien, nous avons 8 bits par octet, et nous avons 64 octets en mémoire pour les 512 bits nécessaires pour chaque LED, donc // nous divisons le nombre que nous venons de trouver par 8, et en prenons l'entier, donc nous savons dans quel octet se trouve ce bit //confused? c'est ok, prenons un exemple, si nous voulions écrire sur la LED jusqu'à la dernière LED du cube, nous écririons un 7, 7, 7 // donnant (7*64)+(7*8)=7 =511, ce qui est juste, mais maintenant divisons-le par 8, 511/8 =63,875, et prenons l'entier ainsi, nous obtenons 63, // c'est le dernier octet du tableau, ce qui est juste puisque c'est le last LED // Obtenir le numéro de LED 0 - 511 int wholebyte =(level * LEDS_PER_LEVEL) + (row * CUBE_SIZE) + column; // Récupère l'index dans le tableau. Chaque emplacement indexé contient un octet ou 8 bits ; int quel octet =int (octet entier / 8); int quel bit =(octet entier &7); // Tout cela aura un sens en une seconde // Il s'agit d'une résolution de couleur de 4 bits, donc chaque couleur contient des tableaux x4 de 64 octets, explication ci-dessous :bitWrite(red0[whichbyte], whichbit, bitRead(red, 0)); bitWrite(red1[quel octet], quel bit, bitRead(rouge, 1)); bitWrite(red2[quel octet], quel bit, bitRead(rouge, 2)); bitWrite(red3[quel octet], quel bit, bitRead(rouge, 3)); bitWrite(green0[quel octet], quel bit, bitRead(vert, 0)); bitWrite(green1[quel octet], quel bit, bitRead(vert, 1)); bitWrite(green2[quel octet], quel bit, bitRead(vert, 2)); bitWrite(green3[quel octet], quel bit, bitRead(vert, 3)); bitWrite(blue0[quel octet], quel bit, bitRead(bleu, 0)); bitWrite(blue1[quel octet], quel bit, bitRead(bleu, 1)); bitWrite(blue2[quel octet], quel bit, bitRead(bleu, 2)); bitWrite(blue3[quel octet], quel bit, bitRead(bleu, 3)); // Êtes-vous maintenant plus confus? Vous ne devriez pas l'être ! Cela commence à avoir du sens maintenant. Remarquez comment chaque ligne est un bitWrite, c'est-à-dire //bitWrite(l'octet dans lequel vous voulez écrire, le bit de l'octet à écrire et le 0 ou 1 que vous voulez écrire) //Cela signifie que le "quel octet" est l'octet de 0 à 63 dans lequel le bit correspondant à la LED de 0 à 511 // a du sens maintenant, pourquoi avons-nous fait cela ? prendre une valeur de 0 à 511 et la convertir en une valeur de 0 à 63, puisque chaque LED représente un bit dans // un tableau de 64 octets. //Puis la ligne suivante est quel bit 'wholebyte-(8*whichbyte)' //Ceci prend simplement la valeur de la LED de 0-511 et la soustrait de l'octet, son bit était situé au temps 8 //Pensez-y, octet 63 contiendra des LED de 504 à 511, donc si vous avez pris 505-(8*63), vous obtenez un 1, ce qui signifie que // le numéro de LED 505 est situé dans le bit 1 de l'octet 63 dans le tableau // est-ce que ce? Non, vous devez toujours faire le bitRead de la luminosité 0-15 que vous essayez d'écrire, // si vous écrivez un 15 à RED, les 4 tableaux pour cette LED auront un 1 pour ce bit, ce qui signifie qu'il sera allumé 100% //C'est pourquoi les quatre tableaux lisent 0-4 de la valeur entrée pour ROUGE, VERT et BLEU //espérons que tout cela a un sens ?}//***MultiPlex BAM***MultiPlex BAM** *MultiPlex BAM***MultiPlex BAM***MultiPlex BAM***MultiPlex BAM***MultiPlex BAMISR(TIMER1_COMPA_vect){ //Cette routine est appelée en arrière-plan automatiquement à la fréquence définie par OCR1A //Dans ce code, je définis OCR1A à 30, donc cela s'appelle tous les 124us, donnant à chaque niveau du cube 124us de temps ON // Il y a 8 niveaux, nous avons donc une luminosité maximale de 1/8, car le niveau doit s'éteindre avant que le niveau suivant ne soit allumé //La fréquence du multiplexage est alors de 124us*8=992us, soit 1/992us=environ 1kHz PORTD |=1 <=CUBE_SIZE) { fx =CUBE_MAX; fxm =-1; } Pause; cas 1 :fy =fy + fym; if (fy <0) { fy =0; amy =1 ; } if (fy>=CUBE_SIZE) { fy =CUBE_MAX; fm =-1; } Pause; cas 2 :fz =fz + fzm; si (fz <0) { fz =0; fzm =1 ; } si (fz>=CUBE_SIZE) { fz =CUBE_MAX; fzm =-1; } Pause; } switch (random(3)) { cas 0 :ftx =ftx + ftxm; si (ftx <0) { ftx =0; ftxm =1 ; } si (ftx>=CUBE_SIZE) { ftx =CUBE_MAX; ftxm =-1; } Pause; cas 1 :fty =fty + ftym; if (fty <0) { fty =0; ftym =1 ; } if (fty>=CUBE_SIZE) { fty =CUBE_MAX; ftym =-1; } Pause; cas 2 :ftz =ftz + ftzm; si (ftz <0) { ftz =0; ftzm =1 ; } si (ftz>=CUBE_SIZE) { ftz =CUBE_MAX; ftzm =-1; } Pause; } } //pendant qu'il est propre();}//wipeout//****rainVersionTwo****rainVersionTwo****rainVersionTwo****rainVersionTwo****rainVersionTwovoid rainVersionTwo(int runtimeInSeconds){ int x[LEDS_PER_LEVEL ], y[LEDS_PER_LEVEL], z[LEDS_PER_LEVEL], ledcolor ; int xx[LEDS_PER_LEVEL], yy[LEDS_PER_LEVEL], zz[LEDS_PER_LEVEL], xold[LEDS_PER_LEVEL], yold[LEDS_PER_LEVEL], zold[LEDS_PER_LEVEL] ; for(int addr =0; addr =200 &&ledcolor <300) { for(int addr =0; addr =300 &&ledcolor <400) { } if(ledcolor>=500 &&ledcolor <600) { } ledcolor++; si (couleur led>=300) couleur led=0; for(int addr =0; addr Schémas
eagle_files_WfqPEUP7Mp.zip