简体   繁体   English

如何在AVR编程上激活16位定时器

[英]how to activate 16bit timer on AVR programming

I have an atmega168a chip. 我有一个atmega168a芯片。 I use Counter 0 to toggle PORTC by using ISR(TIMER0_COMPA_vect) and ISR(TIMERB_COMPA_vect) interrupt sub-routines. 我使用Counter 0通过使用ISR(TIMER0_COMPA_vect)ISR(TIMERB_COMPA_vect)中断子程序来切换PORTC I would like to activate the 16-bit timer when if condition is true. if条件为真,我想激活16-bit timer So, I use TIMSK1 = (1<<OCIE1A) , but this line calls ISR(TIMER1_COMPA_vect) interrupt instantly where I want 16 bit timer to be interrupted only when the counter reaches to OCR1A value. 因此,我使用TIMSK1 = (1<<OCIE1A) ,但此行立即调用ISR(TIMER1_COMPA_vect)中断,我希望只有当计数器reaches OCR1A值时才会中断16位定时器。 How can I activate the 16-bit timer on the run-time without causing an instant interrupt? 如何在运行时激活16位定时器而不会导致瞬间中断?

here is my code: 这是我的代码:

#define F_CPU 8000000
#include <avr/io.h>
#include <avr/interrupt.h>
#include <stdint.h>

volatile uint8_t counter;

int main (void){
    DDRC = 0xFF;  //sets PORTC as output
    PORTC = 0xFF; //initial output value
    /*COUNTER0 settings*/
    TIMSK0 = ((1<<OCIE0A) | (1<<OCIE0B));  // Enable Interrupt TimerCounter0 Compare Match A & B
    TCCR0A = (1<<WGM01);  // Mode = CTC
    TCCR0B = (1<<CS01) | (1<<CS00);   // Clock/64, 1/(8000000/64)= 0.000008 seconds per tick
    OCR0A = 200;      //   0.000008 *230 = 1.6 ms
    OCR0B = 100;      //     0.8 ms

    /*16bit timer - counter1 settings*/
    TIMSK1 &= ~(1<<OCIE1A); // Disable Interrupt Counter 1, output compare A (TIMER1_CMPA_vect)
    TCCR1B = ((1<<CS12) | (1<<CS10) | (1<<WGM12));    // Clock/1024, 1/(8000000/1024) = 0.000128 seconds per tick, Mode=CTC
    OCR1A = 40;                       // 0.000128*40 ~= 5.12 milliseconds

    sei(); //interrupts are globally switched on
    counter =0;
    while(1){
        if(counter >= 4){
            TCNT1 = 0; // clear the counter 1
            TIMSK1 = (1<<OCIE1A);// Enables the interrupt for Counter 1,(TIMER1_CMPA_vect)
            TIMSK0 &= ~((1<<OCIE0A) | (1<<OCIE0B)); //disables the Counter 0's interrupts
            counter = 0;
        }
    }
    return 0;
}

ISR(TIMER0_COMPA_vect){ //1.6ms
    PORTC = 0xFF;
    counter++;
}

ISR(TIMER0_COMPB_vect){  //0.8 ms
    PORTC = ~PORTC;
}

ISR(TIMER1_COMPA_vect){ // 5.2 milisecond interrupt
    PORTC = 0x00;
    TCNT0 = 0; //clear the counter of counter0
//  TIMSK0 = ((1<<OCIE0A) | (1<<OCIE0B)); //Enable the Counter 0 interrupts
//  TIMSK1 &= ~(1<<OCIE1A);// Disable Interrupt Counter 1, output compare A (TIMER1_CMPA_vect)
}

here is an oscilloscope output that shows why I don't want the interrupt to be set instantly, because it set the signal 0 instantly. 这是一个示波器输出,显示为什么我不希望立即设置中断,因为它立即设置信号0。 在此输入图像描述

I think the problem might be that in CTC mode, interrupt is generated when OCF1A flag is set (in TIFR ). 我认为问题可能是在CTC模式下,当设置OCF1A标志时(在TIFR )会产生中断。 Since your timer is always running, just not generating interrupts, it sets OCF1A flag, which never gets cleared. 由于您的定时器始终在运行,只是没有产生中断,因此它会设置OCF1A标志,该标志永远不会被清除。 On page 142 in the datasheet it says: 在数据表的第142页上,它说:

OCF1B is automatically cleared when the Output Compare Match B Interrupt Vector is executed. 执行输出比较匹配B中断向量时,OCF1B自动清零。 Alternatively, OCF1B can be cleared by writing a logic one to its bit location. 或者,可以通过将逻辑1写入其位位置来清除OCF1B。

This means that when you set up timer 1, you also need to clear OCF1A : 这意味着当您设置计时器1时,您还需要清除OCF1A

TIFR1 &= ~(1<<OCF1A)

However, I think you can do better. 但是,我认为你可以做得更好。 You could just stop the timer when not needed, and start it when you do, instead of twiddling the TIMSK and having timer 1 run always. 您可以在不需要时停止计时器,并在执行时启动计时器,而不是整理TIMSK并始终运行计时器1。 If you set TCCR1B to zero, that clears CS12 , CS11 , and CS10 , which, according to the datasheet means "Timer stopped." 如果将TCCR1B设置为零,则清除CS12CS11CS10 ,根据数据表显示“定时器已停止”。 Then, when your counter reaches 4 you can turn on timer1 as you have it above: 然后,当你的计数器达到4时,你可以打开上面的计时器1:

TCCR1B = ((1<<CS12) | (1<<CS10) | (1<<WGM12));

If you do this, you shouldn't need to turn timer 1 interrupts on and off: just leave them on, and only turn the counting on when you need it. 如果这样做,你不需要打开和关闭定时器1中断:只需打开它们,只在你需要时打开计数器。

Also I am wondering if it is actually necessary to fire off two interrupts to toggle pins on PORTC ? 另外,我想知道是否真的有必要在PORTC上触发两个中断来切换引脚? Are you not using PWM for that because it doesn't give you the pulse lengths precisely enough? 你没有使用PWM,因为它没有给你足够的脉冲长度吗?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM