Display de 7 segmentos y 4 dígitos

Objetivos

 

  • Nuestro primer display numérico de 4 digitos.
  • Multiplexando los digitos.
  • Aprendiendo a programar: Dividiendo el problema en funciones.
  • Vuelta a las operaciones con enteros
  •  

    Material requerido.

     

    Kit Arduino Uno  Kit inicio UNO
    Kit Arduino MEGA Kit Inicio Mega

     

    Los displays LED de 4 dígitos

     

    En la sesión anterior, la cosa ha ido bastante bien con un dígito, pero ahora que le hemos cogido el puntillo, queremos poder usar 4 dígitos para, digamos dar la hora.

    Y si queremos mostrar 4 dígitos… ¿Vamos a multiplicar 8 cables x 4 dígitos más tensión y GND, en total 34 pines?

    Para empezar, Arduino UNO no tiene tantos pines (Si, el Mega sí que los tiene, pero recordad, elegancia, mucha elegancia), entonces si vosotros fabricarais estos displays ¿Cómo evitaríais usar 34 pines? Pensadlo, ¿Qué solución daríais vosotros al problema?

    Pues una fácil ( y barata que es lo que les gusta a los que fabrican) es la de mantener 8 pines para iluminar los 7 segmentos más el punto, y poner otros 4 pines para indicar a cuál de los dígitos  corresponde la información que ponéis en a, b, c, d, e, f, g, h.

    La cosa va por ahí, pero para eso habría que poner unas memorias y latch como en el shift register y alguien dijo: No, no, más barato aun. Y un ingeniero creativo dijo: pues si hacemos que esos 4 pines para indicar la posición vayan a tierra pasando por un transistor cada uno podemos hacer que se ilumine solo uno cada vez. Y si hacemos el ciclo lo bastante rápido, pasando de uno a otro, ni se enteran. Ni que decir tiene que el ingeniero creativo pasó a jefe de proyectos.

    Y eso es todo. Simplemente seguimos utilizando 8 pines para iluminar los segmentos, pero solo hay uno activo en un momento concreto. Y haciendo un ciclo rápido, iluminamos uno cada vez rápidamente y pasamos al siguiente y luego al siguiente y problema resuelto.

    Así que lo primero que vamos a hacer es conectar los 8 segmentos del display a los pines del 2 al 10 de nuestro Arduino, para probarlos. Conectad GND al cátodo del primer digito con una resistencia y comprobad las conexiones.

     

    Conexiones iniciales

     

    De nuevo, tengo que insistiros en que leáis la hoja de características de vuestro display y no os fieis del diagrama de abajo, porque el vuestro puede ser distinto. Mirad el código de vuestro display y bajaros la data sheet de Internet. Leedla, aunque solo sea para comprobar si vuestros pines coinciden con el diagrama que os pongo debajo (Que es del manual de Parallax).

    Este diagrama es para el display que tengo entre manos (5461AS) y el vuestro no tiene por qué usar los mismos pines ( Aunque la probabilidad de que sea así es alta, y en caso negativo tampoco es grave porque basta con que conectéis los pines correctos al mismo orden de vuestro Arduino).

    Conexion a ArduinoLo que yo he hecho (porque mi display solo tiene 12 pines), es conectar los 8 segmentos y enviar el cátodo a masa mediante una resistencia, para probar el primer digito y ya me preocupare del resto luego. Es imperativo que os aseguréis de conectar correctamente los segmentos antes que nada.

    Podeís correr un programa simple como este, para comprobar la conexión de los segmentos, que los va encendiendo y apagando en secuencia: Prog_31_1

    void setup()
       { 
           for ( int i=2 ; i<10 ; i++)
                 pinMode( i, OUTPUT);
       }
    
    void loop()
       { 
           for (int j=2; j<10 ; j++)  
             {    digitalWrite( j, HIGH);
                  delay(300);
                  digitalWrite( j, LOW) ;
                  delay(300);
             }
        }

    Si todos se encienden, ya podemos pasar a la siguiente fase.

     

    Diagrama de conexión

     

    Ahora que estamos seguros de que nuestros 7 segmentos están enchufados donde corresponde viene la cuestión de  utilizar 4 pines de Arduino para elegir cual se ilumina.

    Nuestra primera idea sería conectar esas salidas del display, 12, 9, 8 y 6  a 4 pines de nuestro Arduino. Si mantenemos esos pines en HIGH excepto el que queremos iluminar, que ponemos en LOW, parece que cerraría el circuito a GND y ya está.

    Pero no. El consumo típico de cada segmento, (como de cada LED) es de entre 15 y 20mA. Como son 8 segmentos cuando escribamos el 8 más el punto, el consumo será de 8 x 15 = 120 mA y pudiendo llegar a 160mA. Muy por encima de los 40 mA que un pin de nuestro Arduino puede suministrar o drenar, así que mejor que pensemos otra cosa antes de que huela a quemado.

    Y la solución, queridos amigos, es, naturalmente, utilizar un transistor para permitir cerrar el circuito de cada dígito.

    Diagrama ed conexion

    El 2N2222 es ya un viejo conocido (No os olvidéis de la resistencia de la base, es imprescindible), poniendo a LOW los pines 9, 10, 11, y 12 los transistores están al corte, y ningún digito puede iluminarse. Si ponemos tensión en el pin 12, su transistor se satura y permite la salida a Ground del primer digito que encenderá los segmentos que le indiquen los pines 2 al 8.

    Ahora ponemos en LOW el pin 12 y en HIGH el 11. Los valores de los segmentos iluminaran ahora el segundo digito. Y luego el terceo y el cuarto. El único trucos es hacerlo rápido, y eso se le da muy bien a nuestro Duino.

     

    El programa de control

     

    Vamos a reaprovechar la función Display () que escribimos en la sesión anterior para dibujar los dígitos en el display, que si recordáis se apoyaba en un array para saber que segmentos encender: Prog_31_2

    byte Digit[10][8] =
       { 
         { 1,1,1,1,1,1,0,0 },    // 0
         { 0,1,1,0,0,0,0,0 },    // 1
         { 1,1,0,1,1,0,1,0 },    // 2
         { 1,1,1,1,0,0,1,0 },    // 3
         { 0,0,1,0,0,1,1,0 },    // 4
         { 1,0,1,1,0,1,1,0 },    // 5
         { 1,0,1,1,1,1,1,0 },    // 6
         { 1,1,1,0,0,0,0,0 },    // 7
         { 1,1,1,1,1,1,1,0 },    // 8
         { 1,1,1,0,0,1,1,0 }     // 9
       };
    
    void setup()
        {           for (int i= 2; i<13; i++)
                         pinMode(i, OUTPUT);
        }

    Pero vamos a extender Display para que escriba un digito en la posición que queramos, donde la posición 0 son las unidades, 1 las decenas, 2 las centenas y 3 los miles.

    void Display(int pos, int N)
       {  
           digitalWrite(9 ,LOW);        // Apaga todos los digitos
           digitalWrite(10,LOW);
           digitalWrite(11,LOW);
           digitalWrite(12,LOW);
     
          for (int i= 0 ; i<8 ; i++)    // Esto no cambia de la session anterior
                digitalWrite(i+2 , Digit[N][i]) ;
    
          digitalWrite(pos + 9, HIGH);      // Enciende el digito pos
      }

    Como veis, es la misma función en la parte de iluminar segmentos, pero hemos hecho que al entrar los apague todos, luego levanta los pines que queremos y solo luego activamos el transistor de salida de la posición que queremos, lo que hace que ilumine la posición pedida en pos.

    Calculamos el pin de salida como pos + 9, porque a las posiciones 0, 1, 2, 3 les corresponden los pines 9, 10, 11, 12, también aquí, la elección del orden de los pines juega a nuestro favor.

    Una vez que tenemos resuelto dibujar el número buscado en la posición elegida tenemos que escribir otra función que descomponga un número dado en unidades, decenas, centenas y miles.

    En un alarde de creatividad he bautizado a esta función como CalculaDigitos()

    void CalculaDigitos( int Num)
       {
          int Digit0 = Num %10 ;
          int Digit1 = (Num % 100) / 10 ;
          int Digit2 = (Num % 1000) / 100 ;
          int Digit3 = Num  / 1000)  ;
    
          Display(3 , Digit3);
          Display(2 , Digit2);
          Display(1 , Digit1);
          Display(0 , Digit0);
       }

    Por si acaso alguien faltó el día que hablamos de las operaciones con enteros haremos un caso concreto. Supongamos un número como 2.386. ¿Cómo obtenemos sus dígitos separados?

    2386 % 10 = 6          Porque el %  nos devuelve el resto de dividir por 10, o sea 6.
    2386 % 100 = 86        Ahora hacemos la división entera por 10 o sea 8,los decimales se tiran
    2386 % 1000 = 386      386 / 100 = 3
    2386  / 1000 = 2       Directamente, para eso se inventó la división entera.

    Y a continuación le pedimos directamente que nos  saque los dígitos al display.

    Por ultimo para la función principal, empecemos pidiéndole que cuente décimas de segundo (La cuenta atrás la hacemos, luego) 

    void loop()
       {
           CalculaDigitos( millis() / 100);
       }

    ¿Creías que iba a ser difícil? Pues lo siento. Es así de sencillo. Ya conocíamos millis(), el reloj interno de nuestro Duino en milisegundos. Pues haciendo la división entera (otra vez) nos da un contador de hasta 999 segundos.

    ¿Y si queremos hacer una cuenta atrás?  Venga pensad un momento antes de mirar la solución.

    • Muy fácil también. Como nuestro contador va hasta 9999 basta con restarle a esto el cálculo de arriba, o simplemente poner en lugar del 9999 la cifra desde la que deseamos descontar.

     

    Más interesante, y práctico supone convertir esa cifra a minutos y segundos sexagesimales para hacer un reloj.

    void loop()
       {
           int n = millis() / 1000 ;       // Lo pasamos a segundos
           int segundos = n % 60  ;
           int minutos =  n / 60  ;
    
           int k = minutos * 100 + segundos ;
           CalculaDigitos(k) ;
       }

    De nuevo a partir del reloj interno de nuestro Duino, millis(),(que cuenta en milisegundos por lo que lo dividimos por mil para pasarlo a segundos), calculamos los segundos y minutos, para luego llamar a CalculaDigitos() que espera un numero centesimal y por eso multiplicamos por 100 los minutos para que cuadre el display.

     

    Os dejo como ejercicio que hagáis un reloj que efectúa una cuenta atrás desde un número dado.

  • El circuito que hemos visto, es el correcto para garantizar que el display tenga una vida larga y pacífica, de hecho es el que recomienda el fabricante.En internet encontrareis bastantes ejemplos en los que, en vez de transistores usan resistencias de un cierto valor para limitar la intensidad en los controles de salida. He preferido no hacerlo así, a sabiendas de que el montaje que os he propuesto es bastante más pesado.
  •  

    Algunos comentarios finales

     

    Cablear este montaje es un asco y si fuera un circuito comercial seria caro (Porque aunque los componentes sean baratos, montarlos cuesta pasta, más que los componentes en este caso).

    Así que en la práctica os desaconsejo que uséis estos displays de por si, en vuestros proyectos. Hay demasiados cables y siempre hay alguno dando guerra. Lo normal es usar un display tipo I2C o similar que lleven un circuito de control interno, o bien usar un integrado de control BCD como el Max7219 (Volveremos a hablar del asunto en un futuro próximo).

    Y ¿Por qué a pesar de todo hemos hecho esta práctica? Pues porque es importante que entendáis cómo funcionan las cosas y el concepto de multiplexado es uno de los claves básicas para entender la electrónica digital,

    Por cierto, ¿Os habéis dado cuenta de que, al hacer un multiplexado de los dígitos basado en que nuestro Duino recorra el ciclo completo en menos tiempo de lo que nuestro ojo percibe, cualquier uso de un delay() dará al traste con el invento?. Meted uno por donde queráis y ved lo que ocurre.

    Aunque hasta ahora hemos usado y abusado de los delays, son algo poco práctico y potencialmente muy peligroso a medida que los proyectos que presentemos se vayan complicando, y este es uno de esos casos. Ya hablaremos de las soluciones.

     

    Resumen de la sesión

     

  • Hemos presentado los displays LED de 7 segmentos y 4 digitos.
  • Lo suficiente como para comprender, que como ejercicio está bien, pero veremos otras maneras de incluir estos displays, menos trabajosas.
  • Hemos mejorado nuestra función Display(), para que podamos usarla en displays de digitos múltiples(Seria muy fácil extenderla a 8 digitos).
  • Hemos resuelto una serie de problemas lógicos, en pasos más pequeños de abordar para mejorar nuestra competencia en la búsqueda de algoritmos útiles.
  • Hemos visto que podemos abordar problemas complejos mediante pequeños pasos y funciones, que al combinarse resuelven problemas que inicialmente parecen inabordables.
  •  

    Deja una respuesta