我有一个atmega168a芯片。我使用Counter 0
来使用PORTC
和ISR(TIMER0_COMPA_vect)
中断子例程来切换ISR(TIMERB_COMPA_vect)
。当16-bit timer
条件为真时,我想激活if
。所以,我使用TIMSK1 = (1<<OCIE1A)
,但此行立即调用ISR(TIMER1_COMPA_vect)
中断,我希望16位定时器仅在计数器reaches
到OCR1A
值时被中断。如何在运行时激活16位定时器而不会导致瞬间中断?
这是我的代码:
#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)
}
这是一个示波器输出,显示为什么我不希望立即设置中断,因为它立即设置信号0。
答案 0 :(得分:2)
我认为问题可能是在CTC模式下,设置OCF1A
标志时会产生中断(在TIFR
中)。由于您的计时器始终在运行,只是不生成中断,因此它会设置OCF1A
标志,该标志永远不会被清除。在数据表的第142页上,它说:
输出比较匹配B时,OCF1B自动清零 执行中断向量。或者,可以清除OCF1B 将逻辑1写入其位位置。
这意味着当您设置计时器1时,您还需要清除OCF1A
:
TIFR1 &= ~(1<<OCF1A)
但是,我认为你可以做得更好。您可以在不需要时停止计时器,并在您执行时启动计时器,而不是使TIMSK
和使计时器1始终运行。如果您将TCCR1B
设置为零,则会清除CS12
,CS11
和CS10
,根据数据表,这意味着“计时器已停止”。然后,当你的计数器达到4时,你就可以打开timer1,如上所示:
TCCR1B = ((1<<CS12) | (1<<CS10) | (1<<WGM12));
如果你这样做,你不需要打开和关闭定时器1中断:只需打开它们,只在你需要时打开计数器。
另外,我想知道实际上是否有必要在PORTC
上触发两个中断来切换引脚?你没有使用PWM,因为它没有给你足够精确的脉冲长度吗?