AVR 定时器和硬件中断
AVR Timer and Hardware interrupts
我尝试在第一次检测到硬件中断检测的下降沿时激活定时器,并在运行 8 次后停用定时器。但是当我停止定时器时,硬件中断再次触发并立即启动定时器。
图中蓝色信号可以忽略。紫色信号是 timer1 切换引脚。绿色是硬件中断切换引脚。
它所要做的就是在第一个下降沿触发,然后在一段时间内切换一个引脚。
我的问题是:为什么硬件中断会触发两次?
#define F_CPU 16000000UL
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
volatile int cnt = 0;
uint8_t data[8];
int main(void)
{
// TIMER 1
DDRB |= (1 << PORTB0); // Set LED as output
DDRB |= (1 << PORTB1); // Set LED as output
DDRB |= (1 << PORTB2); // Set LED as output
DDRD &= ~(1 << PORTD2); // Set LED as INPUT
PORTD |= (1 << PORTD2); // PULLUP resistor
TCCR1B |= (1 << WGM12); // Configure timer 1 for CTC mode
TIMSK1 &= ~(1 << OCIE1A); // Disable CTC interrupt
//TIMSK1 |= (1 << OCIE1A); // Enable CTC interrupt
OCR1A = 1200; // Set CTC compare value to 15873Hz at 16MHz AVR clock, with a prescaler of 1
//TCNT0 = 0;
TCCR1B |= ((1 << CS10)); // Start timer at Fcpu/1
// Interrupt
EICRA |= (1 << ISC01) | (1 << ISC11); //ENABLE INT0 and INT1 ON falling EDGE
EIMSK |= (1 << INT0); //ENABLE INT0
EIMSK |= (1 << INT1); //ENABLE INT0
sei(); // Enable global interrupts
while (1)
{
}
}
ISR(TIMER1_COMPA_vect)
{
cnt = cnt + 1;
PORTB ^= (1 << PORTB0); // D8
if (cnt > 7)
{
TIMSK1 &= ~(1 << OCIE1A); // stop CTC interrupt
EIMSK |= (1 << INT0); //Enable INT0
EIMSK |= (1 << INT1); //Enable INT0
return;
}
}
ISR(INT0_vect) //External interrupt_zero ISR
{
EIMSK &= ~(1 << INT0); //Disable INT0
PORTB ^= (1 << PORTB2); // Toggle the LED
TCNT1 = 0;
cnt = 0;
TIMSK1 |= (1 << OCIE1A); // Enable CTC interrupt
}
ISR(INT1_vect) //External interrupt_zero ISR
{
PORTB ^= (1 << PORTB2); // Toggle the LED
EIMSK &= ~(1 << INT1); //Disable INT0
TCNT1 = 0;
cnt = 0;
TIMSK1 |= (1 << OCIE1A); // Enable CTC interrupt
}
即使禁用它,下降沿也会设置中断标志。这称为“挂起”中断。一旦中断被启用,它的服务例程就会被调用(前提是满足所有其他启用条件)。
您需要在启用中断之前清除此挂起标志。
我尝试在第一次检测到硬件中断检测的下降沿时激活定时器,并在运行 8 次后停用定时器。但是当我停止定时器时,硬件中断再次触发并立即启动定时器。
图中蓝色信号可以忽略。紫色信号是 timer1 切换引脚。绿色是硬件中断切换引脚。
它所要做的就是在第一个下降沿触发,然后在一段时间内切换一个引脚。
我的问题是:为什么硬件中断会触发两次?
#define F_CPU 16000000UL
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
volatile int cnt = 0;
uint8_t data[8];
int main(void)
{
// TIMER 1
DDRB |= (1 << PORTB0); // Set LED as output
DDRB |= (1 << PORTB1); // Set LED as output
DDRB |= (1 << PORTB2); // Set LED as output
DDRD &= ~(1 << PORTD2); // Set LED as INPUT
PORTD |= (1 << PORTD2); // PULLUP resistor
TCCR1B |= (1 << WGM12); // Configure timer 1 for CTC mode
TIMSK1 &= ~(1 << OCIE1A); // Disable CTC interrupt
//TIMSK1 |= (1 << OCIE1A); // Enable CTC interrupt
OCR1A = 1200; // Set CTC compare value to 15873Hz at 16MHz AVR clock, with a prescaler of 1
//TCNT0 = 0;
TCCR1B |= ((1 << CS10)); // Start timer at Fcpu/1
// Interrupt
EICRA |= (1 << ISC01) | (1 << ISC11); //ENABLE INT0 and INT1 ON falling EDGE
EIMSK |= (1 << INT0); //ENABLE INT0
EIMSK |= (1 << INT1); //ENABLE INT0
sei(); // Enable global interrupts
while (1)
{
}
}
ISR(TIMER1_COMPA_vect)
{
cnt = cnt + 1;
PORTB ^= (1 << PORTB0); // D8
if (cnt > 7)
{
TIMSK1 &= ~(1 << OCIE1A); // stop CTC interrupt
EIMSK |= (1 << INT0); //Enable INT0
EIMSK |= (1 << INT1); //Enable INT0
return;
}
}
ISR(INT0_vect) //External interrupt_zero ISR
{
EIMSK &= ~(1 << INT0); //Disable INT0
PORTB ^= (1 << PORTB2); // Toggle the LED
TCNT1 = 0;
cnt = 0;
TIMSK1 |= (1 << OCIE1A); // Enable CTC interrupt
}
ISR(INT1_vect) //External interrupt_zero ISR
{
PORTB ^= (1 << PORTB2); // Toggle the LED
EIMSK &= ~(1 << INT1); //Disable INT0
TCNT1 = 0;
cnt = 0;
TIMSK1 |= (1 << OCIE1A); // Enable CTC interrupt
}
即使禁用它,下降沿也会设置中断标志。这称为“挂起”中断。一旦中断被启用,它的服务例程就会被调用(前提是满足所有其他启用条件)。
您需要在启用中断之前清除此挂起标志。