Is it possible to get an hour timer interrupt from Atmega328p?

984 Views Asked by At

Coming from this question and I just wonder How to calculate maximum time that an Atmega328 timer can give us before trigger an interrupt? I want it to trigger every hour or so in my project but due to the fact that C integer and OCR1A register has some limitation in size it seems far fetch to get an hour from it.

Is it possible to modify my last question code to get some hour delay?

2

There are 2 best solutions below

0
On

The comment by Jabberwocky translates to this code (based on the other question to which your have posted the link)

... includes

/* In milliseconds */
const unsigned int ISR_QUANTUM = 1000; // once in a second

/* How much time should pass (1 hours = 3600 seconds = 3600 * 1000 ms */
const unsigned long LONG_TIME_INTERVAL = 1000 * 3600;

volatile unsigned long time_counter;

void once_an_hour() {
    ... do what needs to be done
}

int main(void) {
    ... setup your timer interrupt (high-precision, "short-range")

    // reset your 'seconds' time counter
    time_counter = 0;

    while (1)
    {
        // busy-wait for time counter passing
        if (time_counter > LONG_TIME_INTERVAL) {
            // reset global timer
            time_counter = 0;
            once_an_hour();
        }

        // do other things
        ...
    }
}

ISR (TIMER1_COMPA_vect)
{
    // action to be done every Xms - just increment the time_counter
    time_counter += ISR_QUANTUM;
}

This way you just increment a "global" time counter in a "local" interrupt handler.

0
On

It should be, depending on the frequency of your microcontroller and the prescaler you're going to use.

Atmega 328P is 20 MHz. So if you take 20,000,000/1024 = 19531. Thats the number of cycles in 1 second.

You can find this in the data sheet for a 16 Bit Timer:

    volatile uint8_t count = 0;

    void set_up_timer() {
      TCCR1B = (1 << WGM12);       // from the datasheet
      OCR1A = 19531;               // number of ticks in a second
      
      TIMSK1 = (1 << OCIE1A);      // from the data sheet
      TCCR1B |= (1 << CS12) | (1 << CS10);   

You can set a global variable, and increment it in the ISR Routine until the desired value is achieved. Something along the lines of:

      ISR(TIMER1_COMP1_VECT) {
        counter++;
        if(counter >= 3600) {
         // do whatever needs to be done
        }