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

Muy buen articulo, muchas gracias por tus aportaciones.
ResponderSuprimirMagnifico articulo, muchisimas gracias
ResponderSuprimirexcelente proyecto¡¡ y pues como menciona al inicio del proyecto que muchos tenemos dudas a la hora de encarar este proyecto y aun despues de leer y leer, y yo soy uno de ellos puesto que he leido y solo he podido comprender este tema con una matriz de 8x8 pero usando los puertos B y C del pic16F877A para filas y columnas.Ahora quiero realizar lo mismo pero con un shift register para controlar solo las 8 columnas y no he podido hacerlo.Realizo la programacion en proton ide.
ResponderSuprimirentonces si es posible que pusiera el codigo en este lenguaje o como hago funcionar el 74HC595 con el pic, me sera de muchisima ayuda . saludos¡¡¡
Según entiendo necesitas hacer que el 74HC595 controle las columnas y, por otro lado, enviar el contenido de la fila por un puerto, ¿no?. Nunca he usado el Proton IDE, pero no creo que se diferencie mucho del BASIC, si me pasas el código a mi e-mail, puedo ver que se puede hacer.
ResponderSuprimirEn teoría solo debes hacer la secuencia correcta para pasar los datos deseados al shift register, no tiene mas problema.
Saludos.
¡Qué buen artículo mi hermano! Está muy bien documentado y lo mejor es que si posteas código fuente que FUNCIONA.
ResponderSuprimirMuchas gracias por el aporte...