Código
Cube_8x8x8_V1.ino C / C ++
/ * O 8x8x8 RGB LED Cubeby John Bradnambaseado no trabalho de Kevin DarrahLatestV12 04/17 / 2013Notas de lançamento:V11- Corrigido bug com temporização BAM- Movido a configuração do pino em branco para ISR, então os pinos estão mortos até que sejam gravados na operação V12 bitwise para definir pins LOW estava incorreto deve ser PORTx &=~ (1 < // Biblioteca SPI usado para registrar dados para os registradores de deslocamento # define LATCH_PIN 2 // pode usar qualquer pino que você deseja travar os registradores de deslocamento # define BLANK_PIN 4 // mesmo, pode usar qualquer pino que desejar para isso, apenas certifique-se de puxar por a 1k a 5V # define DATA_PIN 11 // usado pelo SPI, deve ser o pino 11 # define CLOCK_PIN 13 // usado pelo SPI, deve ser 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 // Número de colunas, linhas ou níveis no cubo # define CUBE_MAX (CUBE_SIZE - 1) // Cubo máximo em dex # define LEDS_PER_LEVEL (CUBE_SIZE * CUBE_SIZE) // Número de LEDS por nível // *** variáveis *** variáveis *** variáveis *** variáveis *** variáveis *** variáveis *** variáveis *** variáveis // Essas variáveis são usadas por multiplexação e código de modulação de ângulo de bit // É assim que o brilho de cada LED é armazenado, // Cada LED só precisa de um 'bit' para saber se deve estar LIGADO ou DESLIGADO, então 64 bytes você 512 bits =512 LEDs // Como estamos modulando os LEDs, usando resolução de 4 bits, cada cor tem 4 matrizes contendo 64 bits cada byte red0 [LEDS_PER_LEVEL], red1 [LEDS_PER_LEVEL], red2 [LEDS_PER_LEVEL], red3 [LEDS_PER_LEVEL]; byte azul0 [LEDS_PER_LEVEL], azul1 [LEDS_PER_LEVEL], azul2 [LEDS_PER_LEVEL], azul3 [LEDS_PER_LEVEL]; byte verde0 [LEDS_PER_LEVEL], verde1 [LEDS_PER_LEVEL], verde2 [LEDS_PER_LEVEL], verde3 [LEDS_PER_LEVEL], verde3 [LEDS_PER_LEVEL] notará quanto mais resolução; mais de seu precioso nível de RAMint =0; // mantém o controle de qual nível estamos transferindo dados paraint anodeLevel =0; // isso aumenta através dos níveis de ânodoint BAM_Bit , BAM_Contador =0; // Variáveis de modulação de ângulo de bit para controlar as coisasint animation =0; // Mantém o controle da animação no loop principal // **** configuração **** configuração **** configuração **** configuração **** configuração **** configuração **** configuração **** configuração **** configuração **** configuração **** configuração **** configuração **** configuraçãovoid configuração () {SPI.setBitOrder (MSBFIRST); // Bit Mais Significativo Primeiro SPI.setDataMode (SPI_MODE0); // Modo 0 borda ascendente dos dados, mantenha o clock baixo SPI.setClockDivider (SPI_CLOCK_DIV2); // Execute os dados em 16 MHz / 2 - 8 MHz //Serial.begin(115200);// se precisar? noInterrupts (); // elimina as interrupções até que todos estejam configurados // Usamos o Timer 1 para atualizar o cubo TCCR1A =B00000000; // Registre A todos os 0s, já que não estamos alternando nenhum pino TCCR1B =B00001011; // bit 3 definido para colocar no modo CTC, irá chamar uma interrupção em um contador de correspondência // bits 0 e 1 são definidos para dividir o relógio por 64, então 16MHz / 64 =250kHz TIMSK1 =B00000010; // bit 1 definido para chamar a interrupção em um OCR1A corresponde a OCR1A =30; // você pode brincar com isso, mas eu defini para 30, o que significa:// nosso relógio funciona a 250kHz, que é 1 / 250kHz =4us // com OCR1A definido para 30, isso significa que a interrupção será chamada a cada ( 30 + 1) x4us =124us, // o que dá uma frequência multiplex de cerca de 8 kHz // finalmente configurar o pinMode das saídas (LATCH_PIN, OUTPUT); // Latch pinMode (DATA_PIN, OUTPUT); // MOSI DATA pinMode (CLOCK_PIN, OUTPUT); // PinMode do relógio SPI (LAYER_A, OUTPUT); // 74138 PinMode de entrada A (LAYER_B, OUTPUT); // 74138 PinMode de entrada B (LAYER_C, OUTPUT); // 74138 Entrada C digitalWrite (LAYER_A, LOW); digitalWrite (LAYER_B, LOW); digitalWrite (LAYER_C, LOW); pinMode (SWITCH_PGM, INPUT); // Chave PGM 1 / PGM 2 pinMode (SWITCH_SEQ, INPUT); // Chave SEQ / COLOR // pinMode (BLANK_PIN, OUTPUT); // Habilitar saída importante para fazer isso por último, então os LEDs fazem não pisca na inicialização do SPI.begin (); // inicia a biblioteca SPI interrupts (); // deixe o show começar, isso permite o início da multiplexação} // *** start loop *** start loop *** loop inicial *** loop inicial *** loop inicial *** loop inicial *** loop inicial *** loop inicial *** iniciar loopvoid loop () {// Cada animação localizada em uma sub-rotina // Para controlar um LED, você simplesmente:// LED (nível que você deseja 0-CUBE_MAX, linha que deseja 0-CUBE_MAX, coluna que deseja 0-CUBE_MAX, brilho vermelho 0-15, brilho verde 0-15, brilho azul 0-15); if (digitalRead (SWITCH_PGM) ==HIGH) test_leds (); else {clean (); animação =animação + 1; switch (animação) {case 1:rainVersionTwo (20); pausa; caso 2:pasta (10); pausa; caso 3:sinwaveTwo (15); pausa; caso 4:randomColor (10); pausa; caso 5:wipe_out (10); pausa; caso 6:bouncyvTwo (15); pausa; caso 7:color_wheelTWO (10); pausa; caso 8:harlem_shake (); pausa; caso 9:ondulações (10); pausa; caso 10:animação =0; pausa; }}} // **** LED Rotina **** LED Rotina **** LED Rotina **** LED Routinevoid LED (nível interno, linha interna, coluna interna, byte vermelho, byte verde, byte azul) { // É aqui que tudo começa // Esta rotina é como os LEDs são atualizados, com as entradas para a localização do LED e seus níveis de brilho RG e B // Primeiro, verifique e certifique-se de que nada foi além dos limites, apenas fixe as coisas em ou 0 ou 7 para localização e 0 ou 15 para nível de brilho =restrição (nível, 0, CUBE_MAX); linha =restrição (linha, 0, CUBE_MAX); coluna =restrição (coluna, 0, CUBE_MAX); vermelho =restrição (vermelho, 0, 15); verde =restrição (verde, 0, 15); azul =restrição (azul, 0, 15); // Existem (CUBE_SIZE * CUBE_SIZE * CUBE_SIZE) LEDs no cubo, então quando gravamos no nível 2, coluna 5, linha 4, isso precisa ser convertido em um número de 0 a (CUBE_SIZE * CUBE_SIZE * CUBE_SIZE) - 1 // Os LEDs de primeiro nível estão primeiro na sequência, depois no segundo nível, depois no terceiro e assim por diante // Para um cubo 4 x 4 x 4, o (nível * (4 * 4)) é o que indexa o local de início do nível, então o nível 0 são LEDs 0 - 15, o nível 1 são LEDs 16 - 31 e assim por diante // se você olhou para baixo no cubo e olhou apenas para o nível inferior // 00 01 02 03 // 04 05 06 07 / / 08 09 10 11 // 12 13 14 15 // Para um cubo de 8 x 8 x 8 o (nível * (8 * 8)) é o que indica o local de início do nível, então o nível 0 são LEDs 0 - 63, nível 1 são LEDs 64 - 127 e assim por diante // se você olhou para baixo no cubo, e apenas olhou para o nível inferior // 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 // Então, se você incrementou o nível, o canto superior direito da grade acima começaria em (CUBE_SIZE * CUBE_SIZE) // A razão para fazer isso, é para que você não precise memorizar um número para cada LED, permitindo que você use nível, linha, coluna // Agora, que tal dividir por 8 aí? //... bem, temos 8 bits por byte e 64 bytes na memória para todos os 512 bits necessários para cada LED, então // dividimos o número que acabamos de encontrar por 8 e pegamos o inteiro dele, então sabemos qual byte esse bit está localizado // confuso? está tudo bem, vamos dar um exemplo, se quiséssemos escrever do LED para o último LED no cubo, escreveríamos 7, 7, 7 // dando (7 * 64) + (7 * 8) =7 =511, que está certo, mas agora vamos dividi-lo por 8, 511/8 =63,875, e pegar o int dele, obtemos 63, // este é o último byte na matriz, o que está certo, pois este é o último LED // Obtém o LED número 0 - 511 int wholebyte =(nível * LEDS_PER_LEVEL) + (linha * CUBE_SIZE) + coluna; // Pega o índice no array. Cada localização indexada contém um byte ou 8 bits; int whichbyte =int (wholebyte / 8); int whichbit =(wholebyte &7); // Tudo isso fará sentido em um segundo // Esta é a resolução de cor de 4 bits, então cada cor contém matrizes de x4 64 bytes, explicação abaixo: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)); // Você está mais confuso agora? Você não deveria estar! Está começando a fazer sentido agora. Observe como cada linha é um bitWrite, que é, // bitWrite (o byte que você deseja escrever, o bit do byte a escrever e o 0 ou 1 que deseja escrever) // Isso significa que o 'whichbyte' é o byte de 0-63 em que o bit corresponde ao LED de 0-511 // Faz sentido agora por que fizemos isso? pegando um valor de 0-511 e convertendo-o em um valor de 0-63, já que cada LED representa um bit em // um array de 64 bytes. // Então a próxima linha é qual bit 'wholebyte- (8 * whichbyte)' // Isso está simplesmente pegando o valor do LED de 0-511 e subtraindo-o do BYTE seu bit foi localizado em tempos 8 // Pense nisso, byte 63 conterá LEDs de 504 a 511, então se você pegou 505- (8 * 63), você obtém um 1, o que significa que // o LED número 505 está localizado no bit 1 do byte 63 na matriz // é aquele isto? Não, você ainda tem que fazer o bitRead do brilho 0-15 que você está tentando escrever, // se você escreveu um 15 para VERMELHO, todas as 4 matrizes para aquele LED teriam um 1 para aquele bit, o que significa que ele estará ligado 100% // É por isso que as quatro matrizes leem 0-4 do valor inserido para VERMELHO, VERDE e AZUL // espero que tudo isso faça algum sentido?} // *** MultiPlex BAM *** MultiPlex BAM ** * MultiPlex BAM *** MultiPlex BAM *** MultiPlex BAM *** MultiPlex BAM *** MultiPlex BAMISR (TIMER1_COMPA_vect) {// Esta rotina é chamada em segundo plano automaticamente na frequência definida por OCR1A // Neste código, eu configurei OCR1A a 30, então isso é chamado a cada 124us, dando a cada nível no cubo 124us do tempo ON // Existem 8 níveis, então temos um brilho máximo de 1/8, já que o nível deve desligar antes que o próximo nível seja ligado // A frequência da multiplexação é então 124us * 8 =992us, ou 1 / 992us =cerca de 1kHz PORTD | =1 < =CUBE_SIZE) {fx =CUBE_MAX; fxm =-1; } pausa; caso 1:fy =fy + fym; if (fy <0) {fy =0; fym =1; } if (fy> =CUBE_SIZE) {fy =CUBE_MAX; fym =-1; } pausa; caso 2:fz =fz + fzm; if (fz <0) {fz =0; fzm =1; } if (fz> =CUBE_SIZE) {fz =CUBE_MAX; fzm =-1; } pausa; } switch (random (3)) {case 0:ftx =ftx + ftxm; if (ftx <0) {ftx =0; ftxm =1; } if (ftx> =CUBE_SIZE) {ftx =CUBE_MAX; ftxm =-1; } pausa; caso 1:fty =fty + ftym; if (fty <0) {fty =0; ftym =1; } if (fty> =CUBE_SIZE) {fty =CUBE_MAX; ftym =-1; } pausa; caso 2:ftz =ftz + ftzm; if (ftz <0) {ftz =0; ftzm =1; } if (ftz> =CUBE_SIZE) {ftz =CUBE_MAX; ftzm =-1; } pausa; }} // while clean ();} // 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]; para (int addr =0; addr =200 &&ledcolor <300) {for (int addr =0; addr =300 &&ledcolor <400) {} if (ledcolor> =500 &&ledcolor <600) {} ledcolor ++; if (ledcolor> =300) ledcolor =0; para (int addr =0; addr