Cubo de LED RGB de 8x8x8
Componentes y suministros
| × | 512 | ||||
| × | 12 | ||||
| × | 1 | ||||
| × | 8 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 8 | ||||
| × | 8 | ||||
| × | 8 |
Aplicaciones y servicios en línea
|
Acerca de este proyecto
Video
Construir
Esta construcción se inspiró en el cubo RGB de Kevin Darrah.
Mirando la complexión de Kevin, su paciencia no debe tener límites, desafortunadamente la mía lo tiene.
Decidí reemplazar los 24 registros de desplazamiento, 192 transistores y 640 resistencias con 12 controladores LED DM13a (alrededor de $ 1 USD cada uno en eBay).
El cubo en sí fue construido como Kevin describe en el siguiente video:
Una vez que se hizo el cubo, creé una placa de circuito impreso utilizando el método Toner para contener los chips del controlador DM13A y el cubo en sí. En lugar de pagar el costo de una placa fabricada comercialmente con revestimiento de orificio pasante, decidí cablear a mano cada conexión de LED al pin DM13A apropiado utilizando un cable envolvente. Los archivos Eagle incluidos contienen la versión cableada a mano y una versión enrutada automáticamente (no probada).
El microprocesador y la placa del ánodo también tienen un MSGEQ7 - Ecualizador gráfico de siete bandas y preamplificador de micrófono con el que planeo experimentar en el futuro. Ahora mismo, no se utilizan. Si desea utilizar una placa UNO o Nano comercial, todo lo que necesita es el decodificador 74HC138 de 3 a 8 líneas y los MOSFET de 8 canales P y las resistencias asociadas. Puede simplemente conectarlos en algún protoboard si lo desea.
La fuente de alimentación de 5V 20W se compró en eBay. Hice la caja de pino revestido de 40 mm x 9 mm.
Agregué un par de animaciones al software del cubo de Kevin, pero básicamente permanece sin cambios.
Conclusión
Debería poder comprar LED RGB difusos de ánodo común de 600 x 5 mm en eBay por alrededor de $ 30 dólares estadounidenses. Incluso después de simplificar la electrónica, la construcción del cubo llevó mucho tiempo, pero al final fue gratificante.
Código
- Cube_8x8x8_V1.ino
Cube_8x8x8_V1.ino C / C ++
/ * The 8x8x8 RGB LED Cube de John Bradnambasado en el trabajo de Kevin DarrahLatestV12 04/17 / 2013Notas de lanzamiento:V11- Se corrigió un error con la sincronización de BAM- Se movió la configuración del pin en blanco a ISR para que los pines estén muertos hasta que se escriban en la operación V12bitwise para configurar pines LOW era incorrecto debería ser PORTx &=~ (1 <// Biblioteca SPI utilizado para registrar datos en los registros de desplazamiento # definir LATCH_PIN 2 // puede usar cualquier pin que desee para bloquear los registros de desplazamiento # definir BLANK_PIN 4 // igual, puede usar cualquier pin que desee para esto, solo asegúrese de tirar hacia arriba a través de a 1k a 5V # define DATA_PIN 11 // usado por SPI, debe ser pin 11 # define CLOCK_PIN 13 // usado por SPI, debe ser 13 # define LAYER_A 5 // 74138 A Entrada # define LAYER_B 6 // 74138 A Entrada # define LAYER_C 7 // 74138 A Entrada # define SWITCH_PGM 10 // PB2 # define SWITCH_SEQ 9 // PB1 # define CUBE_SIZE 8 // Número de columnas, filas o niveles en el cubo # define CUBE_MAX (CUBE_SIZE - 1) // Max cubo en dex # define LEDS_PER_LEVEL (CUBE_SIZE * CUBE_SIZE) // Número de LEDS por nivel // *** variables *** variables *** variables *** variables *** variables *** variables *** variables *** variables // Estas variables se utilizan mediante multiplexación y código de modulación de ángulo de bits // Así es como se almacena el brillo de cada LED, // Cada LED solo necesita un 'bit' para saber si debe estar ENCENDIDO o APAGADO, por lo que 64 Bytes da usted 512 bits =512 LED // Como estamos modulando los LED, usando una resolución de 4 bits, cada color tiene 4 matrices que contienen 64 bits cada byte rojo0 [LEDS_PER_LEVEL], rojo1 [LEDS_PER_LEVEL], rojo2 [LEDS_PER_LEVEL], rojo3 [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] más de su preciosa RAMint level =0; // realiza un seguimiento de qué nivel estamos cambiando los datos aint anodeLevel =0; // esto se incrementa a través de los niveles de ánodoint BAM_Bit , Contador_BAM =0; // Variables de modulación de ángulo de bits para realizar un seguimiento de thingsint animation =0; // Realiza un seguimiento de la animación en el bucle principal // **** configuración **** configuración **** configuración **** configuración **** configuración **** configuración **** configuración **** configuración **** configuración **** configuración **** configuración **** configuración **** setupvoid setup () {SPI.setBitOrder (MSBFIRST); // Bit más significativo primero SPI.setDataMode (SPI_MODE0); // Modo 0 Borde ascendente de datos, mantenga el reloj bajo SPI.setClockDivider (SPI_CLOCK_DIV2); // Ejecute los datos a 16MHz / 2 - 8MHz //Serial.begin(115200);// si lo necesita? noInterrupts (); // mata las interrupciones hasta que todos estén configurados // Usamos el temporizador 1 para actualizar el cubo TCCR1A =B00000000; // Registrar A todos ceros ya que no estamos alternando ningún pin TCCR1B =B00001011; // bit 3 configurado para colocar en modo CTC, llamará a una interrupción en una coincidencia de contador // los bits 0 y 1 están configurados para dividir el reloj entre 64, por lo que 16MHz / 64 =250kHz TIMSK1 =B00000010; // bit 1 configurado para llamar a la interrupción en un OCR1A coincide con OCR1A =30; // puedes jugar con esto, pero lo configuré en 30, lo que significa:// nuestro reloj corre a 250 kHz, que es 1/250 kHz =4us // con OCR1A configurado en 30, esto significa que la interrupción se llamará cada ( 30 + 1) x4us =124us, // que da una frecuencia multiplex de aproximadamente 8kHz // finalmente configure las salidas pinMode (LATCH_PIN, OUTPUT); // Latch pinMode (DATA_PIN, OUTPUT); // MOSI DATA pinMode (CLOCK_PIN, OUTPUT); // SPI Clock pinMode (LAYER_A, OUTPUT); // 74138 A Input pinMode (LAYER_B, OUTPUT); // 74138 B Input pinMode (LAYER_C, OUTPUT); // 74138 C Entrada digitalWrite (LAYER_A, LOW); escritura digital (CAPA_B, BAJA); escritura digital (CAPA_C, BAJA); pinMode (SWITCH_PGM, INPUT); // PGM 1 / PGM 2 Switch pinMode (SWITCH_SEQ, INPUT); // SEQ / COLOR Switch // pinMode (BLANK_PIN, OUTPUT); // Output Enable importante para hacer esto último, por lo que los LED lo hacen no parpadea al arrancar SPI.begin (); // inicia la biblioteca SPI interrupts (); // deja que comience el espectáculo, esto permite que comience la multiplexación} // *** iniciar el ciclo *** iniciar el ciclo *** inicio de ciclo *** inicio de ciclo *** inicio de ciclo *** inicio de ciclo *** inicio de ciclo *** inicio de ciclo *** inicio de ciclovoid loop () {// Cada animación ubicada en una subrutina // Para controlar una LED, simplemente:// LED (nivel que desea 0-CUBE_MAX, fila que desea 0-CUBE_MAX, columna que desea 0-CUBE_MAX, brillo rojo 0-15, brillo verde 0-15, brillo azul 0-15); if (digitalRead (SWITCH_PGM) ==HIGH) test_leds (); else {limpio (); animación =animación + 1; cambiar (animación) {caso 1:rainVersionTwo (20); descanso; caso 2:carpeta (10); descanso; caso 3:sinwaveTwo (15); descanso; caso 4:randomColor (10); descanso; caso 5:wipe_out (10); descanso; caso 6:bouncyvTwo (15); descanso; caso 7:color_wheelTWO (10); descanso; caso 8:harlem_shake (); descanso; caso 9:ondulaciones (10); descanso; caso 10:animación =0; descanso; }}} // **** LED Routine **** LED Routine **** LED Routine **** LED Routinevoid LED (nivel int, fila int, columna int, byte rojo, byte verde, byte azul) { // Aquí es donde todo comienza // Esta rutina es cómo se actualizan los LED, con las entradas para la ubicación del LED y sus niveles de brillo RG y B // Primero, verifique y asegúrese de que nada haya ido más allá de los límites, simplemente fije las cosas en 0 o 7 para la ubicación y 0 o 15 para el nivel de brillo =restricción (nivel, 0, CUBE_MAX); fila =restringir (fila, 0, CUBE_MAX); columna =restringir (columna, 0, CUBE_MAX); rojo =restringir (rojo, 0, 15); verde =restringir (verde, 0, 15); azul =restringir (azul, 0, 15); // Hay (CUBE_SIZE * CUBE_SIZE * CUBE_SIZE) LED en el cubo, por lo que cuando escribimos en el nivel 2, columna 5, fila 4, eso debe traducirse a un número de 0 a (CUBE_SIZE * CUBE_SIZE * CUBE_SIZE) - 1 // Los LED del primer nivel están primero en la secuencia, luego el segundo nivel, luego el tercero, y así sucesivamente // Para un cubo de 4 x 4 x 4, el (nivel * (4 * 4)) es lo que indexa el lugar de inicio del nivel, entonces el nivel 0 son los LED 0-15, el nivel 1 son los LED 16-31, y así sucesivamente // si miraste hacia abajo en el cubo, y solo miraste el nivel inferior // 00 01 02 03 // 04 05 06 07 / / 08 09 10 11 // 12 13 14 15 // Para un cubo de 8 x 8 x 8, el (nivel * (8 * 8)) es lo que indexa el lugar de inicio del nivel, por lo que el nivel 0 son los LED 0 - 63, nivel 1 son LED 64-127, y así sucesivamente // si miraste hacia abajo en el cubo, y solo miraste al nivel 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 // Luego, si aumentaras el nivel, la parte superior derecha de la cuadrícula de arriba comenzaría en (CUBE_SIZE * CUBE_SIZE) // La razón para hacer esto es para que no tengas que memorizar un número para cada LED, lo que le permite usar nivel, fila, columna // Ahora, ¿qué pasa con la división por 8 allí? //... bueno, tenemos 8 bits por byte, y tenemos 64 bytes en memoria para los 512 bits necesarios para cada LED, así que // dividimos el número que acabamos de encontrar por 8, y tomamos el número entero, entonces sabemos qué byte, ese bit se encuentra // confundido? está bien, tomemos un ejemplo, si quisiéramos escribir en el LED en el último LED del cubo, escribiríamos un 7, 7, 7 // dando (7 * 64) + (7 * 8) =7 =511, que es correcto, pero ahora dividámoslo por 8, 511/8 =63.875, y tomamos el int de él, obtenemos 63, // este es el último byte en la matriz, lo cual es correcto ya que este es el último LED // Obtener el número de LED 0 - 511 int enterobyte =(nivel * LEDS_PER_LEVEL) + (fila * CUBE_SIZE) + columna; // Introduce el índice en la matriz. Cada ubicación indexada contiene un byte u 8 bits; int whichbyte =int (enterobyte / 8); int whichbit =(bytes completos y 7); // Todo esto tendrá sentido en un segundo // Esta es una resolución de color de 4 bits, por lo que cada color contiene matrices x4 de 64 bytes, explicación a continuación:bitWrite (red0 [whichbyte], whichbit, bitRead (red, 0)); bitWrite (red1 [whichbyte], whichbit, bitRead (rojo, 1)); bitWrite (red2 [whichbyte], whichbit, bitRead (rojo, 2)); bitWrite (red3 [whichbyte], whichbit, bitRead (rojo, 3)); bitWrite (green0 [whichbyte], whichbit, bitRead (verde, 0)); bitWrite (green1 [whichbyte], whichbit, bitRead (verde, 1)); bitWrite (green2 [whichbyte], whichbit, bitRead (verde, 2)); bitWrite (green3 [whichbyte], whichbit, bitRead (verde, 3)); bitWrite (blue0 [whichbyte], whichbit, bitRead (azul, 0)); bitWrite (blue1 [whichbyte], whichbit, bitRead (azul, 1)); bitWrite (blue2 [whichbyte], whichbit, bitRead (azul, 2)); bitWrite (blue3 [whichbyte], whichbit, bitRead (azul, 3)); // ¿Estás ahora más confundido? ¡No deberías estarlo! Empieza a tener sentido ahora. Observe cómo cada línea es un bitWrite, que es, // bitWrite (el byte en el que desea escribir, el bit del byte para escribir y el 0 o 1 que desea escribir) // Esto significa que el 'whichbyte' es el byte de 0-63 en el que el bit correspondiente al LED de 0-511 // ¿Tiene sentido ahora por qué hicimos eso? tomando un valor de 0-511 y convirtiéndolo en un valor de 0-63, ya que cada LED representa un bit en // una matriz de 64 bytes. // Luego, la siguiente línea es qué bit 'wholebyte- (8 * whichbyte)' // Esto es simplemente tomar el valor del LED de 0-511 y restarlo del BYTE en el que se ubicó su bit en tiempos 8 // Piense en ello, byte 63 contendrá LED de 504 a 511, por lo que si tomó 505- (8 * 63), obtendrá un 1, lo que significa que, // El LED número 505 está ubicado en el bit 1 del byte 63 en la matriz // es que ¿eso? No, todavía tienes que hacer el bit Lee del brillo 0-15 que estás intentando escribir, // si escribiste un 15 en ROJO, las 4 matrices para ese LED tendrían un 1 para ese bit, lo que significa que estará encendido 100% // Esta es la razón por la que las cuatro matrices leen 0-4 del valor ingresado para ROJO, VERDE y AZUL // ¿Ojalá todo esto tenga algún sentido?} // *** MultiPlex BAM *** MultiPlex BAM ** * MultiPlex BAM *** MultiPlex BAM *** MultiPlex BAM *** MultiPlex BAM *** MultiPlex BAMISR (TIMER1_COMPA_vect) {// Esta rutina se llama en segundo plano automáticamente a la frecuencia establecida por OCR1A // En este código, configuro OCR1A a 30, por lo que esto se llama cada 124us, dando a cada nivel en el cubo 124us de tiempo ON // Hay 8 niveles, por lo que tenemos un brillo máximo de 1/8, ya que el nivel debe apagarse antes de que el siguiente nivel sea encendido // La frecuencia de multiplexación es 124us * 8 =992us, o 1 / 992us =aproximadamente 1kHz PORTD | =1 < =TAMAÑO_CUBO) {fx =MÁXIMO_CUBO; fxm =-1; } descanso; caso 1:fy =fy + fym; si (fy <0) {fy =0; fym =1; } if (fy> =TAMAÑO_CUBO) {fy =CUBO_MAX; fym =-1; } descanso; caso 2:fz =fz + fzm; si (fz <0) {fz =0; fzm =1; } if (fz> =TAMAÑO_CUBO) {fz =MÁXIMO_CUBO; fzm =-1; } descanso; } cambiar (aleatorio (3)) {caso 0:ftx =ftx + ftxm; si (ftx <0) {ftx =0; ftxm =1; } if (ftx> =TAMAÑO_CUBO) {ftx =MÁXIMO_CUBO; ftxm =-1; } descanso; caso 1:fty =fty + ftym; si (fty <0) {fty =0; ftym =1; } if (cincuenta> =TAMAÑO_CUBO) {fty =MÁXIMO_CUBO; ftym =-1; } descanso; caso 2:ftz =ftz + ftzm; si (ftz <0) {ftz =0; ftzm =1; } if (ftz> =TAMAÑO_CUBO) {ftz =CUBO_MAX; ftzm =-1; } descanso; }} // 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]; for (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; for (int addr =0; addr Esquemas
eagle_files_WfqPEUP7Mp.zip
Proceso de manufactura
- Alerta de sed Alarma de planta
- Cubo LED 5x5x5
- Reloj Word en italiano
- Medidor de kWh Sigfox
- Mezclador de colores Arduino RGB
- Monitor de temperatura Bluetooth
- DMX RGB LED para exteriores
- Bloqueo controlado por gestos
- El IC complementario
- Una entrada analógica aislada para Arduino
- Mide tu tiempo de reacción