Manejar un display 7 segmentos

Un display 7 segmentos es nada mas que 7 LED encapsulados formando un 8, de modo que es posible lograr mostrar los dígitos 0~9. También se encuentran encapsulados de 2, 3 y 4 dígitos. Algunos llevan un octavo LED para representar el punto decimal. De modo que para manejar un dígito se requieren los 7 elementos que normalmente son nombrados con letras a, b, c, d, e, f y g, ademas un pin común a todos los LED que puede ser ánodo común o cátodo común. Si tiene punto decimal este normalmente se nombra como DP.

Display 7 segmentos

1. Circuito propuesto

Ya que el circuito electrónico es mas complejo y hay bastantes opciones de equivocarse, les recomiendo avanzar paso a paso y no pasar al siguiente paso si no lograron el anterior.

Manejar un display 7 segmentos

2. Componentes

Los componentes son muy simples.

  1. Arduino UNO
  2. Display 7 segmentos de cátodo común
  3. 7 resistencia 330 ohms
  4. 7448 (solución 3)
  5. 74595 (solución final)

Como practica podrías intentar hacer funcionar un display de ánodo común.

3. Código Arduino

Con este código pretendemos comprobar que las conexiones electrónicas son las correctas. Lo que deberías lograr ver aquí es que cada uno de los 7 segmentos se van prendiendo en secuencia y en orden (a, b, c...), al terminar el ciclo hay una pausa de 2 seg antes de volverla a repetir.

void setup(){
   pinMode(7, OUTPUT);  //g
   pinMode(8, OUTPUT);  //f
   pinMode(9, OUTPUT);  //e
   pinMode(10, OUTPUT); //d
   pinMode(11, OUTPUT); //c
   pinMode(12, OUTPUT); //b
   pinMode(13, OUTPUT); //a
}

void loop(){
   for (byte i=13; i>=7; i--){
      digitalWrite(i, HIGH);
      delay(500);
      digitalWrite(i, LOW);
   }
   delay(2000);
}

Si alguno de los segmentos no prende o el orden de la secuencia no es el correcto debes revisar el cableado correspondiente.

4. Solución 1

Ahora que tenemos todos los segmentos funcionando adecuadamente daremos un paso adelanto para mostrar números entre 0 y 9. En esta primera oportunidad en secuencia con un intervalo de 0.5 segundo y al final u na pausa de 1 segundo.

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

void loop(){
   for (byte n=0; n<=9; n++){
      for (byte i=7; i<=13; i++){
	     digitalWrite(i, dig[n][13-i]);
      }
      delay(500);
   }
   delay(1000);
}

En esta oportunidad hemos usado 7 pines digitales para manejar el display.

5. Solución 2

Simplifiquemos nuestro código y elevemos los requerimientos. Usaremos la función random() para generar el numero aleatorio. Por lo que ahora los números mostrados sean aleatorios. Ademas se hizo un gran ahorro en la matriz guardando los segmentos como un numero binario.

const byte dig[10]={
   B1111110,   //0
   B0110000,   //1
   B1101101,   //2
   B1111001,   //3
   B0110011,   //4
   B1011011,   //5
   B1011111,   //6
   B1110000,   //7
   B1111111,   //8
   B1110011    //9
};
void setup() {
   for (byte i=7; i<=13; i++){
      pinMode(i, OUTPUT);
   }
	randomSeed(analogRead(0));
}

void loop() {
   byte n = random(10);
   for (byte i=7; i<=13; i++){
      digitalWrite(i, bitRead(dig[n],i-7));
   }
   delay(500);
}

6. Solución 3

En este ejemplo intentaremos manejar 5 dígitos por este método, por lo que tendríamos que usar 5 pines digitales adicionales (Ej: 2~6) para a través de un transistor (NPN para cátodo común) prender un dígito a la vez mientras al mismo tiempo enviamos el numero a mostrar por el bus de datos (pin 7~13). Este proceso debería ser muy rápido para engañar al ojo humano y que crea que los 5 dígitos están prendidos a la vez.

Manejar 5 display 7 segmentos
const byte dig[10]={
   B1111110,   //0
   B0110000,   //1
   B1101101,   //2
   B1111001,   //3
   B0110011,   //4
   B1011011,   //5
   B1011111,   //6
   B1110000,   //7
   B1111111,   //8
   B1110011    //9
};
void setup() {
   for (byte i=2; i<=6; i++){
      pinMode(i, OUTPUT);
      digitalWrite(i, HIGH);
   }
   for (byte j=7; j<=13; j++){
      pinMode(j, OUTPUT);
   }
}

void loop() {
   for (unsigned int i=10000; i<99999; i++){
      for (byte j=0; j<50; j++){
         //1ro
         ver(i%10);
         digitalWrite(2, LOW);
         delay(1);
         digitalWrite(2, HIGH);
         //2do
         ver((i/10)%10);
         digitalWrite(3, LOW);
         delay(1);
         digitalWrite(3, HIGH);
         //3ro
         ver((i/100)%10);
         digitalWrite(4, LOW);
         delay(1);
         digitalWrite(4, HIGH);
         //4ro
         ver((i/1000)%10);
         digitalWrite(5, LOW);
         delay(1);
         digitalWrite(5, HIGH);
         //5to
         ver(i/10000);
         digitalWrite(6, LOW);
         delay(1);
         digitalWrite(6, HIGH);
      }
   }
}

void ver(byte n){
   for (byte i=7; i<=13; i++){
      digitalWrite(i, bitRead(dig[n],i-7));
   }
}

Para que NO notes el parpadeo la frecuencia de refresco debe ser superior a 25 Hz, en otras palabras todo el proceso debe hacerse en menos de 40 ms. En este ejemplo gastamos 1 ms por dígito osea 5 ms, por eso repetimos este proceso varias veces para que el contador avance a una velocidad razonable 50 x 5 = 250 ms.

Es este ejemplo ya estamos usando 12 pines (5 dígitos + 7 segmentos), por lo que quizás ya estamos al limite a nos ser que echemos mano de los pines analógicos (14~19) y no requeririamos hacer nada mas. En este caso uso display de bajo consumo (1 mA x segmento) por lo que como máximo tengo 7 mA en los pines 2~6. Otro tipo de display requiere transitores.

7. Solución 4

Otra opción interesante cuando tienes que manejar display 7 segmentos es usar un IC decodificador de BCD a 7 segmentos como el 7448 o 4011. Su principal virtud es que te ahorra pines de Arduino ya que no tendrás que usar 7 pines sino solamente 4. Ademas mejoramos nuestro código usando la función bitRead()

void setup() {
   for (byte i=10; i<=13; i++){
      pinMode(i, OUTPUT);
   }
}

void loop() {
   byte n = random(10);
   for (byte i=10; i<=13; i++){
      digitalWrite(i, bitRead(n,13-i));
   }
   delay(500);
}

En esta oportunidad hemos usado 4 pines digitales para manejar el display.

8. Solución 4

Pero gracias a la comunidad tenemos la libreria SevSeg.h que simplifica tremendamente las cosas incluso manejaremos 4 digitos al mismo tiempo.

Valores para hardwareConfig
hardwareConfigDescripción
COMMON_CATHODECatodo comun sin driver
COMMON_ANODEAnodo comun sin driver
N_TRANSISTORSCatodo comun con NPN
P_TRANSISTORSAnodo comun con PNP
NP_COMMMON_CATHODECatodo comun con doble transitor
NP_COMMMON_ANODEAnodo comun con doble transitor
#include <SevSeg.h>
SevSeg sevseg;       //Instanciamos el object

void setup() {
   byte hardwareConfig = N_TRANSISTORS;  //Indica que es cátodo común con NPN
   byte numDigits = 4;
   byte digitPins[] = {2,3,4,5};
   byte segmentPins[] = {13,12,11,10,9,8,7,6};
   bool resistorsOnSegments = true;     //true indica que resistencia esta en el pin de segmento
   bool updateWithDelays = false;       //Recomendado
   bool leadingZeros = true;            //true muestra ceros a izquierda
  
   sevseg.begin(hardwareConfig, numDigits, digitPins, segmentPins, resistorsOnSegments, updateWithDelays, leadingZeros);
   sevseg.setBrightness(90);            //Establece brillo a 90%
}

void loop() {
   static unsigned long hora = millis();
   static int deciSeconds = 0;
   
   if (millis() >= hora) {
      deciSeconds++;
      hora += 100; 
      if (deciSeconds == 10000) {
         deciSeconds=0;
      }
      sevseg.setNumber(deciSeconds, 1);
   } 
   sevseg.refreshDisplay();
}

9. Solución final

Si requerirás 8 display 7 segmentos con la ayuda de IC externos una buena idea es enviar toda la información de manera serie (bus I2C). Esto se puede hacer por ejemplo con un Shift Register como el 74164 o 74595. Su principal virtud es que te ahorra pines de Arduino ya que no tendrás que usar 7 pines sino solamente 3 (Ck, data, MR). Ademas mejoramos nuestro código usando la librería ShiftDisplay.h

MétodoDescripciónPosibles
set()Guardar próximo valor a mostrardisplay.set(valor)
display.set(valor, decimales)
display.set(valor, decimales, alineamiento)
show()Mostrar valor almacenadodisplay.show()
display.show(milisegundos)
display.show(valor, milisegundos)
display.show(valor, milisegundos, alineamiento)
COMMON_CATHODE
Cátodo común
COMMON_ANODE
Anodo común
ALIGN_LEFT
Alineado a la izquierda
ALIGN_CENTER
Centrado
ALIGN_RIGHT
Alineado a la derecha

Fuente: ShiftDisplay.

#include <Wire.h>
#include <RTClib.h>
#include <ShiftDisplay.h>

RTC_Millis rtc;

const byte DATA_PIN = 5;
const byte LATCH_PIN = 6;
const byte CLOCK_PIN = 7;
const int DISPLAY_TYPE = COMMON_CATHODE;  //COMMON_CATHODE o COMMON_ANODE
const byte DISPLAY_SIZE = 6;              //Numero de digitos

ShiftDisplay display(LATCH_PIN, CLOCK_PIN, DATA_PIN, DISPLAY_TYPE, DISPLAY_SIZE);

void setup() {
   rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
}

void loop() {
   DateTime hoy = rtc.now();
   String hora = "";
   if (hoy.hour() < 10){
      hora = '0';
   }
   hora = hora + hoy.hour();
   if (hoy.minute() < 10){
      hora = hora + '0';
   }
   hora = hora + hoy.minute();
   if (hoy.second() < 10){
      hora = hora + '0';
   }
   hora = hora + hoy.second();
   display.set(hora);
   display.show(1000);
}

Si puedes mejorar o simplificar mas aun este código de ejemplo dímelo aquí

Eston otras librerias para 7 segmentos que podrias investigar como son: