是否可以从Atmega328p获得一个小时计时器中断?

问题描述

来自this question,我只是想知道如何在触发中断之前计算Atmega328计时器可以给我们的最大时间?我希望它在我的项目中每隔一个小时左右触发一次,但由于C整数和OCR1A寄存器在大小上有一定限制,因此从中获取一个小时似乎很遥不可及。

是否可以修改我的最后一个问题代码以延迟一小时?

解决方法

取决于您的微控制器的频率和将要使用的预分频器。

Atmega 328P是20 MHz。因此,如果您采用20,000,000 / 1024 =19531。那就是1秒内的循环数。

您可以在数据表中找到16位定时器的信息:

    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);   

您可以设置一个全局变量,并在ISR例程中对其进行递增,直到获得所需的值为止。类似于:

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

Jabberwocky的评论翻译为以下代码(基于您向其发布链接的另一个问题)

... 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;
}

通过这种方式,您只需在“本地”中断处理程序中增加“全局”时间计数器即可。