LCD de 7 segmentos y ahorro de energía

¿Has usado exhibidores de 7 segmentos de cristal líquido? ¿Sabías que trabajan con muy poca energía? El ejemplo que te presento consume menos de 1 mA, incluyendo la alimentación para 2 dígitos (14 segmentos) y un PIC16F1938. Como punto de comparación: recuerda que las especificaciones de los leds suelen obtenerse para corrientes de prueba de 10 ó 20 mA. Si consideras que ahorrar energía a escala de mA es irrelevante, piensa en equipos que usan baterías, ¿cuántas tendrías que comprar en un año?, y ¿cuánta basura generarías? En caso de baterías recargables: ¿con qué frecuencia tendrías que recargarlas? y ¿cuántas recargas sopartarían?

Antes de iniciar:

Entre los productos que usan exhibidores de cristal líquido de 7 segmentos, habrás visto dispensadoras o bombas de gasolina, multímetros, teléfonos fijos, medidores de presión arterial o de nivel de glucosa, etc.

Pantalla de multímetro.
Figura 1. Pantalla de multímetro. Además de los segmentos que se usan para conformar los dígitos, se aprecian el punto decimal y el texto mA.
Pantalla de un teléfono fijo con todos los elementos encendidos.
Figura 2. Pantalla de un teléfono fijo con todos los elementos encendidos. Observa que en este caso hay los dígitos típicos de 7 segmentos, textos, figuras y una sección para formar caracteres a partir de 25 pixeles cada uno.
Edición de la figura 2 que muestra en el renglón central los caracteres que usaremos en este ejercicio.
Figura 3. Edición de la figura 2 que muestra en el renglón central los caracteres que usaremos en este ejercicio. Observa que activaremos seis segmentos para formar el 6 y el 9 (otra versión de estos dígitos sólo activa cinco segmentos). Observa también que definiremos una E para tener una indicación de error.

Debido a que en las tiendas de electrónica al menudeo de la Ciudad de México no encontré LCD de 7 segmentos, usé un viejo EDS812. Si en tu localidad los venden o decides comprar por Internet, podrías usar alguno de estos: LCD-S2X1C50TR, FE0203W-DU, LCD-A2X1C50TR, VI302-DP-FC-S-L o LCD-H301C31KR-1. Me refiero a que éstos son LCD de 7 segmentos en producción, NO a que sean reemplazos directos. En la figura 4 te muestro una sección de la hoja de datos del EDS812; mientras que en la figura 5, está una sección de la especificación del LCD-H301C31KR-1.

Fragmento de la especificación del EDS812.
Figura 4. Fragmento de la especificación del EDS812. Se muestran las dimensiones del exhibidor y el acomodo de las terminales. En el ejemplo sólo usaremos los dos dígitos de la izquierda.
Fragmento de la especificación del LCD-H301C31KR-1.
Figura 5. Fragmento de la especificación del LCD-H301C31KR-1. Se muestran las dimensiones del exhibidor, el acomodo de las terminales y otros datos.

El diagrama del circuito de prueba se muestra en la figura 6, mientras que Lcd7seg.c se lista a continuación:

#include <xc.h>
// Oscilador interno a 500 kHz.
#pragma config FOSC=INTOSC 
// Evita que el watchdog reinicie el uC.
#pragma config WDTE=OFF    
// Inicia hasta que el oscilador esté estable.
#pragma config PWRTE=ON    

void main(void)
{
 char unidades=0, decenas=0;
 
 // Configura el temporizador 0 para obtener
 // intervalos de aproximadamente 0.5 s.
 OPTION_REGbits.TMR0CS=0;
 OPTION_REGbits.PSA=0;
 // Asignación de terminales compartidas al manejador
 // de dispositivos de cristal líquido.
 LCDSE0=0xBF;
 LCDSE1=0xF7;
 // Todos los segmentos apagados.
 LCDDATA0=0;
 LCDDATA1=0;
 // Modo estático, factor de escala para f de 1:5.
 LCDPS=0x04;
 // Usar la tensión de referencia interna.
 LCDREF=0x80;
 // Máximo contraste.
 LCDCST=0;
 // Modos A y B a corriente mínima.
 LCDRL=0x50;
 // Activa el módulo para trabajar en modo estático
 // y usar el oscilador interno de 31 kHz.
 LCDCON=0x88;
 while(1)
 {
  // La condición es verdadera cada 488.28 ms.
  if (INTCONbits.TMR0IF==1)
  {
   INTCONbits.TMR0IF=0;
   switch (unidades)
   {
    case 0: LCDDATA0=LCDDATA0|0b10110000;
            LCDDATA1=(LCDDATA1|0b10110000)&0b10111111;
            break;
    case 1: LCDDATA0=(LCDDATA0|0b10000000)&0b11001111;
            LCDDATA1=(LCDDATA1|0b10000000)&0b10001111;
            break;
    case 2: LCDDATA0=LCDDATA0|0b10110000;
            LCDDATA1=(LCDDATA1|0b01010000)&0b01011111;
            break;
    case 3: LCDDATA0=(LCDDATA0|0b10010000)&0b11011111;
            LCDDATA1=(LCDDATA1|0b11010000)&0b11011111;
            break;
    case 4: LCDDATA0=(LCDDATA0|0b10000000)&0b11001111;
            LCDDATA1=(LCDDATA1|0b11100000)&0b11101111;
            break;
    case 5: LCDDATA0=(LCDDATA0|0b00010000)&0b01011111;
            LCDDATA1=LCDDATA1|0b11110000;
            break;
    case 6: LCDDATA0=(LCDDATA0|0b00110000)&0b01111111;
            LCDDATA1=LCDDATA1|0b11111000;
            break;
    case 7: LCDDATA0=(LCDDATA0|0b10000000)&0b11001111;
            LCDDATA1=(LCDDATA1|0b10010000)&0b10011111;
            break;
    case 8: LCDDATA0=LCDDATA0|0b10110000;
            LCDDATA1=LCDDATA1|0b11110000;
            break;
    case 9: LCDDATA0=(LCDDATA0|0b10010000)&0b11011111;
            LCDDATA1=LCDDATA1|0b11110000;
            break;
    default:LCDDATA0=(LCDDATA0|0b00110000)&0b01111111;
            LCDDATA1=(LCDDATA1|0b01110000)&0b01111111;
   }
   switch (decenas)
   {
    case 0: LCDDATA0=LCDDATA0|0b00001111;
            LCDDATA1=(LCDDATA1|0b00000011)&0b11111011;
            break;
    case 1: LCDDATA0=(LCDDATA0|0b00000101)&0b11110101;
            LCDDATA1=LCDDATA1&0b11111000;
            break;
    case 2: LCDDATA0=(LCDDATA0|0b00001011)&0b11111011;
            LCDDATA1=(LCDDATA1|0b00000101)&0b11111101;
            break;
    case 3: LCDDATA0=(LCDDATA0|0b00000111)&0b11110111;
            LCDDATA1=(LCDDATA1|0b00000101)&0b11111101;
            break;
    case 4: LCDDATA0=(LCDDATA0|0b00000101)&0b11111101;
            LCDDATA1=(LCDDATA1|0b00000110)&0b11111110;
            break;
    case 5: LCDDATA0=(LCDDATA0|0b00000110)&0b11110110;
            LCDDATA1=LCDDATA1|0b00000111;
            break;
    case 6: LCDDATA0=(LCDDATA0|0b00001110)&0b11111110;
            LCDDATA1=LCDDATA1|0b00000111;
            break;
    case 7: LCDDATA0=(LCDDATA0|0b00000101)&0b11110101;
            LCDDATA1=(LCDDATA1|0b00000001)&0b11111001;
            break;
    case 8: LCDDATA0=LCDDATA0|0b00001111;
            LCDDATA1=LCDDATA1|0b00000111;
            break;
    case 9: LCDDATA0=(LCDDATA0|0b00000111)&0b11110111;
            LCDDATA1=LCDDATA1|0b00000111;
            break;
    default:LCDDATA0=(LCDDATA0|0b00001010)&0b11111010;
            LCDDATA1=LCDDATA1|0b00000111;
   }
   unidades++;
   if (unidades==10)
   {
    unidades=0;
    if (decenas<9) decenas++; else decenas=0;
   }
  }
 }
}

Diagrama del circuito de prueba.

Figura 6. Diagrama del circuito de prueba. Observa que no hay cristales ni condensadores,  usaremos el oscilador interno. Observa también que conecté “por debajo de los circuitos” las terminales COM0 y COM.

En el documento LCD Fundamentals and the LCD Driver Module of 8-bit PIC Microcontrollers, hay una explicación muy detallada de la estructura y funcionamiento de los exhibidores de cristal líquido. Sin embargo, los puntos esenciales para comprender el programa son:

  • Cada segmento se activa aplicando una diferencia de potencial entre dos terminales.
  • Varios segmentos comparten una terminal de polarización.
  • Aplicar corriente directa daña el dispositivo, por lo que se usa corriente alterna en forma de oscilaciones cuadradas.
  • Cuando la diferencia de potencial entre las dos terminales que controlan un segmento es cero o muy pequeña, éste se apaga. Una diferencia de potencial de magnitud apropiada enciende el segmento, figura 7.
  • Se suele emplear frecuencias de entre 50 y 150 Hz para las señales cuadradas. A mayor frecuencia mayor consumo de energía; frecuencias muy bajas pueden causar parpadeo; y frecuencias muy altas pueden hacer que los segmentos encendidos no se vean nítidos.
  • Cada elemento constituye una carga capacitiva para el circuito que lo controla.
  • Cuando los exhibidores tienen sólo una terminal común se manejan en un modo denominado estático.
  • El manejador para exhibidores de cristal líquido que se incluye como periférico del PIC16F1938 cuenta con todos los componentes electrónicos necesarios para controlar al EDS812.
Conexión y polarización de los elementos en un dígito del exhibidor.
Figura 7. Conexión y polarización de los elementos en un dígito del exhibidor. Observa que: 1) Cada elemento tiene dos terminales. 2) De cada elemento, una terminal está conectada a COM0. 3) La terminal restante de cada elemento está etiquetada SEG0, SEG1 … SEG7. 4) En cada terminal se aplica una oscilación cuadrada. 5) Se ejemplifica usando el número 2. 6) La diferencia de potencial en los segmentos activos, como SEG0, SEG2 o SEG3, es grande. 7) La diferencia de potencial en los segmentos inactivos, como SEG1 y SEG2, es cero. Esta figura pertenece a Microchip y está en la página 23 de LCD Fundamentals and the LCD Driver Module of 8-bit PIC Microcontrollers.

Como la mayoría de los códigos que se ejecutan en un microcontrolador, Lcd7seg.c tiene una etapa de configuración y una sección que se repite indefinidamente.

La etapa de configuración comienza en las directivas pragma, donde ordené el uso del oscilador interno del uC. Después, ya dentro de la función main, activé el temporizador 0 y establecí un factor de escala que permite obtener intervalos cercanos a medio segundo, estos son los intervalos para incrementar el contador. Respecto a los registros de uso especial que controlan al manejador de LCD:

  • LCDSE0 y LCDSE1 son los registros que indican si una pata del uC será asignada al manejo del LCD o a otro propósito. El PIC16F1938 tiene 16 patas que pueden cumplir con esta tarea, seleccioné cuáles usar procurando una “conexión fácil” entre el uC y el EDS812; y también, dejando disponibles las terminales para una eventual comunicación I2C.
  • LCDDATA0 y LCDDATA sirven para indicar que segmentos deben encender. Un 1 en el bit 0 de LCDDATA0 prenderá el elemento del LCD conectado a la terminal SEG0 del microcontrolador, un 0 en el bit 7 de LCDDATA0 apagará el elemento del LCD conectado a la terminal SEG7, un 1 en el bit 0 de LCDDATA1 prenderá el elemento del LCD conectado a la terminal SEG8 – tabla 1.
  • LCDPS. A través de este registro configuré el manejador para aplicar la polarización correspondiente al modo estático (BIASMD = 0), y un factor de 1 a 5 al obtener la frecuencia para la oscilación cuadrada, figura 8.
  • En LCDREF habilité el uso de la tensión de referencia interna para obtener los voltajes de polarización.
  • En LCDCST ordené el máximo contraste (esto se logra aplicando la mayor diferencia de potencial posible entre los segmentos y el común).
  • LCDRL sirve para establecer cuánta corriente se puede entregar al LCD. Recuerda que cada elemento del exhibidor se puede considerar como un condensador; y que a mayor tamaño de los segmentos, mayor será la capacitancia que presentan al manejador. Dicha corriente se puede establecer hasta en dos etapas llamadas modo A y modo B; la intensión sería manejar dos corrientes diferentes, una cercana a los momentos de transición de la onda cuadrada y otra para cuando los elementos ya están estables. Dado que el EDS812 es pequeño, bastó con mantener la corriente mínima todo el tiempo. LRLAT<2:0> = 000 mantiene permanentemente el uso del modo B, y LRLBP<1:0> = 01 establece el uso de poca potencia para el modo B. Aunque finalmente no usé el modo A, lo dejé programado para baja potencia.
  • LCDCON me permitió habilitar el módulo manejador de LCD, establecer como fuente de reloj el oscilador interno de baja frecuencia e indicar el uso de modo estático.
Relación de los bits y registros que indican si un elemento del LCD debe prender o apagar.
Tabla 1. Relación de los bits y registros que indican si un elemento del LCD debe prender o apagar.
Sistema para establecer la frecuencia de las señales de manejo del LCD.
Figura 8. Sistema para establecer la frecuencia de las señales de manejo del LCD. Utilicé el oscilador interno de 31 kHz, para un LCD de modo estático, con un factor de escala en el pre-escalador de 1 a 5. Por lo anterior, la frecuencia de las señales de polarización que usé es: 31000 / 4 / 5 / 32 = 48.4 Hz. Edité la figura 27-2 que está en la página 332 de la hoja de datos del PIC16F1938 para obtener esta imagen.

Por otra lado, en la parte del código que se repite indefinidamente: conté las veces que se cumple el intervalo programado en TMR0 y envié dicha cuenta al LCD. Observa que conté usando una variable para las unidades y otra para las decenas; evidentemente, la cuenta se repite al rebasar los 99 eventos.
Almacené en dos estructuras switch las operaciones para obtener los valores de LCDDATA0 y LCDDATA1. Usé mascaras porque cada uno de estos registros controla parte de la unidad y una parte de la decena (resultó conveniente hacerlo así para alambrar el circuito con facilidad). Las operaciones AND son para apagar segmentos, mientras que las OR son para encenderlos.

En este punto ya habrás notado que el módulo manejador puede generar más modos de polarización y formas de onda; éstos te serán útiles cuando controles LCD con varias terminales comunes, es decir, con muchos segmentos a controlar y que, muy probablemente, tendrás que mandar a hacer para producción industrial (la mayoría de los LCD de propósito general incluyen su circuito manejador).

Finalmente te comento que en los apéndices del documento LCD Fundamentals and the LCD Driver Module of 8-bit PIC Microcontrollers encontrarás tablas que resumen las capacidades del manejador de LCD que contienen varios procesadores de Microchip.

Hasta la próxima.

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos necesarios están marcados *