PIC-Cal, un PIC hecho calculadora.

... O una calculadora hecha con PIC.
En esta ocación les presento una calculadora hecha con un PIC16F88 y un módulo LCD administrado con el microcontrolador Hitachi 44780 o compatible.
Esta no es una gran calculadora, pero resuelve fórmulas algebraicas reconociendo términos y utilizando parentesis. Esta versión todavía no maneja números negativos ni decimales, ya que solo el hecho de utilizar números float32 aumenta el consumo de memoria flash del PIC desde el 60% hasta cerca del 80%. Si se quisiera hacer una calculadora mas exacta y compleja se tendría que recurrir a un PIC con mas memoria.
El proyecto es una mezcla de la práctica de varios artículos que se pueden encontrar en este blog. Ya que utiliza la librería LCDGAR.c para el display, controlado con un shift register que a su vez se usa para barrer el teclado.
El código es demasiado extenso como para publicarlo en el blog, por ese motivo es que solo dejo el link para descargar el proyecto completo en CCS C y la simulación en ISIS. De todos modos pasaré a comentarlo brevemente:
El bucle principal espera a que se pulse una tecla, cuando esto sucede actua en consecuencia de la tecla pulsada. Esta es la parte sencilla.
Cuando se pulsa cualquier tecla, que no sea el signo igual, la almacena en una cadena y si se pulsa el signo igual, resuelve. Esto en teoría también es sencillo.
Ahora la pregunta es ¿cómo se resuelve?, pues bien, las calculadoras normales van haciendo las operaciones según se las vayan ingresando. Pero sabemos que en matemáticas esto no es así, una calculadora científica, reconoce términos, y eso es lo que se pretendía resolver en este proyecto, luego se agregó el uso de parentesis, pero la forma de resolverlos es igual para ambos casos.
Supongamos que la fórmula ingresada es:

15 X 3 + 8 X 4

Para resolverlo, con lápiz y papel, no podemos hacer:

15 X 3 = 45
45 + 8 = 53
53 X 4 = 212

La forma correcta sería separandolo en términos, que es de esta forma:

15 X 3 = 45
8 X 4 = 32
45 + 32 = 77

15 X 3 + 8 X 4 = 77

Eso es lo que se pretende que haga la calculadora, para eso, una vez pulsada la tecla resolver, la secuencia es como se muestra a continucación:
Paso 1Se recorre toda la fórmula. Si encuentra un + o un - corta la fórmula, de modo que queden tres términos y si hay mas de tres, en el último habrá varios términos.
Paso 2Resuelve el segundo término, dejando en este el resultado.
Paso 3Junta el primer término con el segundo en un único y primer término.
Paso 4Resuelve el primer término, dejando el resultado.
Paso 5Junta el resultado del primer término con el tercero en la fórmula.
Paso 6Si todavía hay cuentas por realizar vuelve al paso 1.
FINPresenta el resultado en pantalla.

En la práctica para la fórmula 3 X 3 + 8 X 4 - 2 X 3, pasaría lo siguiente:
Vuelta 1 Paso 1 Recorre la fórmula buscando + y -, recortándola y dejando:
Primer término: 3 X 3 +
Segundo término: 8 X 4
Tercer término: - 2 X 3
Paso 2 Resuelve el segundo término:
Segundo término: 32
Paso 3Junta el primer y el segundo término:
Primer término: 3 X 3 + 32
Paso 4Resuelve el primer término:
3 X 3 = 9
9 + 32 = 41
Primer término: 41
Paso 5Junta el primer y tercer término, en fórmula:
Fórmula: 41 - 2 X 3
Paso 6Hay cuenta, vuelve al paso 1.
Vuelta 2 Paso 1 Recorre la fórmula buscando + y -, recortándola y dejando:
Primer término: 41 -
Segundo término: 2 X 3
Tercer término: (vacío)
Paso 2 Resuelve el segundo término:
Segundo término: 6
Paso 3 Junta el primer y el segundo término:
Primer término: 41 - 6
Paso 4Resuelve el primer término:
41 - 6 = 35
Primer término: 35
Paso 5Junta el primer y tercer término, en fórmula:
Fórmula: 35 (No hay nada en el tercero)
Paso 6No hay mas cuentas, sale del bucle.
FIN Presenta el resultado en pantalla.
Los parentesis se resuelven utilizando el mismo método, con la diferencia que utiliza el contenido de los mismos como fórmulas independientes y son las primeras en resolverse. El algoritmo detecta parentesis dentro de parentesis.
Para terminar, aclarar que el código no está pulido ni probado al 100%, de modo que puede, y debe, tener muchos bugs. Pero lo comparto por si a alguien le es útil como ejemplo. Si se encuentra algún error o alguna modificación significativa, bienvenidas serán sus sugerencias.
El primer bug que sé que va a tener, es que no se puede ingresar fórmulas de mas de 64 caracteres, y el código no tiene ningún tipo de control para evitar la catástrofe cuando se ingrese el número 65.

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.

Inicio

Desde esta entrada puede buscar el contenido deseado.
Cargando el buscador...


                                                                                   
PIC-Cal, un PIC hecho calculadora
MAX232, conectando un PIC al ordenador
Algoritmo antirrebote de pulsadores
Puente H
Conexión y funciones de un módulo LCD
Control de un módulo LCD con PIC y CCS C
Librería para el manejo de un módulo LCD en CCS C
Generar sonido con PIC
Generar música con PIC
Fuente de alimentación y cargador de baterías
Reguladores de voltaje 7805
Reguladores de voltaje, ¿cuál mejor?
Probador de PIC 16X84
Probador de PIC 16F876A
SHIFT REGISTER ¿que son y cómo se usan?
Controlar display de 7 segmentos con shift register
Controlar 8 displais de 7 segmentos con shift register
Matriz de 8x8 LED controlada con 2 shift register y PIC
NE555
Grabador de PIC
Robot SiLMuP
Sitios de interés

Algoritmo antirrebote de pulsadores

Indagando en foros uno se da cuenta que lo que parece tan fácil como capturar la simple pulsación de una tecla conectada a un pin de un microcontrolador, en el fondo lleva consigo algunas técnica a tener en cuenta; Muchos son los que preguntan, sobretodo cuando se está iniciando en materia de programación de microcontroladores, como debería ser un buen algoritmo de antirrebote. Pues bien, en esta ocasión les traigo la implementación de la rutina escrita en CCS C para PIC16F88, que, si bien puede que no sea la mejor, es sin duda, muy funcional y práctica, al menos cumple su función a las mil maravillas. Es el modo en que hago el antirrebote en mis códigos y hasta ahora no ha fallado nunca.

La teoría es bastante sencilla, el programa espera a que se pulse una tecla, cuando detecta la pulsación guarda el número de tecla pulsada en una variable, luego comprueba que sea la primera vez que se pulsó, si es así actúa en consecuencia y si es que está pulsada desde antes, comprueba que haya pasado un tiempo determinado para volver a tenerla en cuenta. De este modo se puede hacer, por ejemplo un reloj que cuando se incremente alguno de sus parámetros, por ejemplo los minutos, y la tecla correspondiente se mantenga pulsada, luego del primer incremento comience a avanzar mas rápido.


He aquí el código en CCS C:
#include <16f88.h>
#use delay(clock=8MHz)
#use fast_io(all)
#fuses MCLR,NOPUT,INTRC_IO,NOWDT,NOBROWNOUT


#define Tec1   PIN_B0
#define Tec2   PIN_B1
#define Tec3   PIN_B2
#define Tec4   PIN_B3   //Pines del PIC correspondientes a cada tecla.

#define Nada   0  
#define Mas    1     // valores validos para Flag
#define Menos  2  

int Segs;            // Segundos.
int Minu;            // Minutos.
int Hora;            // Hora.
int Tmp;             // Temporal.
int Tecla;           // Tecla pulsada.
int anTecla;         // Tecla pulsada en la comprobacion anterior
int Tiempo;          // Tiempo transcurrido desde la ultima comprobacion
                     // de teclado.
int CuantoTiempo;    // Cuanto tiempo debe esperar para la
                     // proxima comprobacion.
int Flag;            // Flag para incrementar o decrementar
                     // el valor deseado.
int Set;             // Flag para seleccionar el valor a cambiar.

void main(){
   
   setup_oscillator(OSC_8MHz);
   
   set_tris_a(0);                // Puerto A como salida
   set_tris_b(0b00001111);       // Puerto B<7:4> salida B<3:0> entradas
   
   // Inicio Variables
   anTecla=255;
   Set=0;
   Hora=0;
   Minu=0;
   Segs=0;  
   
   
   do{   
   
      Tecla=0;
      if (input(Tec1))Tecla=1;        // Comprueba que pulsador se activó
      if (input(Tec2))Tecla=2;        // y lo guarda en Tecla
      if (input(Tec3))Tecla=3;
      if (input(Tec4))Tecla=4;        
      
      if (++Tiempo>CuantoTiempo||Tecla!=anTecla) {  // Incrementa el
                              // tiempo transcurrido, Si se pasa de
                              // CuantoTiempo o cambia el estado de
                              // de las teclas con respecto a la
                              // iteracion anterior.
Flag=Nada;                    // Limpia el flag
            
         if(Tecla!=0){                 // Si hay una tecla pulsada
            if(Tecla!=anTecla){        // si la tecla es la primera
                                       // vez que se pulsa.
               CuantoTiempo=100;       // establece el tiempo de
                                       // espera en 100.               
               if(Tecla==1){           // Si se pulsó la tecla 1
                  if(++Set>3) Set=1;   // Avanza el flag para setear
                                       // segs/minu/hora
               }
               if(Tecla==4) Set=0;     // Se pulsó la tecla 4, desactiva
                                       // el modo configuracion
            
            }else{                     // Si no es la primera vez que se
                                       // pulsa la tecla
               CuantoTiempo=30;        // la proxima comprobacion la
                                       // hará en menos tiempo.
            }
            
            if(Tecla==2) Flag=Menos;   // Si la tecla pulsada es la 2
                                       // flag de decremento
            if(Tecla==3) Flag=Mas;     // y si es la 3 flag de incremento
         }
         
         
         if (Set!=0){                  // Si está en modo configuracion
            
            if(Set==1) Tmp=Segs;       // Si se está configurando los
                                       // segundos Segs a temporal
            if(Set==2) Tmp=Minu;       // lo mismo si está configurando
                                       // los minutos
            if(Set==3) Tmp=Hora;       // o la hora
            
            if (Flag==Menos){          // si el flag es de decremento
               if(--Tmp>200)Tmp=59;    // le resta 1 al temporal si es
                                       // menor a 0 pasa a 59
               if(Set==3&&Tmp==59)Tmp=23;// Si está configurando las
                                       // horas el limite es 23
            }
            
            if (Flag==Mas){            // Si el flag es de incremento
               if(++Tmp>59)Tmp=0;      // Incrementa el temporal y si
                                       // se pasa de 59 vuelve a 0
               if(Set==3&&Tmp>23)Tmp=0;// Si configura las horas y
                                       // se pasa de 23 vuelve a 0
            }
            
            if(Set==1) Segs=Tmp;
            if(Set==2) Minu=Tmp;       // Guarda el valor temporal
            if(Set==3) Hora=Tmp;       // en donde corresponda...
         }      
         anTecla=Tecla;                // Almacena la tecla pulsada
                                       // para la próxima 
         Tiempo=0;                     // iteración, Tiempo a 0 para
                                       // volver a contar el tiempo
            
      }
      delay_ms(5);   // Entre iteración e iteración espera 5 ms que
                     // multiplicado por CuantoTiempo, es el tiempo
                     // que tarda en reaccionar a las pulsaciones y
                     // cuanto tarda en avanzar cuando se mantiene
                     // pulsado un botón.
     
   }while(true);
}

Y aquí un video del algoritmo implantado en un pseudo-reloj, en el ejemplo solo incluí la parte de los pulsadores y el display que están controlados con shift register.



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

Reguladores de voltaje, ¿cuál mejor?

Reguladores de voltaje hay muchos, sin lugar a dudas toda persona del mundillo, conoce por lo menos al archifamoso LM7805 , y seguramente el LM317 , pero lo que veremos en esta ocasión serán alternativas válidas y mejoras a dichos integrados.

Para empezar el LM7805 es un regulador de tensión positiva, perteneciente a la familia 78xx, que entrega 5V (ideal para alimentar microcontroladores) a una corriente de 1A. Y el LM317 es un regulador de tensión variable de hasta 1.5A. Para refrescarse un poco la memoria pueden ver estos dos artículos Reguladores de voltaje 7805 y Fuente de alimentación y cargador de baterías

A la hora de elegir un regulador de voltaje, normalmente nos fijamos en dos cosas: Tensión de salida (Volts) y Corriente de salida (Amperes), pero en realidad hay mas cosas que nos deberían preocupar, por ejemplo el encapsulado, tensión máxima de entrada y sobretodo si nuestro diseño final es algún dispositivo a pilas, deberíamos prestar especial atención a la caída de tensión (Dropout voltage) ya que a menor caída, mayor eficiencia al consumir menos.

Empezaremos comparando los reguladores fijos de 5V de salida:

Modelo Fabricante Tensión Máx.Ent. Corriente salida Dropout voltage Otras tensiones (1) Pinout TO-220 (2)
LM1084-5.0 National 30V 5A 1.3V
1.5V
3.3V, 12V, ADJ GOI
LM1085-5.0 National 30V 3A 1.3V
1.5V
3.3V, 12V, ADJ GOI
LD1085xx50 ST 30V 3A 1.3V
1.5V
ADJ GOI
LM1086-5.0 National 30V 1.5A 1.3V
1.5V
3.3V, 12V, ADJ GOI
L4940V5 ST 17V 1.5A 0.5V
0.9V
8.5V IGO
µA7805 Texas Instruments 25V 1.5A 2V 8V, 10V, 12V, 15V, 24V IGO
LM7805
LM340-5.0
National 35V 1A 2V 12V, 15V IGO
LM7805 Fairchild 35V 1A 2V 6V, 8V, 9V, 12V, 15V, 18V, 24V IGO
L7805 ST 35V 1A 2V 6V, 8V, 8.5V, 9V, 12V, 15V, 18V, 24V IGO
LM2940-5.0 National 26V 1A 0.5V
0.8V
8V, 9V, 10V, 12V, 15V IGO
LF50 ST 16V 0.5A 0.4V
0.7V
1.5V, 1,8V, 2.5V, 3.3V, 6V, 8V, 9V, 12V IGO

(1) Los parámetros especificados en esta tabla corresponden a los modelos de 5V, "Otras tensiones" se refiere a las variedades disponibles en encapsulado TO-220 y cada variedad tiene sus especificaciones propias. Consulte los respectivos Datasheets.

(2) IGO: 1.Input (entrada), 2.GND (ground), 3.Output (salida)
GOI: 1.GND, 2.Output, 3.Input

Observando la tabla se puede ver que para reemplazar el integrado de batalla 7805 se puede usar el LM2940-5.0 ya que es un reemplazo directo en cuanto a disposición de pines y entrega de corriente, pero hay que tener en cuenta que su tolerancia máxima a la tensión de entrada es de 26V contra los 35V del otro, aunque para pruebas con microcontroladores en raras ocasiones se superan los 12V en la entrada del regulador. Este reemplazo trae como ventaja la menor caída de tensión reduciéndola a un cuarto (500mV) en condiciones normales y 800mV en las peores condiciones contra los 2V del 7805, esto es muy importante si la tensión de entrada proviene de una batería ya que a menor caída de tensión, mayor rendimiento, porque no olvidemos que la caída de tensión no es ni mas ni menos que un desperdicio de energía.

También se debe tener en cuenta al L4940V5 cuya caída de tensión es la misma que el anterior en condiciones normales (500mV) y de 900mV en el peor de los casos reduciendo la entrada máxima a 17V pero con el agregado de ser capaz de entregar hasta 1.5A de corriente contra 1A que entrega la familia 78xx, especial para cuando haya muchos integrados que alimentar en el circuito.

Y si 1.5A no nos resulta suficiente tenemos dos modelos más, el LM1085-5.0 y LM1084-5.0 capaces de entregar hasta 3 y 5A respectivamente, pero con una caída de tensión entre 1.3 y 1.5V.

En conclusión el mejor regulador para reemplazar a nuestro viejo y querido LM7805 es el L4940V5, con la ventaja de entregar un 50% mas de corriente y tener una caída de tensión 75% menor.


Tal vez le interese: