Problema con timer interno basico

Buenas tengo un problema, tengo que hacer un programa que tenga una interrupcion interna con un timer, para que cada 30 segundos se muestre un mensaje en la pantalla lcd, pero no esta funcionando, lo hace cada 4, 6, 5 segundos, es lo unico y lo ultimo que me esta fallando, por favor si alguien me puede decir como se puede se puede hacer lo agradeceria mucho.

El programa principal debe de imprimir los numeros del 1 al 99 cada numero en un intervalo de 500 mS y hay 3 interrupciones, 2 externas (ya funcionan) y una interna (el timer que nomas no funciona).

#include <Wire.h>
#include <LiquidCrystal_I2C.h>
 

// Inicializa la pantalla LCD 16x2 con el modulo I2C
LiquidCrystal_I2C lcd(0x27, 16, 2);


// Variables globales
volatile unsigned long tiempo_transcurrido = 0;
volatile bool interrupt1_triggered = false;
volatile bool interrupt2_triggered = false;
volatile bool flagInterrupcion = false;

// Función para manejar la interrupción 1
void interrupt1() {
  interrupt1_triggered = true;
}

// Función para manejar la interrupción 2
void interrupt2() {
  interrupt2_triggered = true;
}

// Función para manejar la interrupción 2
ISR(TIMER3_COMPA_vect) {
  tiempo_transcurrido++; // Incrementar el tiempo transcurrido en 1 segundo
}



void setup() {
  Serial.begin(9600);

  // Configurar el timer1 para interrupción cada 30 segundos
  cli(); // Deshabilitar interrupciones
  TCCR3A = 0; // Configurar el Timer3 en modo normal
  TCCR3B = (1 << CS32) | (1 << CS30); // Configurar el Timer3 con preescaler de 1024
  TCNT3 = 0; // Reiniciar el contador del Timer3
  OCR3A = 500000; // Valor de comparación para interrupción cada 30 segundos
  TIMSK3 |= (1 << OCIE3A); // Habilitar interrupción del Timer3 por comparación con OCR3A
  sei(); // Habilitar interrupciones

  
  // Inicializa la pantalla LCD
  lcd.init();
  lcd.backlight();

  // Configura los pines de las interrupciones externas
  attachInterrupt(digitalPinToInterrupt(2), interrupt1, FALLING);
  attachInterrupt(digitalPinToInterrupt(3), interrupt2, FALLING);
}


void loop() {


  
  // Cuenta del 1 al 99 y muestra cada número en la pantalla
  for (int i = 1; i <= 99; i++) {

    if (tiempo_transcurrido >= 30) {
      lcd.clear();
      lcd.setCursor(0, 0); // Posicionar el cursor en la primera columna de la segunda fila
      lcd.print("PASARON 30 SEG"); // Mostrar el mensaje "pasaron 30 seg" en la pantalla LCD
      tiempo_transcurrido = 0; // Reiniciar el tiempo transcurrido
    }

    // Verifica si se ha activado la interrupción 1
    if (interrupt1_triggered) {
      lcd.clear();
      lcd.setCursor(0, 0);
      lcd.print("interrupción 1");

      // Reinicia la variable de interrupción
      interrupt1_triggered = false;

      // Espera un segundo antes de continuar con la cuenta
      delay(1000);
    }


    // Verifica si se ha activado la interrupción 2
    if (interrupt2_triggered) {
      lcd.clear();
      lcd.setCursor(0, 0);
      lcd.print("interrupción 2");

      // Reinicia la variable de interrupción
      interrupt2_triggered = false;

      // Espera un segundo antes de continuar con la cuenta
      delay(1000);
    }

    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print(i);

    // Espera medio segundo antes de mostrar el siguiente número
    delay(500);


    
  }
}


Por el timer3 asumo que estas utilizando un arduino Mega cierto?
El usuario Thomasx en su publicación del foro ejecuta satisfactoriamente interrupciones con el arduino mega en el timer 4
timer setup for timer4 For arduino Mega

A su vez me queda claro que estas haciendo mal la interrupción 3 ya que estableces el timer 3 con un prescaler de 1024 a 16 bits , lo que significa que puede almacenar un valor de contador máximo de 65535 y tu le asignas 500000

OCR3A = 500000; // Valor de comparación para interrupción cada 30 segundos

para finalizar cuentas con la variable tiempo transcurrido para crear un contador de 30 segundos cada que se interrumpe el timer3, pero esta declarado para incrementar la misma cada 1 segundo segun esta funcion

ISR(TIMER3_COMPA_vect) {
  tiempo_transcurrido++; // Incrementar el tiempo transcurrido en 1 segundo
}

En conclusión recomiendo hacer el timer3 a frecuencia de 1Hz lo que te dara una interrupción cada 1 segundo, así podrias usar tu variable tiempo_transcurrido hasta que llegue a 30 y presentar el mensaje en tu LCD, leyendo el código de thomasx las correcciones en el setup quedarian de la siguiente forma

void setup() {
  Serial.begin(9600);

  // Configurar el timer1 para interrupción cada 30 segundos
  cli(); // Deshabilitar interrupciones
  TCCR3A = 0; // Configurar el Timer3 en modo normal
  TCCR3B = 0 // same for TCCR1B
  TCNT3 = 0; // Reiniciar el contador del Timer3
  // set compare match register for 1hz increments
  OCR3A = 15624 / 1; // = (16*10^6) / (1*1024) - 1 (must be <65536)
  // turn on CTC mode
  TCCR3B |= (1 << WGM12);
  // Set CS12 and CS10 bits for 1024 prescaler
  TCCR3B |= (1 << CS12) | (1 << CS10);
  TIMSK3 |= (1 << OCIE3A); // Habilitar interrupción del Timer3 por comparación con OCR3A
  sei(); // Habilitar interrupciones


  // Inicializa la pantalla LCD
  lcd.init();
  lcd.backlight();

  // Configura los pines de las interrupciones externas
  attachInterrupt(digitalPinToInterrupt(2), interrupt1, FALLING);
  attachInterrupt(digitalPinToInterrupt(3), interrupt2, FALLING);
}

HOLA!

Ya hice los cambios que me comentaste y sigue sin funcionar, me di cuenta que al imprimir la variable tiempo_transcurrido en cada ciclo en vez del mensaje "PASARON 30 SEG", me estaba imprimiendo 891, como si en una vuelta del ciclo for la variable se incrementara 891 veces, no se si sea la condicion o algo en el programa principal que no permite que funcione correctamente aqui esta el codigo actualizado. Ah en mi desesperacion por querer hacerlo funcionar cambie el timer 3 por el timer 2 y efectivamente tengo arduino mega

#include <Wire.h>
#include <LiquidCrystal_I2C.h>
 

// Inicializa la pantalla LCD 16x2 con el modulo I2C
LiquidCrystal_I2C lcd(0x27, 16, 2);


// Variables globales
volatile unsigned long tiempo_transcurrido = 0;
volatile bool interrupt1_triggered = false;
volatile bool interrupt2_triggered = false;
volatile bool flagInterrupcion = false;

// Función para manejar la interrupción 1
void interrupt1() {
  interrupt1_triggered = true;
}

// Función para manejar la interrupción 2
void interrupt2() {
  interrupt2_triggered = true;
}

// Función para manejar la interrupción 2
ISR(TIMER2_COMPA_vect) {
  tiempo_transcurrido++; // Incrementar el tiempo transcurrido en 1 segundo
}



void setup() {
  Serial.begin(9600);

  // Configurar el timer2 para interrupción cada 30 segundos
  cli(); // Deshabilitar interrupciones
  TCCR2A = 0; // Configurar el Timer2 en modo normal
  TCCR2B = 0; // Configurar el Timer2 en modo normal
  TCNT2 = 0; // Reiniciar el contador del Timer2
  // set compare match register for 1hz increments
  OCR2A = 15624 / 1; // = (16*10^6) / (1*1024) - 1 (must be <65536)
  // turn on CTC mode
  TCCR2A |= (1 << WGM21);
  // Set CS22 and CS21 and CS20 bits for 1024 prescaler
  TCCR2B |= (1 << CS22) | (1 << CS21) | (1 << CS20);
  TIMSK2 |= (1 << OCIE2A); // Habilitar interrupción del Timer2 por comparación con OCR2A
  sei(); // Habilitar interrupciones


  // Inicializa la pantalla LCD
  lcd.init();
  lcd.backlight();

  // Configura los pines de las interrupciones externas
  attachInterrupt(digitalPinToInterrupt(2), interrupt1, FALLING);
  attachInterrupt(digitalPinToInterrupt(3), interrupt2, FALLING);
}


void loop() {


  
  // Cuenta del 1 al 99 y muestra cada número en la pantalla
  for (int i = 1; i <= 99; i++) {

    if (tiempo_transcurrido >= 30) {
      lcd.clear();
      lcd.setCursor(0, 0); // Posicionar el cursor en la primera columna de la segunda fila
      lcd.print(tiempo_transcurrido); // Mostrar el mensaje "pasaron 30 seg" en la pantalla LCD
      delay(500);
      tiempo_transcurrido = 0; // Reiniciar el tiempo transcurrido
    }

    // Verifica si se ha activado la interrupción 2
    if (interrupt1_triggered) {
      lcd.clear();
      lcd.setCursor(0, 0);
      lcd.print("FRANCISCO CETI");

      // Reinicia la variable de interrupción
      interrupt1_triggered = false;

      // Espera un segundo antes de continuar con la cuenta
      delay(1000);
    }


    // Verifica si se ha activado la interrupción 2
    if (interrupt2_triggered) {
      lcd.clear();
      lcd.setCursor(0, 0);
      lcd.print("DON CHUY FILEMON");

      // Reinicia la variable de interrupción
      interrupt2_triggered = false;

      // Espera un segundo antes de continuar con la cuenta
      delay(1000);
    }

    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print(i);

    // Espera medio segundo antes de mostrar el siguiente número
    delay(500);


    
  }
}


Probado y funciona bien (corregido seteo del timer)

#include <Wire.h>
#include <LiquidCrystal_I2C.h>

// Inicializa la pantalla LCD 16x2 con el modulo I2C
LiquidCrystal_I2C lcd(0x27, 16, 2);


// Variables globales
volatile unsigned long tiempo_transcurrido = 0;
volatile bool interrupt1_triggered = false;
volatile bool interrupt2_triggered = false;
volatile bool flagInterrupcion = false;

// Función para manejar la interrupción 1
void interrupt1() {
  interrupt1_triggered = true;
}

// Función para manejar la interrupción 2
void interrupt2() {
  interrupt2_triggered = true;
}

// Función para manejar la interrupción timer3
ISR(TIMER3_COMPA_vect) {
  tiempo_transcurrido++; // Incrementar el tiempo transcurrido en 1 segundo
}



void setup() {
  Serial.begin(9600);

  // Configurar el timer1 para interrupción cada 1 segundo
  noInterrupts();
  // Clear registers
  TCCR3A = 0;
  TCCR3B = 0;
  TCNT3 = 0;

  // 1 Hz (16000000/((15624+1)*1024))
  OCR3A = 15624;
  // CTC
  TCCR3B |= (1 << WGM32);
  // Prescaler 1024
  TCCR3B |= (1 << CS32) | (1 << CS30);
  // Output Compare Match A Interrupt Enable
  TIMSK3 |= (1 << OCIE3A);
  interrupts();
  
  // Inicializa la pantalla LCD
  lcd.init();
  lcd.backlight();

  // Configura los pines de las interrupciones externas
  attachInterrupt(digitalPinToInterrupt(2), interrupt1, FALLING);
  attachInterrupt(digitalPinToInterrupt(3), interrupt2, FALLING);
}


void loop() {

  // Cuenta del 1 al 99 y muestra cada número en la pantalla
  for (int i = 1; i <= 99; i++) {

    if (tiempo_transcurrido >= 30) {
      lcd.clear();
      lcd.setCursor(0, 0); // Posicionar el cursor en la primera columna de la segunda fila
      lcd.print("PASARON 30 SEG"); // Mostrar el mensaje "pasaron 30 seg" en la pantalla LCD
      tiempo_transcurrido = 0; // Reiniciar el tiempo transcurrido
      delay(2000);  // agregue este delay para que se vea el mensaje
    }

    // Verifica si se ha activado la interrupción 1
    if (interrupt1_triggered) {
      lcd.clear();
      lcd.setCursor(0, 0);
      lcd.print("interrupción 1");

      // Reinicia la variable de interrupción
      interrupt1_triggered = false;

      // Espera un segundo antes de continuar con la cuenta
      delay(1000);
    }


    // Verifica si se ha activado la interrupción 2
    if (interrupt2_triggered) {
      lcd.clear();
      lcd.setCursor(0, 0);
      lcd.print("interrupción 2");

      // Reinicia la variable de interrupción
      interrupt2_triggered = false;

      // Espera un segundo antes de continuar con la cuenta
      delay(1000);
    }

    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print(i);

    // Espera medio segundo antes de mostrar el siguiente número
    delay(500);

  }
}

Una buena fuente para trabajar con los timers Arduino Slovakia - AVR Timer Interrupts Calculator

Saludos

1 Like

Ya funciono!, muchas gracias amigo, de verdad. Note que tiene un ligero desfase, supongo que sera por el delay de 500mS para mostrar el iterator del ciclo. Muchas gracias otra vez!.

Seguramente.
Saludos

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.