Precisamente de una duda que se me planteó hace poco por correo electrónico surgió un pequeño proyecto a modo de ejemplo de un array de 8x8 LED; El cual funciona de maravillas tanto simulado como físicamente y es por eso que lo publico en esta ocación.
Dicho proyecto está basado en una serie de artículos anteriores dedicados a los shift register, en otras palabras es una implementación de los registros para usarlos con una matriz de LED.
Aquí presento el diagrama de conexión:
El PIC utilizado en esta ocación es el PIC16F88 por ser muy fácil de implementar y contar con oscilador interno.
La línea Load se conecta al pin B0 del PIC, Clk al B1, dClm a B2 y dLin a B3.
La lista de componentes es mas cuantiosa que variada pues esta compuesta por:
R1-R8 | 8 x Resistencias de 220Ω |
R9-R16 | 8 x Resistencias de 3,9KΩ |
Q1-Q8 | 8 x Transistores BC547 o similar |
2 x 74HC595 | |
64 x LED rojo de 5mm brillo standard |
El código, escrito en CCS C, para probar el hardware es el que sigue a continuación, solo he dejado las letras pertinentes a PICROBOT, ya que sino se hace muy largo y repetitivo para mostrarlo como ejemplo, pero desde este link te puedes descargar el código completo con las letras en mayúsculas A-Z, el .HEX, el .COF para simularlo en el ISIS de Proteus y el .DSN con el diseño.
Hay dos versiones del código en este paquete, matriz8x8Q y matriz8x8. La primera es para cuando se usen los transistores a los cátodos de los LED y la segunda si los cátodos van directamente a las salidas del registro de desplazamiento encargado de controlar las columnas.
La única diferencia entre las dos versiones es que la primer versión (Q) no invierte y la segunda si lo hace, las salidas del registro encargado de controlar las filas.
Se podría haber solucionado el problema declarando o no una macro instrucción dirán algunos, después de todo lo único que varía es un caracter de una versión a otra, pero para no confundir, y como este es un ejemplo sencillo, decidí hacerlo así. En un futuro ejemplo de la implementación tal vez incluya una macro instrucción.
/************************************************************************* ** ** ** Ejemplo básico para controlar una matriz de 8x8 LEDs con PIC. ** ** ** ** (c) 2010 Gerardo Ariel Ramírez ** ** picblog@hotmail.com ** ** http://picrobot.blogspot.com/ ** ** ** ************************************************************************** ** ** ** Microcontrolador: PIC16F88 Oscilador: Interno - 8 MHz ** ** Lenguaje: CCS C ** ** ** *************************************************************************/ #include <16f88.h> // Tipo de microcontrolador #fuses INTRC_IO,MCLR // Oscilador interno, MCLR activo #fuses NOPUT,NOBROWNOUT // Sin Brownout reset ni Power up timer #use fast_io(all) // La configuración de los puertos solo se hace al principio. #use delay(clock=8M) // Velocidad del oscilador interno 8 MHz #define Load PIN_B0 // Load (STCP ambos integrados) B0 #define Clk PIN_B1 // Clock (SHCP ambos integrados) B1 #define dClm PIN_B2 // Data para las columnas (DS integrado 1) BC2 #define dLin PIN_B3 // Data para las lineas (DS integrado 2) B3 char Memoria[96]; // 96 Bytes para la memoria (0 - 95) char Visor[8]; // 8 para el visor (8 columnas) int1 flag; // Flags de control int1 flag2; int indx; // Indice donde almacenará las nuevas columnas. int line; // Linea que a mostrar. int time; // Variables para el control de int ptime; // la velocidad de desplazamiento. int t; // Variable auxiliar. void CargaMem(char Ascii); void GuardaClm(char c); #int_rtcc void isr(){ int Mul=128; // Cada vez que ocurre la interrupcion if(++line>7)Line=0; // selecciona la siguiente linea, si se pasa de 7 vuelve a 0. if(++ptime>5){ // Suma 1 a ptime. Si se pasa de 20 ptime=0; // lo pone en 0 y suma 1 a time. if(++time>200){ // Si se pasa de 200 time=0; // lo pone en 0 Flag=true; // y activa el flag. } } for(t=0;t<8;t++){ // Bucle 0 - 7 (Lineas) output_bit(dLin,!!(Visor[Line]&Mul)); // dLin es seteado con el valor // del bit de la fila actual. if (Line==t)output_high(dClm); // Si Line es igual a t // activa el bit correspondiente else output_low(dClm); // a la columna, sino lo desactiva. output_low(Clk); // output_high(Clk); // Rota el contenido interno del 74HC595. Mul>>=1; // Divide la mascara que compara con Visor[] (128,64,32...) } output_low(Load); output_high(Load);// El contenido interno del integrado pasa a las salidas. } void main(){ int k; set_tris_a(0x00); set_tris_b(0x00); for (k=0;k<8;k++){ Visor[k]=0; } for (k=0;k<96;k++){ Memoria[k]=0; } // Limpia la memoria y el visor flag=true; // Activo el flag para que cargue la memoria setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1); // Configuración del Timer0 enable_interrupts(int_rtcc); // Interrupcion por Timer0 enable_interrupts(global); // Interrupciones globales do{ if (Flag){ // Si el flag está activado flag2=true; // Activa el flag2 for (k=0;k<8;k++){ // Pasa el contenido de las primeras 8 visor[k]=Memoria[k]; // columnas en memoria al visor } for (k=0;k<95;k++){ // Rota el contenido de toda la memoria Memoria[k]=Memoria[k+1];// a la izquierda 1=1+1, 2=2+1, n=n+1... if (Memoria[k]!=0){Flag2=false;} // Si hay alguna columna que no // esté vacía desactiva el flag2 } Memoria[95]=0; // Limpia la ultima columna de la memoria if (Flag2){ // Si flag2 está activo indx=7; // a partir de la columna 7 CargaMem("PICROBOT"); // escribe PICROBOT } Flag=false; // Desactiva el flag } }while (true); // Bucle infinito } void GuardaClm(char c){ if (indx<94){ Memoria[indx]=c; // Guarda la columna en la ubicación actual de memoria indx++; // y aumenta el indice } } void CargaMem(char ascii){ // Carga la memoria con el caracter deseado switch (ascii){ case('B'): GuardaClm(0b01111111); GuardaClm(0b01111111); GuardaClm(0b01001001); GuardaClm(0b01001001); GuardaClm(0b01111111); GuardaClm(0b00110110); break; case('C'): GuardaClm(0b00111110); GuardaClm(0b01111111); GuardaClm(0b01000001); GuardaClm(0b01000001); GuardaClm(0b01100011); GuardaClm(0b00100010); break; case('I'): GuardaClm(0b01000001); GuardaClm(0b01000001); GuardaClm(0b01111111); GuardaClm(0b01111111); GuardaClm(0b01000001); GuardaClm(0b01000001); break; case('O'): GuardaClm(0b00111110); GuardaClm(0b01111111); GuardaClm(0b01000001); GuardaClm(0b01000001); GuardaClm(0b01111111); GuardaClm(0b00111110); break; case('P'): GuardaClm(0b01111111); GuardaClm(0b01111111); GuardaClm(0b00001001); GuardaClm(0b00001001); GuardaClm(0b00001111); GuardaClm(0b00000110); break; case('R'): GuardaClm(0b01111111); GuardaClm(0b01111111); GuardaClm(0b00001001); GuardaClm(0b00011001); GuardaClm(0b01111111); GuardaClm(0b01100110); break; case('T'): GuardaClm(0b00000011); GuardaClm(0b00000001); GuardaClm(0b01111111); GuardaClm(0b01111111); GuardaClm(0b00000001); GuardaClm(0b00000011); break; } GuardaClm(0b00000000); }