Cuatro contadores inversos activados por una señal de entrada por puerto serial

Buen día.
Estoy trabajando en un código cuyo objetivo es el siguiente:
Enviar un dato por el puerto serial y que este sea recibido por el Arduino UNO, después de recibido, dependiendo del dato se inicie una cuenta regresiva de tiempo. 1 hora, media hora, quince minutos y cinco minutos
A continuación, adjunto el código que he trabajado hasta el momento y una imagen de las conexiones con el display de 7 segmentos, 4 dígitos, cátodo común.

//7 Segmentos de display
int a = 12;
int b = 8;
int c = 4;
int d = 6;
int e = 7;
int f = 11;
int g = 3;
 
// digitos de Display
int dg1 = 2;
int dg2 = 9;
int dg3 = 10;
int dg4 = 13;

//Punto
int dp=5;

//Velocidad. Entre menos valor el contador ira mas rapido, si le aumentamos el valor ira mas lento.
int vel=1;

//Unidades,decenas, centenas y millares
int mil,cien,dec,uni;

byte segmentos[7] = { a,b,c,d,e,f,g };
byte orden_digitos[4] = { dg1,dg2,dg3,dg4 };
byte digitos[4][4] = { 
  { 0,0,0,1 },
  { 0,0,1,0 },
  { 0,1,0,0 },
  { 1,0,0,0 }
};

byte siete_segmentos_digitos[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 EscribeDigito(byte digito, byte numero) {
  int secuencia = 0; 
  //Activa número
  ActivarDigito(digito); 
  //digitalWrite(dp,1);//Punto
  //Escribe Numero 
  for (byte i = 0; i < 7; i++){
    digitalWrite(segmentos[secuencia], siete_segmentos_digitos[numero][i]);
    ++secuencia;
  }
}

void ActivarDigito(int x){
  digitalWrite(dg1, HIGH);
  digitalWrite(dg2, HIGH);
  digitalWrite(dg3, HIGH);
  digitalWrite(dg4, HIGH); 
  switch(x){
    case 1: 
      digitalWrite(dg1, LOW); 
      break;
    case 2: 
      digitalWrite(dg2, LOW); 
      break;
    case 3: 
      digitalWrite(dg3, LOW); 
      break;
    default: 
      digitalWrite(dg4, LOW); 
      break;
  }
}
 
void setup(){
  Serial.begin(9600);
  int i; 
  //Inicializar Pines
  for(i=2; i <= 13;i++)     
     pinMode(i,OUTPUT);
} 

 void loop(){
  int y = Serial.available();
 //una hora
  if(y = 001){
    for(mil=0;mil<=3;mil++){
      for(cien=0;cien<=6;cien++){
          for(dec=0;dec<=0;dec++){
               for(uni=0;uni<=0;uni++){
                   EscribeDigito(1, uni);
                   delay(vel);
                   EscribeDigito(2, dec);
                   delay(vel);
                   EscribeDigito(3, cien);
                   delay(vel);
                   EscribeDigito(4, mil);
                   delay(vel);
               } 
          }    
      }
  }
}
  
  if(y = 002){
   //media hora
   for(mil=0;mil<=1;mil++){
      for(cien=0;cien<=8;cien++){
          for(dec=0;dec<=0;dec++){
               for(uni=0;uni<=0;uni++){
                   EscribeDigito(1, uni);
                   delay(vel);
                   EscribeDigito(2, dec);
                   delay(vel);
                   EscribeDigito(3, cien);
                   delay(vel);
                   EscribeDigito(4, mil);
                   delay(vel);
               } 
          }    
      }
  }
}

  if(y = 003){
//quince minutos
    for(mil=0;mil<=0;mil++){
      for(cien=0;cien<=9;cien++){
          for(dec=0;dec<=9;dec++){
               for(uni=0;uni<=9;uni++){
                   EscribeDigito(1, uni);
                   delay(vel);
                   EscribeDigito(2, dec);
                   delay(vel);
                   EscribeDigito(3, cien);
                   delay(vel);
                   EscribeDigito(4, mil);
                   delay(vel);
               } 
          }    
      }
  }
}

  if(y = 004){
//cinco minutos
    for(mil=0;mil<=0;mil++){
      for(cien=0;cien<=3;cien++){
          for(dec=0;dec<=0;dec++){
               for(uni=0;uni<=0;uni++){
                   EscribeDigito(1, uni);
                   delay(vel);
                   EscribeDigito(2, dec);
                   delay(vel);
                   EscribeDigito(3, cien);
                   delay(vel);
                   EscribeDigito(4, mil);
                   delay(vel);
               } 
          }    
      }
  }
}
 
 }

Mi problema está en que el contador va en ascendencia, además de que cuando llega al número 9 este ya no regresa al 0, si no que se queda en 9 y continua con el siguiente display.

Les agradezco su ayuda.

Si fuera por mi te cambio todo el código y uso la librería SevSeg que hace todo de manera muy simple. Búscala!!

Mira a ver si esto funciona

void loop(){
  int y; 

  if (Serial.available()>0) {
      y = Serial.read()-48;
  }
  //una hora
  if (y = 1){
      for (mil=0;mil<=3;mil++){
          for (cien=0;cien<=6;cien++){
               for (dec=0;dec<=0;dec++){
                    for (uni=0;uni<=0;uni++){
                         EscribeDigito(1, uni);
                         delay(vel);
                         EscribeDigito(2, dec);
                         delay(vel);
                         EscribeDigito(3, cien);
                         delay(vel);
                         EscribeDigito(4, mil);
                         delay(vel);
                    } 
               }    
          }
  }
}
  
  if(y = 2){
   //media hora
   for(mil=0;mil<=1;mil++){
      for(cien=0;cien<=8;cien++){
          for(dec=0;dec<=0;dec++){
               for(uni=0;uni<=0;uni++){
                   EscribeDigito(1, uni);
                   delay(vel);
                   EscribeDigito(2, dec);
                   delay(vel);
                   EscribeDigito(3, cien);
                   delay(vel);
                   EscribeDigito(4, mil);
                   delay(vel);
               } 
          }    
      }
  }
}

  if(y = 3){
//quince minutos
    for(mil=0;mil<=0;mil++){
      for(cien=0;cien<=9;cien++){
          for(dec=0;dec<=9;dec++){
               for(uni=0;uni<=9;uni++){
                   EscribeDigito(1, uni);
                   delay(vel);
                   EscribeDigito(2, dec);
                   delay(vel);
                   EscribeDigito(3, cien);
                   delay(vel);
                   EscribeDigito(4, mil);
                   delay(vel);
               } 
          }    
      }
  }
}

  if(y = 4){
  //cinco minutos
      for(mil=0;mil<=0;mil++){
        for(cien=0;cien<=3;cien++){
            for(dec=0;dec<=0;dec++){
                 for(uni=0;uni<=0;uni++){
                     EscribeDigito(1, uni);
                     delay(vel);
                     EscribeDigito(2, dec);
                     delay(vel);
                     EscribeDigito(3, cien);
                     delay(vel);
                     EscribeDigito(4, mil);
                     delay(vel);
                 } 
            }    
        }
    }
  }
}

Con esta librería SevSeg sería asi

#include "SevSeg.h"  // https://github.com/DeanIsMe/SevSeg
SevSeg sevseg; //Instantiate a seven segment controller object

void setup() {
  byte numDigits = 4;
  byte digitPins[] = {2, 9, 10, 13};
  byte segmentPins[] = {12, 8, 4, 6, 7, 11, 3, 5};  // 5 seria el punto decimal
  bool resistorsOnSegments = false; // 'false' means resistors are on digit pins
  byte hardwareConfig = COMMON_ANODE; // Sino funciona usa COMMON_CATHODE
  bool updateWithDelays = false; // Default. Recommended
  bool leadingZeros = false; // Use 'true' if you'd like to keep the leading zeros
  
  sevseg.begin(hardwareConfig, numDigits, digitPins, segmentPins, resistorsOnSegments, updateWithDelays, leadingZeros);
  sevseg.setBrightness(90);
}

void loop() {
  static unsigned long timer = millis();
  static int deciSeconds = 0;
  
  if (millis() - timer >= 100) {
    timer += 100;
    deciSeconds++; // 100 milliSeconds is equal to 1 deciSecond
    
    if (deciSeconds == 10000) { // Reset to 0 after counting for 1000 seconds.
      deciSeconds=0;
    }
    sevseg.setNumber(deciSeconds, 1);
  }

  sevseg.refreshDisplay(); // Must run repeatedly
}

El código no es el tuyo pero ya sabras modificarlo

Buen día surbyte, muchas gracias por tu ayuda. He tenido algo de problemas con mi internet, pero he estado leyendo sobre la libreria que me comentas SevSeg, la cual me ahorra muchisimo codigo :D.

Por otra parte, comence a trabajar con el ultimo codigo que compartiste, le he modificado un par de cosas solamente, me encuentro trabajando sobre el. Ahora bien, quisiera consultarte como podria enviar un tiempo exacto a partir de una variable que pueda modificar y que este tiempo sea un contador regresivo;

Ejemplo;

Variable "tiempo = 300" y que esta se refleje en el display, para que posteriormente comience a disminuir su valor hasta llegar a cero.

Te comparto el codigo que recien empece a modificar y sigo estudiando la libreria :slight_smile:

#include "SevSeg.h"
SevSeg sevseg; //Crea la instancia para el display
unsigned long tiempoLimite = 3600;

void setup() {
  byte numDigits = 4;
  byte digitPins[] = {13, 10, 9, 2};
  byte segmentPins[] = {12, 8, 4, 6, 7, 11, 3, 5};  // 5 seria el punto decimal
  bool resistorsOnSegments = false; // 'false' means resistors are on digit pins
  byte hardwareConfig = COMMON_CATHODE; // Sino funciona usa COMMON_CATHODE
  bool updateWithDelays = false; // Default. Recommended
  bool leadingZeros = false; // Use 'true' if you'd like to keep the leading zeros
  
  sevseg.begin(hardwareConfig, numDigits, digitPins, segmentPins, resistorsOnSegments, updateWithDelays, leadingZeros);
  sevseg.setBrightness(90);
}

void loop() {
  static unsigned long timer = tiempo limite - millis();
  static int deciSeconds = 10;
  
  if (millis() - timer >= 100) {
    timer += 100;
    deciSeconds++; // 100 milliSeconds is equal to 1 deciSecond
    
    if (deciSeconds == 10000) { // Reset to 0 after counting for 1000 seconds.
      deciSeconds=0;
    }
    sevseg.setNumber(deciSeconds, 100);
  }

  sevseg.refreshDisplay(); // Must run repeatedly
}

Lo primero es lo primero.
Tomas la librería y un ejemplo y la adaptas a tu hardware.
Aprendes a mostrar datos y una vez que entendiste todo te pones a trabajar con TU PROBLEMA, antes no.
Antes tienes todo nuevo, no sabes si es catodo o anodo común. Si este o el otro contrala esto o lo otro, si el segmento o el punto decimal.
Cuando ese caos dessaparece.. entonces dices ahhh bien, ahora muestro un contador como esta en el ejemplo o un valor fijo y luego un float que tambien puede hacerlo.

Terminas eso y te pones con tu contador regresivo y será una pavada resolverlo.
Se comprende?

Entendido, gracias :slight_smile:

Buen día, les comparto el código que he trabajado y esta funcional.

#include "SevSeg.h"//incluye la libreria de display de 7 segmentos y 4 digitos
SevSeg sevseg; //Crea la instancia para el display
static unsigned long timer = millis();// variable para control de tiempo en milisegundos
static int deciSeconds = 9000;// numero con el que se iniciara el display

void setup() {
  byte numDigits = 4;//numero de digitos
  byte digitPins[] = {13, 10, 9, 2};//Pines digitales del display D1, D2, D3, D4
  byte segmentPins[] = {12, 8, 4, 6, 7, 11, 3};  // 5 seria el punto decimal
  bool resistorsOnSegments = false; // las resistencias estan en los pines de los digitos
  byte hardwareConfig = COMMON_CATHODE; // Se declara catodo comun
  bool updateWithDelays = false; // Actualizar sin retraso
  bool leadingZeros = true; // Usar verdadero si se desea mantener los ceros a la izquierda
  
  sevseg.begin(hardwareConfig, numDigits, digitPins, segmentPins, resistorsOnSegments, updateWithDelays, leadingZeros);
  sevseg.setBrightness(90);//reestablecer el brillo se puede ajustar de 0-100
  
}

void loop() {

  while(deciSeconds >= 1){
  
    if (millis() - timer >= 1000) {
   
      timer += 1000;// controlador de tiempo en el que disminuye el display 1000 = 1 segundo
      deciSeconds = deciSeconds - 1; // 100 milisegundos es igual a 1 decisegundo
    
        if (deciSeconds == 0) { 
        deciSeconds = 0;// Reestablece el cero despues de llegar a cero
    
        }
    
      }
    
    sevseg.setNumber(deciSeconds);// muestra el valor actual de la variable
    sevseg.refreshDisplay(); // correr repetidamente
  
  }

 sevseg.setNumber(0000, 3);// muestra el valor directamente en el display
 sevseg.refreshDisplay(); // correr repetidamente

}

P.D. Gracias surbyte por la recomendación de la librería.

Seguiré trabajando en el código.

Bueno me alegro que te sirviera.

Recuerden que la mayor parte de las cosas estan hechas y casi siempre hay una librería que las hace y mucho mejor que lo que uds pueden lograr.
Eso es tiempo ahorrado, ahora si es tarea escolar o universitaria es otro cantar.

De lo contrario usenlas. Para eso es código abierto. La comunidad ayudar a crecer. Crezcan y luego podran devolverle a la comunidad.

Buen día, este es el código finalmente terminado; cuatro contadores inversos activados por una señal de entrada por puerto serial. Arduino UNO y display de 7 segmentos, 4 dígitos.

#include "SevSeg.h"//incluye la libreria de display de 7 segmentos y 4 digitos
SevSeg sevseg; //Crea la instancia para el display
static unsigned long timer = millis();// variable para control de tiempo en milisegundos
//static int deciSeconds = 9000;// numero con el que se iniciara el display

void setup() {

  Serial.begin(9600);
  
  byte numDigits = 4;//numero de digitos
  byte digitPins[] = {13, 10, 9, 2};//Pines digitales del display D1, D2, D3, D4
  byte segmentPins[] = {12, 8, 4, 6, 7, 11, 3};  // 5 seria el punto decimal
  bool resistorsOnSegments = false; // las resistencias estan en los pines de los digitos
  byte hardwareConfig = COMMON_CATHODE; // Se declara catodo comun
  bool updateWithDelays = false; // Actualizar sin retraso
  bool leadingZeros = true; // Usar verdadero si se desea mantener los ceros a la izquierda
  
  sevseg.begin(hardwareConfig, numDigits, digitPins, segmentPins, resistorsOnSegments, updateWithDelays, leadingZeros);
  sevseg.setBrightness(90);//reestablecer el brillo se puede ajustar de 0-100
  
}

void loop() {

 int dato = Serial.read();
   
  while (dato == 'a'){
    primerFase();
  }

  while (dato == 'b'){

    segundaFase();
  }

  while (dato == 'c'){

    static int deciSeconds = 1000;// numero con el que se iniciara el display
    
    while(deciSeconds >= 1){
  
      if (millis() - timer >= 1000) {
   
        timer += 1000;// controlador de tiempo en el que disminuye el display 1000 = 1 segundo
        deciSeconds = deciSeconds - 1; // 100 milisegundos es igual a 1 decisegundo
    
          if (deciSeconds == 0) { 
          deciSeconds = 0;// Reestablece el cero despues de llegar a cero
    
          }
    
        }
    
    sevseg.setNumber(deciSeconds);// muestra el valor actual de la variable
    sevseg.refreshDisplay(); // correr repetidamente
  
    }
  }

  while (dato == 'd'){

    static int deciSeconds = 1000;// numero con el que se iniciara el display
    
    while(deciSeconds >= 1){
  
      if (millis() - timer >= 1000) {
   
        timer += 1000;// controlador de tiempo en el que disminuye el display 1000 = 1 segundo
        deciSeconds = deciSeconds - 1; // 100 milisegundos es igual a 1 decisegundo
    
          if (deciSeconds == 0) { 
          deciSeconds = 0;// Reestablece el cero despues de llegar a cero
    
          }
    
        }
    
    sevseg.setNumber(deciSeconds);// muestra el valor actual de la variable
    sevseg.refreshDisplay(); // correr repetidamente
  
    }
  }
  
  sevseg.setNumber(0000, 3);// muestra el valor directamente en el display
  sevseg.refreshDisplay(); // correr repetidamente

}