Pulsador de Pausa

Buenas, tengo este código y quiero agregarle un pulsador para poder pausar y darle inicio al tiempo y otro para resetearlo, el problema es que no se como programarlo y conectarlo en simulador (Proteus).
Alguien me puede ayudar? Gracias!

//CRONOMETRO DECRECIENTE CON BUZZER FUNCIONAL
#define BT0 14
#define BT1 15
#define BUZ 12

int minutos = 2; //Minuto inicial
int timer = minutos * 60; //tiempo total
int ky; //trava dos botones

void decoder(int);
    
void setup() {
 for(int i = 0; i < 13; i++) pinMode(i, OUTPUT);
 for(int i = 14; i < 16; i++) pinMode(i, INPUT_PULLUP);
}

void loop() {

  if(timer < 0){
    timer = 0;
    tone(BUZ, 200, 300);
  }
  
  for(int clk = 0; clk < 5; clk++){ //50*4 = 200*5 = 1000mS = 1 segundo
    decoder(timer); 
    if(!digitalRead(BT0) && !ky) timer -= 60; //Saca un minuto
    if(!digitalRead(BT1) && !ky) timer += 60; //Pone un minuto
    if( digitalRead(BT0) && digitalRead(BT1)) ky = 0; 
    else ky = 1; //Botones travados
  }
 digitalWrite(7, !digitalRead(7));  
 timer--;
}

void decoder(int total){

  int d[4] = {

    (total / 60) / 10, //10:00 decenas minutos d[0]
    (total / 60) - d[0] * 10, //01:00 unidades minutos d[1]
    (total % 60) / 10, // 00:10 decenas segundos d[2]
    (total % 60) - d[2] * 10 //00:01 unidades segundos d[3]
  };

  int digit[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, 1, 0, 1, 1}  // 9
  };//a, b, c, d, e, f, g

  for(int dsp = 0; dsp < 4; dsp++){
    for(int seg = 0; seg < 7; seg++){
      digitalWrite(seg, digit[d[dsp]][seg]);
    }
    !dsp ? digitalWrite(11, 1): digitalWrite(dsp + 7, 1); // apaga el display anterior 
    digitalWrite(8 + dsp, 0); // Asciende undDigito 
    delay(50); // Velocidad de multiplexacion
  }
}```

Hola:
Conecta dos botones a los pines 17 y 18 y a GND
Añade en el setup:

pinMode(17, INPUT_PULLUP);
pinMode(18, INPUT_PULLUP);

Añade lo primero en el loop :

//Para pausar
if (digitalRead (17) == LOW) { //mira si pulsado 17
  while (digitalRead (17) == LOW) {} // espera suelta pulsación
  while (digitalRead (17) == HIGH) {} // espera nueva pulsacion para continuar
  while (digitalRead (17) == LOW) {} // espera suelta pulsación
}
// para resetear
if (digitalRead (18) == LOW) { //mira si pulsado 18
  while (digitalRead (18) == LOW) {} // espera suelta pulsación
  timer = minutos * 60; //tiempo total
}

Esto funciona en la realidad, supongo que tambien en el simulador de proteus,
ese no lo tengo para probar.
Saludos.

1 Like

@gonpezzi se te atravesaron los dedos cuando tipeaste los while! :wink:

Valla por Dios!, lo corrijo. Gracias.

1 Like

Muchas gracias, la verdad funciona tal cual lo esperaba!

Lo que me olvide de comentar que también me esta faltando es un botón para darle inicio, es decir, cuando empiece la simulación no arranque a correr los segundo (pero si los muestre) hasta que yo no pulse ese botón, capaz podes darme una mano también con esta parte?

Nuevamente, muchas gracias

Para eso vamos a utilizar el mismo boton de resetear si añadimos al final del setup :

  while (digitalRead (18) == HIGH) {decoder(timer); } // Espera pulsación

Saludos.

1 Like

Nuevamente me funciona correctamente así que te agradezco muchísimo!

Lo otro en lo que te voy a molestar es que yo quiero poder sumar y restar los minutos antes de que arranque a descontar los segundos (es decir funcionar el circuito) y también quiero poder visualizar todos los 7 segmentos prendidos, se que es subiéndole la frecuencia pero no se como hacer eso, me podes dar una mano con esto también?

No es conveniente que definas la matriz digit como local dentro de decoder()
Definela global (o sea al principio del código)

const byte digit[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, 1, 0, 1, 1}  // 9
  };//a, b, c, d, e, f, g

De paso ahorras memoria.

Respecto al parpadeo de los segmentos, así como está implementado el código, se complica mejorarlo ya que lo único que puedes hacer es bajar el tiempo del delay al final de decoder(). Baja el delay a 25 y sube a 10 el límite del for() en el loop() para mantener los tiempos. Debería mejorar un poco.

Muchas gracias por la respuesta.

De todos modos no veo cambio en los segmentos al hacer lo que tu me indicas, tampoco veo como me puede ayudar hacer la matriz global a la otra problemática planteada.

Si alguien me puede ayudar con esto le agradezco, saludos.

Cada vez que crea y destruye la matriz pierde tiempo que influye en el parpadeo de los segmentos.
Como te dije, de la forma en que está hecho el código poco se puede hacer para mejorarlo.

Pues facil como ya tienes los botones de subir y bajar los minutos vamos a usarlos .
En el wlie que añadistes es el setup añadimos su uso te quedaria una cosa asi:

while (digitalRead (18) == HIGH) {
  decoder(timer); 
  if(!digitalRead(BT0) ){
            While (!digitalRead(BT0) ){} 
            timer -= 60; //Saca un minuto
  }
  if(!digitalRead(BT1) ) {
          While (!digitalRead(BT1) ){} 
         timer += 60; //Pone un minuto
  }
}

Ojo con esto que estas simulando en Proteus y la realidad puede ser muy distinta, yo seguiria los consejos de @gatul .

Saludos y que salga bien el asado.

Mirá, me había olvidado que era una simulación.

@castor18 vos esperás ver cambios significativos en los displays en una simulación?
Tengo un cronómetro que multiplexa 8 digitos a 1kHz perfectamente en físico y que en la simulación parece que un segmento le pidiera permiso al otro para encenderse a pesar que encienden todos los segmentos de cada digito al mismo tiempo.
No te fíes de la simulación de los display de 7 segmentos.

Muchas gracias a ambos! Aunque me parece que tengo un error porque al presionar el botón de inicio no empieza a correr el tiempo sino que se pone en 0 y suena la bocina, dejo mi código para ver si me pueden dar una mano chequeándolo e identificar el error.

//CRONOMETRO DECRECIENTE CON BUZZER FUNCIONAL
#define BT0 14
#define BT1 15
#define BUZ 12

int digit[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, 1, 0, 1, 1}  // 9
  };//a, b, c, d, e, f, g
  
int minutos = 20; //Minuto inicial
int timer = minutos * 60; //tiempo total
int ky; //trava dos botones

void decoder(int);
    
void setup() {
 pinMode(17, INPUT_PULLUP);
 pinMode(18, INPUT_PULLUP);
 for(int i = 0; i < 13; i++) pinMode(i, OUTPUT);
 for(int i = 14; i < 16; i++) pinMode(i, INPUT_PULLUP);
  while (digitalRead (18) == HIGH) {
    decoder(timer); 
  if(!digitalRead(BT0) ){
            while (!digitalRead(BT0) ){} 
            timer -= 60; //Saca un minuto
  }
  if(!digitalRead(BT1) ) {
          while (!digitalRead(BT1) ){} 
         timer += 60; //Pone un minuto
  }
  }
}

void loop() {
  //PARA PAUSAR
  if (digitalRead (17) == LOW) { //mira si pulsado 17
    while (digitalRead (17) == LOW) {} // espera suelta pulsación
    while (digitalRead (17) == HIGH) {} // espera nueva pulsacion para continuar
    while (digitalRead (17) == LOW) {} // espera suelta pulsación
}
  //PARA RESETEAR
  if (digitalRead (18) == LOW) { //mira si pulsado 18
    while (digitalRead (18) == LOW) {} // espera suelta pulsación
    timer = minutos * 60; //tiempo total
}

  if(timer < 0){
    timer = 0;
    tone(BUZ, 200, 300);
  }
  
  /*for(int clk = 0; clk < 5; clk++){ //50*4 = 200*5 = 1000mS = 1 segundo
    decoder(timer); 
    if(!digitalRead(BT0) && !ky) timer -= 60*5; //Saca un minuto
    if(!digitalRead(BT1) && !ky) timer += 60*5; //Pone un minuto
    if( digitalRead(BT0) && digitalRead(BT1)) ky = 0; 
    else ky = 1; //Botones travados
  }*/
 digitalWrite(7, !digitalRead(7));  
 timer--;
}

void decoder(int total){

  int d[4] = {

    (total / 60) / 10, //10:00 decenas minutos d[0]
    (total / 60) - d[0] * 10, //01:00 unidades minutos d[1]
    (total % 60) / 10, // 00:10 decenas segundos d[2]
    (total % 60) - d[2] * 10 //00:01 unidades segundos d[3]
  };

  /*int digit[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, 1, 0, 1, 1}  // 9
  };//a, b, c, d, e, f, g*/

  for(int dsp = 0; dsp < 4; dsp++){
    for(int seg = 0; seg < 7; seg++){
      digitalWrite(seg, digit[d[dsp]][seg]);
    }
    !dsp ? digitalWrite(11, 1): digitalWrite(dsp + 7, 1); // apaga el display anterior 
    digitalWrite(8 + dsp, 0); // Asciende un digito 
    delay(50); // Velocidad de multiplexacion
  }
}

Pude resolver ese problema pero me surgió otro, ahora lo que pasa es que al darle inicio no empieza en el minuto que le marque sino en el que esta estipulado en el código.

Como se puede solucionar esto?

No entiendo donde haces el Start, pero si es con la pulsación para Reset, fijate que
timer = minutos * 60;
te borra lo que ajustaste y pone lo que está por defecto (obvio porque resetea el tiempo).

Saludos

A ver si esto funciona mejor.

//CRONOMETRO DECRECIENTE CON BUZZER FUNCIONAL
#include <avr/wdt.h>
#define BT0 14
#define BT1 15
#define BUZ 12

int digit[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, 1, 0, 1, 1}  // 9
};//a, b, c, d, e, f, g

int minutos, timer;

int ky; //trava dos botones

void decoder(int);

void setup() {
  pinMode(17, INPUT_PULLUP);
  pinMode(18, INPUT_PULLUP);
  for (int i = 0; i < 13; i++) pinMode(i, OUTPUT);
  for (int i = 14; i < 16; i++) pinMode(i, INPUT_PULLUP);
  while (digitalRead (18) == HIGH) {
    decoder(timer);
    if (!digitalRead(BT0) ) {
      while (!digitalRead(BT0) ) {}
      minutos -= 1; //Saca un minuto
    }
    if (!digitalRead(BT1) ) {
      while (!digitalRead(BT1) ) {}
      minutos += 1; //Pone un minuto
    }
    timer = minutos * 60; //tiempo total
  }
  delay (500);
}

void loop() {
  //PARA PAUSAR
  if (digitalRead (17) == LOW) { //mira si pulsado 17
    while (digitalRead (17) == LOW) {} // espera suelta pulsación
    while (digitalRead (17) == HIGH) {} // espera nueva pulsacion para continuar
    while (digitalRead (17) == LOW) {} // espera suelta pulsación para continuar
  }
  //PARA RESETEAR
  if (digitalRead (18) == LOW) { //mira si pulsado 18
    while (digitalRead (18) == LOW) {} // espera suelta pulsación
    wdt_enable(WDTO_15MS); //resetea el micro
    delay(1000);
  }

  if (timer < 0) {
    timer = 0;
    tone(BUZ, 200, 300);
  }

  for (int clk = 0; clk < 5; clk++) { //50*4 = 200*5 = 1000mS = 1 segundo
    decoder(timer);
    if (!digitalRead(BT0) && !ky) timer -= 60; //Saca un minuto
    if (!digitalRead(BT1) && !ky) timer += 60; //Pone un minuto
    if ( digitalRead(BT0) && digitalRead(BT1)) ky = 0;
    else ky = 1; //Botones travados
  }
  digitalWrite(7, !digitalRead(7));
  timer--;
}

void decoder(int total) {
  int d[4] = {

    (total / 60) / 10, //10:00 decenas minutos d[0]
    (total / 60) - d[0] * 10, //01:00 unidades minutos d[1]
    (total % 60) / 10, // 00:10 decenas segundos d[2]
    (total % 60) - d[2] * 10 //00:01 unidades segundos d[3]
  };

  for (int dsp = 0; dsp < 4; dsp++) {
    for (int seg = 0; seg < 7; seg++) {
      digitalWrite(seg, digit[d[dsp]][seg]);
    }
    !dsp ? digitalWrite(11, 1) : digitalWrite(dsp + 7, 1); // apaga el display anterior
    digitalWrite(8 + dsp, 0); // Asciende un digito
    delay(50); // Velocidad de multiplexacion
  }
}

Estás reseteando el micro para resetear el contador??? :roll_eyes::

Si , para el proposito buscado es lo mas comodo. ademas no te gusta el jmp 0000 y luego me criticas . :wink:

Pero eso es como apagar la PC para cerrar un documento. :grimacing:

En el cronómetro que comenté más arriba, con un solo botón inicio, pauso y reinicio o reseteo (y con debouncer)

bool get_button() {
  
  static bool state = false;
  static bool oldstate = false;
  static bool debouncer = false;
  static uint32_t oldtime = 0;
  
  if(debouncer) {
    if(millis() - oldtime >= 20UL) {
      debouncer = false;
    }
  }
  else {
    state = !digitalRead(12); // boton pulsado = LOW => state = HIGH
    if(state != oldstate) { 
        oldstate = state;
        debouncer = true;
        oldtime = millis();
    }
  }
  return state;
}

void loop() {
  
  static uint32_t newtime = 0;

  static bool oldbtn = false;
  static bool started = false;
  static bool paused = false;
  
  uint32_t presstime = 0;
  bool newbtn = false;
  bool hold = false;
  
  newbtn = get_button();
  if(newbtn) {
    if(started) newtime = timecnt; // guarda el tiempo reloj al pulsar el botón 
    if(paused){
      presstime = millis();
      while(get_button()) {  // mientras el boton esté pulsado
        if(millis() - presstime >= 1000UL) { // si pasa 1 seg provoca el reset del cronómetro
          hold = true;
          break;
        }
      }
    }
  }
  if(newbtn != oldbtn) {
    oldbtn = newbtn;
    if(newbtn) {
      if(started) {  // si está corriendo ** pausar **
        started = false;
        paused = true;
      }
      else {
        if(paused) {
          if(hold) {  // si en pausa pulsación larga ** resetear **
            newtime = 0;
          }
          else {
            started = true; // si pulsación corta ** continuar **
          }
          paused = false;
        }
        else {  // si no estaba corriendo ** iniciar **
          timecnt = 0;
          started = true;
        }
      }
    }
  }
// sigue el código

Como trabaja con el timer1 a 1KHz , timercnt cuenta milésimas (de ahí saco min, seg y centésimas) y newtime guarda el tiempo al momento de pulsar el botón, sino mostraría el tiempo mas el retardo del debouncer y/o el segundo de la pulsación larga.
Lo explico para que entiendas de que van esas dos variables.

Fijate si te sirve como guía.

Saludos