Mostrando entradas con la etiqueta Conexión. Mostrar todas las entradas
Mostrando entradas con la etiqueta Conexión. Mostrar todas las entradas

MAX232, conectando un PIC al ordenador

Una de las comunicaciones mas comunmente utilizadas en informática y/o electrónica es la comunicación serie, y dentro de este tipo de comunicaciones se encuentra la USART (Universal Synchronous Asynchronous Receiver Transmitter o en español: Receptor y emisor síncrono o asíncrono universal).

El puerto serie del PC normalmente tiene 9 pines, pero la ventaja de este sistema es que se puede utilizar solo dos líneas de datos y una tercera de GND, para establecer una comunicación bidireccional. Dichas líneas de datos son TX, para transmitir y RX para recibir datos.

La conexión de PC a PC es tan sencilla como cruzar los cables TX de la PC1 se conectará a RX de PC2 y el TX de PC2 a RX de PC1, como se muestra en el siguiente diagrama:

Si bien esta forma de comuncicación quedó un poco anticuada, pero no obsoleta del todo, gracias a la aparición de tecnologías mas avanzadas como USB (Universal Serial Bus, Bus serie universal) es muy recurrida gracias a su compatibilidad, su poco requerimiento de hardware adicional y la sencillez de manejo, estos dos últimos puntos se deben, en gran parte, a que el gestionamiento se hace con hardware exclusivo.

Casi toda la gama de PIC dispone de USART, por no decir que toda la actual; Para comunicarnos con un ordenador vía puerto serie, los PIC disponen de dos pines para tal fin, estos son RX y TX que, dependiendo del modelo de microcontrolador están compartidos con otros recursos.

Ahora bien, sabemos que estos controladores manejan tensiones TTL a 5V, esto quiere decir que, para el PIC, un 0 lógico equivale a  un voltaje muy cercano o como mínimo a 0V y un 1 lógico a un voltaje de 5V como máximo.

El ordenador entiende un 0 lógico cuando la tensión en el pin correspondiente del puerto serie es de entre +3V y +15V, un 1 lógico es cuando esa tensión se encuentra entre -15V y -3V.

Esto solo puede significar algo, si bien el PIC entiende el lenguaje que habla el PC mediente el puerto serie, no se puede conectar directamente porque indudablemente algo no muy agradable le sucederá, es por ello que disponemos del archifamoso integrado MAX232.

Este integrado de 16 pines se encarga, el solo, de invertir y adaptar las señales procedentes tanto desde el PIC hacia el PC como las señales en sentido contrario.

El pinount del MAX232 es la siguiente:

El integrado dispone de 2 receiver y 2 transmitter. Esto puede ser un poco confuso a primera vista pero ya veremos que no lo es.

El primer transmisor esta conformado por T1IN y T1OUT (Pin 11 y 14 respectivamente) y el segundo lo conforman T2IN y T2OUT (Pin 10 y 7), lo mismo sucede con el receptores, el primero R1IN y R1OUT (Pin 13 y 12) y el otro es R2IN y R2OUT (Pin 8 y 9).

Ahora bien, como este integrado esta diseñado para adaptar los niveles del RS232 a los niveles TTL (y viceversa) las nomenclaturas de los pines están expresados del lado del microcontrolador, es decir que cuando se refiere a transmitter se refiere al PIC, el TX del PIC se conectará al TnIN (n es el 1 o 2), la señal TX entra en TnIN y sale por TnOUT hacia el PC. Lo mismo pasa con el receptor, la señal RX del ordenador entra en RnIN y sale hacia el PIC por RnOUT.

La conexión del microcontrolador al PC medienate el MAX232 quedaría como en el siguiente esquema:
Aparte de los pines correspondientes a las señales, el MAX232 dispone de otros, pero son solo para conectarle los componentes adicionales necesarios para su funcionamiento, veámos:

Se observa que dichos componentes no son ni mas ni menos que 5 capacitores, mas especificamente capacitores electrolíticos de 1µF y de unos 16V, si se utilizan de tantalio aún mejor.

Bueno, eso es todo por ahora, luego faltaría algún ejemplo real del manejo de RS232 en CCS C para comunicarse con un ordenador.

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

Controlar 8 displais de 7 segmentos con shift register

Continuando con el tema de los shift register, ofreceré algunas utilidades a dichos integrados utilizando un microcontrolador a modo de ejemplo y totalmente funcionales.

El ejemplo que aquí propongo es la utilización de los registros para controlar 8 displais de 7 segmentos, como ya vimos anteriormente en este artículo, pero con el agregado de la implementación de un teclado; Pero aquí les proporciono el ejemplo completo con el código fuente en CCS C y su respectivo .HEX para que puedan grabarlo en el PIC y probarlo.

He aquí el diagrama de conexión:

El diagrama es bastante sencillo, solo hace falta conectar cada segmento de cada display a las salidas (Q0-Q7) del shift register encargado de "dibujar" los números y el ánodo común de cada display a cada una de las salidas del segundo integrado. También este diseño es válido si los displais son de cátodo común la única diferencia está en que habría que hacer una pequeña modificación en el código.

Para probar el código que les propongo, al diagrama anterior hay que agregarle algunas cosas como por ejemplo 10 pulsadores, 10 diodos 1N4001-7 y 2 resistencias de unos 10KΩ, como se ve en el siguiente diagrama.

Cada ánodo de los diodos se conecta a una salida diferente del shift register encargado de seleccionar el display que se iluminará, de esta forma multiplexámos el teclado de modo que a cada iteración del bucle encargado de encender un display comprobamos una tecla, como esto nos da la posibilidad de conectar solo 8 pulsadores, se agrega otra entrada para comprobar una segunda línea.

A continuación les dejo el código:
/*************************************************************************
**                                                                      **
**             Ejemplo para controlar 8 display de 7 segmentos          **
**              y un teclado con dos shift register y un 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,NOPUT,NOBROWNOUT // Fuses 
#use fast_io(all)      
#use delay(clock=8M)

#define Load      PIN_B0   // Load (STCP ambos integrados) B0
#define Clk       PIN_B1   // Clock (SHCP ambos integrados) B1
#define dDsp      PIN_B2   // Data para seleccionar display (DS integrado 1) B2
#define dSeg      PIN_B3   // Data para activar segmentos (DS integrado 2) B3
#define Teclado1  PIN_B4   // Entrada de teclas 0-7
#define Teclado2  PIN_B5   // Entrada de teclas 8 y 9

#define Seg_A  0x01
#define Seg_B  0x02
#define Seg_C  0x04
#define Seg_D  0x08
#define Seg_E  0x10
#define Seg_F  0x20        // Los bits correspondientes a cada segmento de cada display.
#define Seg_G  0x40        // Estos bits se comparan mediante la máscara Mask.

int Digit[8];
int Numero[10]={
Seg_A + Seg_B + Seg_C + Seg_D + Seg_E + Seg_F,
Seg_B + Seg_C,
Seg_A + Seg_B + Seg_D + Seg_E + Seg_G,
Seg_A + Seg_B + Seg_C + Seg_D + Seg_G,
Seg_B + Seg_C + Seg_F + Seg_G,
Seg_A + Seg_C + Seg_D + Seg_F + Seg_G,
Seg_A + Seg_C + Seg_D + Seg_E + Seg_F + Seg_G,
Seg_A + Seg_B + Seg_C 
Seg_A + Seg_B + Seg_C + Seg_D + Seg_E + Seg_F + Seg_G,
Seg_A + Seg_B + Seg_C + Seg_D + Seg_F + Seg_G
}; // Establece Numero[0-9] con los datos correspondientes a cada segmento que deberá encender.

void CargaMem(char Ascii);
void GuardaClm(char c);

void main(){
   int d;
   int b;
   int Mask;   
   int Tecla;
   int anTecla;
   
   setup_ccp1(CCP_OFF);
   set_tris_a(0);                      // Puerto A como salida
   set_tris_b(0b00110000);             // Puerto B como salida excepto B4:B5 como entradas
   
   setup_oscillator(OSC_8MHZ);   
   
   d=0;
   anTecla=10;
   
  do{      
      Mask=0x80;                       // Carga la mascara, solo el MSB en high                  
      for (b=0;b<8;b++){               // Un bucle de 8 pasos (0-7)
         
         output_bit(dSeg,!(Mask&Numero[Digit[d]]));         // Le envía los bits al shift
                                                            // register encargado de encender
                                                            // los segmentos.
         if (b==d) output_high(dDsp); else output_low(dDsp);// Pone en alto el bit corres-
                                                            // pondiente al display que se va a
                                                            // encender en esta iteración.
         
         Mask>>=1;                     // Divide la mascara por 2 : 128, 64, 32...
         output_low(Clk);              // Low-to-High en el Clk
         output_high(Clk);             // hace que la memoria del shift register rote
      }
      
      output_low(Load);                // Low-to-High en Load hace que la memoria
      output_high(Load);               // del shift register se represente en sus salidas 
      
      if (input(Teclado2)) Tecla=d+9;  // Comprueba que se haya detectado la pulsación en las
      if (input(Teclado1)) Tecla=d+1;  // entradas de teclado y lo guarda en la variable Tecla.
      
      if (++d>7){                      // Incrementa el display a mostrar
                                       // si se pasa de 7 vuelve a 0-         
         if (Tecla!=0 && AnTecla==0){  // Si Tecla es diferente a 0 (se ha pulsado una tecla)
            for (b=7;b>0;b--){
               Digit[b]=Digit[b-1];    // Hace un scroll en los display
            }
            Digit[0]=Tecla-1;          // y guarda la tecla pulsada en el ultimo display.
         }
         AnTecla=Tecla;                // Guarda la tecla pulsada y 
         Tecla=0;                      // pone Tecla a 0 para comprobar la proxima vez.
         d=0;                          // d a 0 para encender el primer display y comenzar
      }                                // otra vez.
   }while (true);                      // Bucle infinito
}

Espero que les haya gustado y lo próximo que les entregaré será un artículo sobre el control de un array de 8x8 LED con el mismo sistema.

Desde este link se puede bajar el código y el .HEX

Puente H

Navegando por uno y otro lado, siempre me encuentro con el dilema de la gente a la hora de controlar un motor con un microcontrolador. Hay muchas soluciones en forma de integrados, pero estos son algo limitados y, hasta en algunos casos, demasiado costosos o difíciles de conseguir.

La mejor solución, sin lugar a dudas, es utilizar un puente H, pero con este tema surge otro problema en la gente, ¿como funcionan?, ¿como se arman?, ¿cuál es mejor?... para responder a todas esas preguntas, trataré de explicar aquí de una forma sencilla el funcionamiento de estos.

Se sabe que en un motor de corriente continua, el sentido de giro viene dado por la conexión que se le haga a sus bornes. Entonces para hacer que un robot vaya hacia adelante o hacia atrás, bastará con invertir la polaridad del motor que mueva sus ruedas, el problema es como hacer esto, el PIC solo puede suministrar 5v y 20mA por pin totalmente insuficiente para mover un motor, lo que se intenta lograr es poder controlar una tensión y una corriente superior que la que el integrado pueda darnos por medio de una señal que será enviada por el PIC.

En definitiva, el encargado de controlar esa tensión será el Puente H y el PIC controlará a este último.

Figura 1. Motor de corriente continua conectado a dos interruptores inversores.

Cuando conectamos un motor como en el gráfico de la figura 1, girará en un sentido u otro, o se parará según la combinación de los interruptores, el puente H hace lo mismo con la diferencia de que el control se realizará digitalmente y los interruptores mecánicos se reemplazarán por transistores PNP y NPN. De modo que se puede controlar el motor de una forma muy precisa, y con cambios giro/parada a una velocidad muy elevada, pudiendo controlar la velocidad de giro por una señal PWM (Pulse Width Modulation o Modulación por Ancho de Pulsos).

Figura 2. Puente en H. 

Si se compara la imagen de la figura 1 con el de la figura 2 se observa que es muy similar, puesto que los interruptores de la primera están reemplazados por un par de transistores, cada uno, en la segunda.

Buscando entre los datasheets encontramos el BD677 (NPN) y BD678 (PNP), que son unos transistores complementarios capaces de soportar 60V y 4A. Suficiente para mover cualquier robot de medianas dimensiones.

Entonces sabiendo esto podremos crear nuestro puente H del diagrama utilizando estos componentes:

Q1,Q2Transistores 2N2222
Q3,Q4Transistores BD678
Q5,Q6Transistores BD677
D1,D2,D3,D4Diodos 1N4007
R1,R2Resistores de 470Ω
R3,R4Resistores de 22Ω

Dos puentes H como el aquí mostrado son los encargados de mover al robot SiLMuP, que a su vez son controlados por señales PWM enviadas por un PIC16F876.

Aquí les dejo un vídeo con la demostración del Puente H funcionando, debido a la reductora del motor (es un potenciómetro con motor de equipo de audio) el movimiento es lento, pero el Puente H es apto para mover motores relativamente potentes, hasta 60V y 4A.

En el disipador hay un regulador de voltaje LM7805 y solo se incluyó en el circuito para suministrar la señal de activación avance/retroceso, se podría haber activado con la misma tensión que alimenta al Puente H pero lo incluí para demostrar que el Puente H puede ser perfectamente controlado con un PIC. También sería recomendable, en las enatradas de avance/retroceso, ponerle resistencias pull-down para que no se activen por alguna interferencia.

Controlar display de 7 segmentos con shift register

Ya vimos lo que es y como se controla un shift register, ahora veremos una de las tantas utilidades que tiene. Aquí se explicará como utilizar un shift register para controlar un display de 7 segmentos.

Para el que todavía no lo conozca, un display de 7 segmentos es un panel conformado por 7 LED que comparten entre si sus ánodos o cátodos según si sean de ánodo o cátodo común respectivamente.

A un display de ánodo común deberemos aplicar tensión positiva al pin compartido y GND a cada uno de los pines correspondientes a los segmentos que se quieran iluminar, para un display de cátodo común deberemos invertir la polaridad. La mayoría de displais poseen también un octavo segmento que normalmente es un punto o dos.

Hasta aquí una pequeña introducción para conocer un poco su funcionamiento, ahora bien, vimos que un shift register serial-paralelo “memoriza” el estado (0 o 1) de un pin (entrada) y va rotando esos valores por cada pulso de reloj para representar la secuencia completa, cuando se activa el pin Load, en unos pines asignados que tiene el integrado a tal fin.

Si a cada pin de salida (Q0-Q7) del integrado le conectamos un segmento del display, como en la figura 1, logramos encender y apagar dichos segmentos independientes unos de los otros. La principal utilidad es representar un número del 0 al 9 o una letra de la A a la F.

La ventaja de usar el shift register es que sólo necesitaremos 3 pines del microcontrolador: Clock (Amarillo), Data out (Verde) y Load (Rojo).


Figura 1. Conexión de un display de 7 segmentos a un shift register.

Si en lugar de emplear un solo integrado usamos dos (Figura 2), podremos multiplexar los datos. Utilizando el segundo integrado para seleccionar el display que deseamos encender en determinado momento, aumentaremos el numero de displais de 1 a 8 con un integrado mas.

8 display de 7 segmentos conectados a 2 shift register
Figura 2. Conexión de 8 display de 7 segmentos a 2 shift register.

Si encendemos un display, lo apagamos y luego encendemos otro, y hacemos todo esto de manera muy rápida el cerebro humano lo interpreta como si en realidad todos los display permanecieran encendidos al mismo tiempo. Jugando con esto podemos ahorrarnos muchísimos pines de nuestro PIC, por ejemplo si quisiéramos hacer un reloj que indique la hora, los minutos y los segundos, y conectáramos cada segmento a cada pin de un microcontrolador necesitaríamos uno con 42 pines solo para los displais.

Sin shift register también se puede multiplexar, pero aun así utilizaríamos demasiados pines, 7 para los segmentos y 1 para cada display, para diseñar el mismo reloj del ejemplo anterior necesitaríamos un total de 13 pines contra los 4 que se necesitan implementando los registros de desplazamiento.

Para usar los dos integrados, se conectan siguiendo el diagrama de la figura 2, el segmento A de todos los displais con la Q0 del primer integrado, los segmentos B con el Q1, los C con Q2… y así sucesivamente. La salida Q0 del segundo integrado se conecta al común del primer display, el pin Q1 al segundo, el Q2 al tercero… así hasta un máximo de 8 displais.

Para controlarlo enviaremos los bits que conforman el caracter del primer display al primer integrado y el bit correspondiente a dicho display en 0, a cada pulso de reloj, cuando hayamos enviado todos los bits se manda el pulso Load y es cuando aparece el caracter en el primer display, luego se repite la operación pero con el bit del segundo display en 0, de esa forma, y si los displais son de cátodo común, encenderán de a uno. A una alta frecuencia esto crea la ilusión de estar todos encendidos.

Utilizando dos shift registers y 4 pines del microcontrolador tendremos capacidad para controlar 8 displais, y si utilizáramos un integrado y un pin del microcontrolador más, aumentaríamos la cantidad de displais a 16.

Control de un módulo LCD con PIC y CCS C

Partiendo de saber la Conexión y funciones de un módulo LCD ahora veremos como se utiliza en la práctica. Para empezar aquí les dejo el diagrama de la conexión mas básica para poder comenzar a utilizar el display.

Conexión LCD a PIC16F84A

En el diagrama utilizamos el Pin 0 del puerto A para la señal Enable del display y el Pin 1 del mismo puerto para la señal RS.

R/W lo conectamos directamente a GND ya que en este proyecto no leeremos el estado del display en ningún momento.
El puerto B lo dedicaremos enteramente al bus de datos del LCD.

Todos los puertos que no utilizaremos, asi como el RESET del PIC, los conectamos a 5V por medio de un resistor.

Alimentamos todo a 5V por medio de una fuente que puede llegar a ser la Fuente de alimentación y cargador de baterías explicada en este blog y listo.

Pero falta algo, el programa o firmware que hace que el display haga algo... Para eso debemos crear el código, compilarlo y grabarlo en el PIC para que este lo ejecute, nosotros usaremos CCS C .

La rutina que hace esto sería esta:

#include <16f84a.h>
#use delay (clock=4000000)

#define E Pin_A0
#define RS Pin_A1

/*  Declaro las funciones antes de utilizarlas en main()
    para que sean reconocidas  */

void print(int c);
void Enviar(int8 Dato, int1 Comando);
void Iniciar_LCD(void);

//Comienzo del programa

void main(void){
   Iniciar_LCD();                // Inicio el Modulo
   print ("PICROBOT");           // Escribo PICROBOT en la pantalla
}
                                       
//Funciones

void print(int8 c){
   enviar (c,1);                 // Envio caracter c con RS a 1 (dato)
                                 // CCS C se encarga de enviar uno a uno
}                                // los caracteres contenidos en c
                                     
void Enviar(int8 Dato, int1 Comando){
   output_low(E);                // E en bajo
   output_b(Dato);               // Cargo el puerto B con Dato
   output_bit(RS,comando);       // Pongo RS en 0 o 1 dependiendo si es
                                 // un comando o dato lo que estoy
                                 // enviando
   output_high(E);               // E en alto
   delay_us(1);                  // Espero a estabilizar tensión
   output_low(E);                // E en bajo
   delay_us(40);                 // Espero 40 uS a que el LCD trabaje
                                 //
   if (Dato < 4) delay_us(1600); // Si envio un Home o un Clear display
                                 // espero otros 1600 uSegundos que
                                 // sumado a los 40 uS anteriores hacen
}                                // 1.64 mS que es lo que tardan estas
                                 // operaciones

void Iniciar_LCD(void){          //
   delay_ms(15);                 // Espero a que se estabilice
                                 // la tensión.
   
   enviar(0b00000001,0);         // Envio un CLEAR DISPLAY
                                 // (Borra la pantalla)
   
   delay_ms(5);                  // Espero 5 mS
   
   enviar(0b00111000,0);         // Envio un FUNCTION SET para bus de 8
                                 // bits, 2 lineas y caracteres de 5x7
                                 // pixeles.
   
   enviar(0b00001100,0);         // Envio un DISPLAY ON/OFF CONTROL
                                 // con pantalla encendida, Cursor
                                 //  apagado y si parpadear.
   
   enviar(0b00000110,0);         // Envio un ENTRY MODE SET con 
                                 // Incrementa cursor y desplaza cursor
}

Este programa introducido en el PIC conectado al circuito anterior hace que nuestro módulo muestre en pantalla la frase:

PICROBOT

En realidad lo único que hace es inicializar el LCD y mostrar el mensaje, se puede adaptar y hacer que muestre cualquier frase cambiando simplemente la palabra PICROBOT por lo que deseen en la línea:

print ("PICROBOT");

Hay que aclarar que para que funcione hay que respetar las comillas.

Pero si arman el circuito y graban el PIC con la rutina, verán que pueden modificar la frase, pero siempre aparecerá en la primer línea. Si volvemos a Conexión y funciones de un módulo LCD y consultamos dichas funciones, veremos que hay una que se llama SET DD RAM ADDRESS; La memoria DD RAM es la que contiene los caracteres que están en pantalla. De modo que esa función se llama Establecer la dirección de la DD RAM, o sea, que lo que hace es cambiar la posición donde se almacenará el próximo caracter, por lo tanto, lugar donde aparecerá en pantalla.

Para hacer que escriba donde queramos, antes de escribir, deberemos ejecutar un SET DD RAM ADDRESS. Continuando con nuestra rutina lo podemos hacer del siguiente modo:

void locate(x,y){
   int d=128;                // Cargo d con 128 (10000000) b7 a 1
   d+=y*64;                  // si y (linea) es 1 sumo 64 a d (11000000) b6 a 1
   d+=x;                     // a todo esto le sumo la posicion de x
   enviar (d,0);             // envio todo al display con RS a 0 (comando)
}

Entonces si, por ejemplo, queremos escribir Hola en la primer línea y Mundo en la segunda, el main() de nuestra rutina se vería así:

void main(void){
   Iniciar_LCD();             // Inicio el Módulo
   locate(6,0);               // Ubico el cursor en la columna 6
                              // de la primer línea
   print ("HOLA");            // Escribo HOLA
   locate(5,1);               // Ubico el cursor en la columna 5
                              // de la segunda línea
   print ("MUNDO");           // y escribo MUNDO
}

En un display de 16 caracteres x 2 líneas se verá centrada la frase HOLA MUNDO. Cabe destacar que antes de poder utilizar la función locate() se debe declarar mediante la sentencia:

void locate(x,y);

Luego podemos simplificar el borrado de la pantalla (CLEAR DISPLAY) con la función:

void cls(void){
   enviar (1,0);              // envio 00000001 (Clear display) 
}                             // con RS a 0 (comando)

Recuerden que CLEAR DISPLAY era 00000001 que es igual a 1 en decimal. De esta forma y previamente declarado cada vez que querramos borrar la pantalla introduciremos en el código la línea cls(); Por último en la entrada Librería para el manejo de un módulo LCD en CCS C encontrarás todas las funciones y la opción para descargarla.

Conexión y funciones de un módulo LCD

Una pantalla de cristal líquido o LCD (Liquid Cristal Display) es un dispositivo para la presentación de imagenes o caracteres. En este caso usaremos uno basado en el µControlador Hitachi 44780 o compatible, que muestra 16 o 20 caracteres en 1, 2 o 4 líneas. Las funciones de control son iguales para todos los modelos.

Conexionado:
PINNombreDirecciónFunción
01VssPGND
02VddPAlimentación a 5V
03VeePControl de contraste
04RSISelección de Registro / Dato
05RWISelección de Escritura / Lestura
06EIEnable / Disable
07 - 14D0 - D7I/OBus de datos
15 - 16A - KPCorresponden al ánodo y cátodo del backlight  (si el modelo lo tiene)

Bueno, la operacion del display es bastante sencilla ya que el µControlador interno, hace casi todo el trabajo, para comandarlo debemos saber como funcionan sus pines.

Para enviar un comando o un dato deberemos primero indicar que es lo que estamos enviando para eso se usa el pin RS, cuando este pin esta en 0 el LCD interpretará la información que esta prensente en sus pines D0 a D7 como un comando, si está en 1 significa que estamos enviandole un caracter, en cuyo caso se imprimira donde esté actualmente el cursor.

Asimismo en lugar de enviar información puede llegar el momento en que queramos leer algo de su memoria, para eso se utiliza el pin R/W, en 0 el LCD estará en modo escritura y en 1 en modo lectura.

El pin E es el que le indica al display que ejecute la operación que estamos enviandole, cuando este pin esta en 0 cualquier modificación que hagamos en sus otros pines será ignorada. Entonces la forma de proceder será asi:


- Se colocan los pines RS en 1 o 0 dependiendo si vamos a enviar un caracter o una dirección.

- R/W a 0 si queremos enviar un caracter o un comando y en 1 si queremos leer algun dato del display.

- Ponemos D0 a D7 Con el valor del caracter que queremos imprimir, o con el comando que deseamos ejecutar en el display ( si R/W es 1 estos pines se convertiran en salidas y solo podremos leer el estado)

- Por ultimo se pone en alto el pin E y el display ejecutará la función.

Ahora bien, como ya comenté por ahi, el R/W no lo usaremos, ya que como nosotros escribiremos en el display no necesitaremos obtener ninguna información de el, para hacer esto basta con conectar el pin 5 (R/W) directamente a GND y el LCD estará siempre en modo escritura.

El funcionamiente se resumiría asi: RS nos servirá para indicarle al LCD si lo que le estamos mandando es un comando o un caracter; D0 a D7 para enviarle el dato o el comando y E para que lo ejecute.

Para enviar un caracter simplemente ponemos RS en 1 y el valor binario del caracter en los pines D0 a D7E y aparecerá nuestro caracter en pantalla. luego pasamos a 1 el pin.

Impresión de caracteres.

Pero esto solo nos permite escribir un caracter al lado de otro, para seleccionar donde escribir, borrar pantalla etc debemos hacer el mismo procedimiento pero con el pin RS en 0 y los pines D0 a D7 con el valor del comando correspondiente a la operación que queramos hacer:

CLEAR DISPLAY Borra el contenido de la pantalla.

HOMEColoca el cursor en el primer espacio de la primera línea sin modificar el contenido de la pantalla.

ENTRY MODE SETEspecifica el modo en que se imprimiran los caracteres. 

I/D = 0 Incrementa el cursor 
I/D=1 Decrementa el cursor  
S=0 Desplaza el cursor
S=1 Desplaza el display

DISPLAY ON/OFF CONTROL Control de encendido y apagado de la pantalla.

D=0 Pantalla apagado
D=1 Pantalla encendida
C=0 Oculta el cursor
C=1 Muestra el cursor
B=0 Cursor estático
B=1 Cursor parpadeante

CURSOR OR DISPLAY SHIFT Mueve el display o el cursor.

S/C=0 Mueve el cursor
S/C=1 Mueve el display
R/L=0 Mueve a la derecha
R/L=1 Mueve a la izquierda

FUNCTION SET Establece el bus de datos, cantidad de líneas y modo de caracteres.

DL=0 Bus de datos de 4 bits (D4 a D7)
DL=1 Bus de datos de 8 bits (D0 a D7)  
N=0 LCD de 1 línea  
N=1 LCD de 2 líneas
F=0 Caracteres de 5 x 7 pixeles
F=1 caracteres de 5 x 10 pixeles

SET CG RAM ADDRESS

Ingresando de este modo la dirección de la CG RAM, indica que cuando usemos el comando para escribir en el display, lo que enviaremos serán caracteres personalizados, se necesitan 7 instrucciones por caracter.

SET DD RAM ADDRESS

Cuando escribimos en el display lo que en realidad estamos diciendole al módulo que haga es almacenar X caracter en Y posición de memoria, con este comando indicamos en que lugar de la DD RAM se guardará el próximo caracter que enviemos. 80-8F corresponde a la memoria para la primera linea y C0-CF a la segunda.

Lo siguiente que nos queda es mostrar las rutinas para hacer todo esto, y eso lo pueden ver en este apartado: Control de un módulo LCD con PIC y CCS C


Tal vez le interese: