Mostrando entradas con la etiqueta Matrix. Mostrar todas las entradas
Mostrando entradas con la etiqueta Matrix. Mostrar todas las entradas

Matriz de 8x8 LED controlada con 2 shift register y PIC

Muchas personas experimentan a diario con arrays de 8x8 LED y un porcentaje de esas personas reflejan sus dudas en distintos sitios desperdigados por la red destinados a este mundillo de la electrónica y los microcontroladores.

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-R88 x Resistencias de 220Ω
R9-R168 x Resistencias de 3,9KΩ
Q1-Q88 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);
}

Tal vez le interese: