Установка флага не работает в моем прерывании по таймеру (пока прерывание работает)

Раньше я писал свои коды в ICCAVR, и у меня не было проблем, но по какой-то причине я не должен переходить на AtmelStudio. в следующем коде светодиод мигает в прерывании, но когда я устанавливаю только флаг в прерывании и хочу мигать светодиодом при опросе (с использованием флага), это не сработает:

#include<avr/io.h>
#include<avr/interrupt.h>

#define LED PA1


ISR (TIMER1_OVF_vect)    // Timer1 ISR
{
    //PORTA ^= (1 << LED);
    TCNT1 = 63974;   // for 1 sec at 16 MHz
    PORTA ^= (1 << LED);
}

int main()
{
    DDRA = (0x01 << LED);     //Configure the PORTD4 as output

    TCNT1 = 63974;   // for 1 sec at 16 MHz

    TCCR1A = 0x00;
    TCCR1B = (1<<CS10) | (1<<CS12);;  // Timer mode with 1024 prescler
    TIMSK = (1 << TOIE1) ;   // Enable timer1 overflow interrupt(TOIE1)
    sei();        // Enable global interrupts by setting global interrupt enable bit in SREG

    while(1)
    {

    }
}

в то время как это изменение заставит его не мигать:

#include<avr/io.h>
#include<avr/interrupt.h>

#define LED PA1

unsigned int counter=0;
unsigned char flag=0;

ISR (TIMER1_OVF_vect)    // Timer1 ISR
{
    //PORTA ^= (1 << LED);
    TCNT1 = 63974;   // for 1 sec at 16 MHz
    counter++;
    if(counter>=10)
    {
        flag=1;
        counter=0;
    }
}

int main()
{
    DDRA = (0x01 << LED);     //Configure the PORTD4 as output

    TCNT1 = 63974;   // for 1 sec at 16 MHz

    TCCR1A = 0x00;
    TCCR1B = (1<<CS10) | (1<<CS12);;  // Timer mode with 1024 prescler
    TIMSK = (1 << TOIE1) ;   // Enable timer1 overflow interrupt(TOIE1)
    sei();        // Enable global interrupts by setting global interrupt enable bit in SREG

    while(1)
    {
        if(flag)
        {
            flag=0;
            PORTA ^= (1 << LED);
        }
    }
}

может кто-нибудь мне помочь?


person Mahdi    schedule 08.02.2019    source источник


Ответы (1)


Компилятор увидел, что flag установлен в 0 в начале программы и не может знать, что переменная может быть изменена обработчиком прерывания (код никогда не вызывается непосредственно в программе). Таким образом, он оптимизировал flag проверку в while цикле.

Используйте квалификатор volatile для переменных, к которым осуществляется доступ из разных потоков кода (основной код и обработчик прерывания, разные потоки в многопоточной среде).

volatile unsigned char flag = 0;
person ReAl    schedule 09.02.2019