问题描述
来自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;
}
通过这种方式,您只需在“本地”中断处理程序中增加“全局”时间计数器即可。