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);
}


