Matriz de LEDS de 8x8

(1/25) > >>

Ariel:


Introducción
En este proyecto veremos como diseñar y construir un display de diodos leds en forma de matriz de 8 filas por 8 columnas. El circuito incluye una memoria EEPROM externa del tipo 24C256 en la que podremos almacenar bloques de pixeles que luego seran representados por la pantalla.



Descripción del proyecto
El proyecto que desarrollaremos es una buena herramienta para el aprendizaje. El microcontrolador empleado es de los más pequeños, un PIC16F628A con 2 KBytes de memoria FLASH. Sin embargo, se puede utilizar un PIC16F627A (que tiene la mitad de memoria) o bien un PIC16F648A (que tiene el doble).

Este microcontrolador puede parecer pequeño, pero es más que suficiente para poder manejar los componentes y funciones del proyecto.

Una memoria EEPROM 24C256 de 32 KBytes , a la que se accede vía I2C puede utilizarse para almacenar el contenido de 4096 pantallas, que el microcontrolador podria representar una a cotinuación de otra, a modo de video de baja resolución.

Las columnas de la matriz se seleccionan mediante un registro de desplazamiento de 8 bits de longitud, implementado a partir de un 74HC164N.



El circuito
El circuito eléctrico de este proyecto es muy sencillo. El corazón del mismo es el microcontrolador PIC16F628A.

El oscilador del PIC esta basado en un cristal de 4 MHz y dos condensadores de 22 picofaradios.

La pantalla esta construida mediante una matriz basada en 8 filas por 8 columnas de diodos LEDs, con sus ánodos controlados desde los pines del PORTB del microcontrolador, mediante un transistor 2N3906 que se encarga de proporcionar la corriente suficiente para encender los 8 LEDs de la fila.

La fila inferior corresponde al pin B0, la siguiente al B1 y asi, hasta la fila superior, que esta conectada al pin B7. Cuando querramos programar el microcontrolador, deberemos configurar todo el puerto B como salidas.

El puerto A tiene a su cargo el control del 74HC164N, que a su vez se encarga de seleccionar las columnas activas en cada momento. Entre cada salida del 74HC164N y los LEDs hemos colocado un resistor para limitar la corriente que circula por ellos. Si el brillo de los LEDs es muy bajo, puede probarse con valores mas pequeños para estos resistores. El pin DATA del 74HC164N es controlado desde A1 y los pulsos de CLOCK los proporciona el pin A0.

La memoria EEPROM tambien depende del puerto A, con la línea SCL conectada al pin A2 y la línea SDA conectada al pin A3. Ambas lineas estan puestas a +V mediante resistores de 10K.

La alimentacion se ha resuelto mediante un regulador de voltaje tipo LM7805 y sus componentes asociados. Un diodo se encarga de proteger el circuito por si involuntariamente conectamos la alimentación con la polaridad invertida. La bornera es la encargada de vincular la fuente de corriente continua de entre 9V y 12V encargada de alimentar la placa.

Un pulsador, junto a una resistencia de 10K forman un circuito de reset, que tiene la capacidad de volver el circuito a su estado inicial en cualquier momento.


(Descarga la imagen para verla con más detalle)


NOTA IMPORTANTE: En el esquema no figura la conexión del PIN 9 (RESET) del 74HC164N a +V, aunque si está contemplado en el diseño del PCB. Ese pin DEBE estar a +V para que el circuito funcione.

Lista de componentes
La lista de componentes es más bien pequeña:

    * 1 microcontrolador PIC16F628A, con su zócalo.
    * 1 memoria EEPROM 24C256, con su zócalo.
    * 1 circuito integrado 74HC164N, con su zócalo.
    * 1 regulador de voltaje LM7805
    * 4 condensadores cerámicos de 0.1 uF.
    * 2 condensadores cerámicos de 22 pF.
    * 1 xtal de 4 MHz.
    * 1 condensador electrolitico de 220uF/16V.
    * 1 diodo 1N4007.
    * 8 transistores 2N3906.
    * 8 resistores de 100 ohms.
    * 1 resistor de 10K.
    * 8 resistores de 1.5K.
    * 1 bornera de dos tornillos.
    * 64 diodos LED de 5mm, color rojo.

PCB
El circuito impreso necesario es de 80x95 milimetros, de una sola cara. Esto ha obligado a realizar una buena cantidad de puentes en el lado trasero de la placa, pero es mucho mas sencillo construir una PCB de simple cara en casa. Si no sabes como hacerlo, puedes aprender con el tutorial que existe en este mismo foro.



Puedes descargar el PCB en formato PDF, listo para imprimir, desde este link. Solo debes imprimirlo a escala 1:1 con una impresora láser, y seguir los pasos del tutorial.

Montaje
El montaje no requiere de ninguna técnica en especial. Una vez que tengamos el PCB listo y agujereado, procedemos a soldar los componentes. Podemos comenzar por los resistores y los LEDs. Al hacerlo, hay que tener en cuenta que los LEDs deben tener la muesca que indica el cátodo hacia el lado de los circuitos integrados. Si no lo hacemos asi, el proyecto no funcionará.

Más tarde soldaremos los zócalos, el pulsador de reset, los condensadores , el diodo 1N4007 (cuidando su orientación) y el LM7805. Por ultimo, soldaremos el cristal y pasaremos al otro lado del PCB.

Aqui es donde este montaje puede diferir un poco de otros que hayas realizado. Sin embargo, tampoco es tan complicado lo que resta por hacer.

Lo primero es soldar las los dos resistores pull-up que requiere el bus I2C para funcionar. La imagen siguiente muestra donde van soldados:



Una vez hecho esto, debemos realizar una serie de puentes para unir los ánodos de cada fila de LEDs al colector del transistor correspondiente. Deberia quedar como se ve en la foto siguiente:



Programación en CCS
Aprovecharemos este montaje para aprender más sobre el compilador CCS. A continuación, algunos ejemplos de lo que puede hacerse con esta matriz de LEDs.

Ejemplo 1: TEST LED
El primer ejemplo simplemente se encarga de mostrar encendidas las filas desde la 0 a la 7, y luego enciende rectangulos de LEDs cada vez mas grandes, comenzando desde la esquina superior derecha. El primer video de la sección correspondiente muestra el efecto.

Como el dato se ingresa dentro del registro de desplazamiento cuando el pulso de clock pasa de estao bajo a alto, hemos escrito dis funciones que se encargan de enviar un cero o un uno al registro. La siguiente envia el "0":

Código:

//--------------------------------------------------
//---Envia un 0 al registro de desplazamiento:
//--------------------------------------------------
void fRDD_send_data0(void){
  output_low(RDD_DATA);
  delay_us(2);
  output_low(RDD_CLOCK);
  delay_us(2);
  output_high(RDD_CLOCK);
}

y esta otra envia un "1":

Código:

//--------------------------------------------------
//---Envia un 1 al registro de desplazamiento:
//--------------------------------------------------
void fRDD_send_data1(void){
  output_high(RDD_DATA);
  delay_us(2);
  output_low(RDD_CLOCK);
  delay_us(2);
  output_high(RDD_CLOCK);
}


Este es el codigo completo del ejemplo 1:
Código:

//Device/Fuses/Etc.---------------------------------
#INCLUDE <16F628A.H>
#INCLUDE <MATH.H>
#FUSES NOWDT                    //No Watch Dog Timer
#FUSES XT                      
#FUSES NOPUT                    //No Power Up Timer
#FUSES NOPROTECT                //Code not protected from reading
#FUSES NOBROWNOUT               //No brownout reset
#FUSES NOLVP                    //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#FUSES NOCPD                    //No EE protection
#use delay(clock=4000000)
//Defines------------------------------------------
#BYTE PORTA = 0x05
#BYTE PORTB = 0x06
#BYTE PORTA_TRIS = 0x85
#BYTE PORTB_TRIS = 0x86
#DEFINE RDD_DATA  PIN_A1
#DEFINE RDD_CLOCK PIN_A0
#DEFINE EEPROM_SCL PIN_A2
#DEFINE EEPROM_SDA PIN_A3
//
void fConfigurar_puertos(void);
void fRDD_send_data0(void);
void fRDD_send_data1(void);
//--------------------------------------------------
//Main----------------------------------------------
//--------------------------------------------------
void main(){
  int8 i,j;
  fConfigurar_puertos();
  output_low(RDD_CLOCK); //RELOJ = Bajo
  output_low(RDD_DATA);
//
//------Dibujo las filas una a una -----  
//
  while (TRUE){
     PORTB = 0b11111110; //Filas 1 encendida, las demas apagadas.
     for (i=0;i<8;i++) {
        for (j=0;j<8;j++) {
            fRDD_send_data0();
           }
        delay_ms(200);
        PORTB = (PORTB <<1) +1;
     }
//
//------Dibujo rectangulos... -----  
//    
     PORTB = 0b11111111; //Filas  apagadas.
     for (i=0;i<8;i++) {fRDD_send_data1();}
     for (i=0;i<8;i++) {
        fRDD_send_data0();
        PORTB = PORTB /2 ;
            delay_ms(200);
         }
  }//Fin while
}//Fin main
//--------------------------------------------------
//- FUNCIONES-
//--------------------------------------------------
void fConfigurar_puertos(void){
  PORTA_TRIS = 0b11000000; //1=ENTRADA, 0=SALIDA
  PORTB_TRIS = 0b00000000; //1=ENTRADA, 0=SALIDA
  setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
  setup_timer_1(T1_DISABLED);
  setup_timer_2(T2_DISABLED,0,1);
  setup_comparator(NC_NC_NC_NC);
  setup_vref(FALSE);
}
//--------------------------------------------------
//---Envia un 0 al registro de desplazamiento:
//--------------------------------------------------
void fRDD_send_data0(void){
  output_low(RDD_DATA);
  delay_us(2);
  output_low(RDD_CLOCK);
  delay_us(2);
  output_high(RDD_CLOCK);
}
//--------------------------------------------------
//---Envia un 1 al registro de desplazamiento:
//--------------------------------------------------
void fRDD_send_data1(void){
  output_high(RDD_DATA);
  delay_us(2);
  output_low(RDD_CLOCK);
  delay_us(2);
  output_high(RDD_CLOCK);
}

Ejemplo 2: Recorriendo la matriz
Este ejemplo es un poco mas elaborado, pero no por ello más complicado que el anterior. Simplemente, se van encendiendo uno a uno los LEDs desde el que esta en la fila y columna cero hasta llegar al de la fila y columna 7. Luego, se repite una y otra vez. Se emplean las mismas funciones que en el ejemplo anterior.


Este es el código:

Código:

//Device/Fuses/Etc.---------------------------------
#INCLUDE <16F628A.H>
#INCLUDE <MATH.H>
#FUSES NOWDT                    //No Watch Dog Timer
#FUSES XT                      
#FUSES NOPUT                    //No Power Up Timer
#FUSES NOPROTECT                //Code not protected from reading
#FUSES NOBROWNOUT               //No brownout reset
#FUSES NOLVP                    //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#FUSES NOCPD                    //No EE protection
#use delay(clock=4000000)
//Defines------------------------------------------
#BYTE PORTA = 0x05
#BYTE PORTB = 0x06
#BYTE PORTA_TRIS = 0x85
#BYTE PORTB_TRIS = 0x86
#DEFINE RDD_DATA  PIN_A1
#DEFINE RDD_CLOCK PIN_A0
#DEFINE EEPROM_SCL PIN_A2
#DEFINE EEPROM_SDA PIN_A3
//
void fConfigurar_puertos(void);
void fRDD_send_data0(void);
void fRDD_send_data1(void);
//--------------------------------------------------
//Main----------------------------------------------
//--------------------------------------------------
void main(){
  int8 i,j;
  fConfigurar_puertos();
  output_low(RDD_CLOCK); //RELOJ = Bajo
  output_low(RDD_DATA);
  //
  while (TRUE){
     PORTB = 0b11111110; //Filas apagadas.  
     for (i=0;i<8;i++) {
        //Limpio columnas
        for (j=0;j<8;j++) {fRDD_send_data1();}
        //
        fRDD_send_data0(); //Enciendo la columna 0
        for (j=0;j<8;j++) {
           delay_ms(1);
           fRDD_send_data1();
        }
        //
        PORTB = (PORTB << 1 )+1 ; //Enciendo las columnas
        delay_ms(1);
        }
  }//Fin while
}//Fin main
//--------------------------------------------------
//- FUNCIONES-
//--------------------------------------------------
void fConfigurar_puertos(void){
  PORTA_TRIS = 0b11000000; //1=ENTRADA, 0=SALIDA
  PORTB_TRIS = 0b00000000; //1=ENTRADA, 0=SALIDA
  setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
  setup_timer_1(T1_DISABLED);
  setup_timer_2(T2_DISABLED,0,1);
  setup_comparator(NC_NC_NC_NC);
  setup_vref(FALSE);
}
//--------------------------------------------------
//---Envia un 0 al registro de desplazamiento:
//--------------------------------------------------
void fRDD_send_data0(void){
  output_low(RDD_DATA);
  delay_us(2);
  output_low(RDD_CLOCK);
  delay_us(2);
  output_high(RDD_CLOCK);
}
//--------------------------------------------------
//---Envia un 1 al registro de desplazamiento:
//--------------------------------------------------
void fRDD_send_data1(void){
  output_high(RDD_DATA);
  delay_us(2);
  output_low(RDD_CLOCK);
  delay_us(2);
  output_high(RDD_CLOCK);
}


Videos
Algunos videos de la matriz funcionando:

Video correspondiente al Ejemplo1:
http://www.youtube.com/watch?v=Kp2LvbqODHk

Video correspondiente al Ejemplo2:
http://www.youtube.com/watch?v=43yy1rZ8QY8


Otro video mostrando las posibilidades del display:
http://www.youtube.com/watch?v=UUsd4jOsBe0

Autor: Ariel

Ascheriit:
Muchas gracias a Ariel por este aporte!!!  :bang:

Yo tengo una matriz de 8x8 ánodo común, y ya que este circuito está controlado por los ánodos, tengo dudas de cómo lo puedo implementar para utilizar mi matriz??? Es necesario hacer modificaciones??? Cuáles son???  :titanic

Se agradece mucho la ayuda ya que es un proyecto que tendré que desarrollar en las próximas 2 semanas ;D

Ariel:
Cita de: Ascheriit en Abril 11, 2010, 06:39:31

Muchas gracias a Ariel por este aporte!!!  :bang:

Yo tengo una matriz de 8x8 ánodo común, y ya que este circuito está controlado por los ánodos, tengo dudas de cómo lo puedo implementar para utilizar mi matriz??? Es necesario hacer modificaciones??? Cuáles son???  :titanic

Se agradece mucho la ayuda ya que es un proyecto que tendré que desarrollar en las próximas 2 semanas ;D


La verdad es que no entiendo lo de "anodo comun" o "catodo comun" en una matriz... ???

¿No podrias usar cualquiera de las dos, simplemente girandola "electricamente" 90 grados?

Yo use LEDs sueltos... ;D

Suky:
Cátodo común: Todos los cátodos (terminal negativo/gnd) unidos en un solo pin por ejemplo para una misma columna. Para encender el led de una determinada fila se debe enviar un pulso positivo (+V) al pin.

En cambio los de ánodo común (terminal positivo) los pines están unidos en un solo pin. Para encender el led de una determinada fila se debe enviar un pulso negativo (GND) al pin.



Saludos!

Ariel:
Cita de: Suky en Abril 11, 2010, 07:26:09

Cátodo común: Todos los cátodos (terminal negativo/gnd) unidos en un solo pin por ejemplo para una misma columna. Para encender el led de una determinada fila se debe enviar un pulso positivo (+V) al pin.

En cambio los de ánodo común (terminal positivo) los pines están unidos en un solo pin. Para encender el led de una determinada fila se debe enviar un pulso negativo (GND) al pin.



Saludos!


Ahh, ok! Por columnas es la cosa! ;D

Navegación

[0] Índice de Mensajes

[#] Página Siguiente