首页 > 解决方案 > AVR Timer and Hardware interrupts

问题描述

I try to activate a timer at the first detection on falling edge of hardware interrupt detection and to deactivate the timer after 8 runs. But when I stop the timer, the hardware interrupt triggers again and starts the timer immediately.

In the image you can ignore the blue signal. The purple signal is timer1 toggling the pin. Green is hardware interrupt toggling the pin.

All it has to do is trigger at the first falling edge, then toggling a pin in a period of time.

My question is: why does hardware interrupts trigger twice?

Signals

#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
}

标签: cinterruptavratmel

解决方案


即使您禁用它,下降沿也会设置中断标志。这称为“未决”中断。一旦启用中断,就会调用其服务程序(假设满足所有其他启用条件)。

您需要在启用中断之前清除此挂起标志。


推荐阅读