Atmega328p обрабатывает только один ISR - PullRequest
0 голосов
/ 17 июня 2020

Я пытаюсь запустить две функции «одновременно» через прерывания:
1) Измерьте AD C по таймеру таймера 0 (100 Гц) и покажите результаты на контакте 0-5
2) Мигает светодиод через таймер 1 (10 Гц) на выводе 6.

Проблема, похоже, в том, что ISR таймера 1 блокирует функцию, поэтому больше ничего не выполняется. Вот код:
(Пожалуйста, не обижайтесь на ошибки стиля, код находится в стадии разработки)

#define F_CPU 16000000UL // 16MHz Clock speed 
#include <avr/io.h>
#include <avr/interrupt.h>

void ADC_init(void);
void SetTimer0(void);
void SetTimer1(void);

int main(void)
{
    DDRB |= (1<<DDB0) + (1<<DDB1) + (1<<DDB2) + (1<<DDB3) + (1<<DDB4) + (1<<DDB5) + (1<<DDB6);
    PORTB = 0b00000000;
    DDRB &= ~(1<<DDB7);

    ADC_init();
    SetTimer0();
    SetTimer1();

    while(1){
    }
}

void ADC_init(void)
{
    cli();
    // Select Vref=AVcc
    // and set left adjust result
    // select pin ADC0 (PC0)
    ADMUX |= (1<<REFS0)|(1<<ADLAR);

    //and enable ADC
    //enable ADC interupt   
    //enable autotriggering 
    //set prescaller to 128
    ADCSRA |= (1<<ADEN) | (1<<ADATE) | (1<<ADIE) | (1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0);

    //set ADC trigger source - Timer0 compare match A
    ADCSRB |= (1<<ADTS1)|(1<<ADTS0);

    // StartADC
    ADCSRA |= (1<<ADSC); 

    sei();
}

//initialize timer0 match A on 100hz
void SetTimer0(void)
{   
    cli();
    TCCR0A = 0; // set entire TCCR0A register to 0
    TCCR0B = 0; // same for TCCR0B
    TCNT0  = 0; // initialize counter value to 0
    // set compare match register for 100Hz increments
    OCR0A = 155; // = 16000000 / (1024 * 100.16025641025641)-1
    // toggle PD6/OC0A pin on compare match
    TCCR0A |=(1<<COM0A0)|(1<<WGM01);    
    //Set CTC mode
    TCCR0B |= (1 << WGM01);
    // Set CS02, CS01 and CS00 bits for 1024 prescaler
    TCCR0B |= (1 << CS02) | (0 << CS01) | (1 << CS00);
    // enable timer compare interrupt
    TIMSK0 |= (1 << OCIE0A);
    sei();
}

//initialize timer1 10hz
void SetTimer1(void){
    cli();
    TCCR1A = 0; // set entire TCCR1A register to 0
    TCCR1B = 0; // same for TCCR1B
    TCNT1  = 0; // initialize counter value to 0
    // set compare match register for 10 Hz increments
    OCR1A = 24999; // = 16000000 / (64 * 10) - 1 (must be <65536)
    // turn on CTC mode
    TCCR1B |= (1 << WGM12);
    // Set CS12, CS11 and CS10 bits for 64 prescaler
    TCCR1B |= (0 << CS12) | (1 << CS11) | (1 << CS10);
    // enable timer compare interrupt
    TIMSK1 |= (1 << OCIE1A);
    sei();
}

// ADC done interrupt
ISR(ADC_vect)
{
    // Clear timer compare match flag
    TIFR0=(1<<OCF0A);

    // save ADC measurement
    uint16_t val = ADC;

    // show ADC results
    if (val < 100)
    { PORTB = 0b00000000; }
    else if (val < 300)
    { PORTB = 0b00000001; }
    else if (val < 550)
    { PORTB = 0b00000011; }
    else if (val < 850)
    { PORTB = 0b00000111; }
    else if (val < 1020)
    { PORTB = 0b00001111; }
    else 
    { PORTB = 0b00011111; }

}


ISR(TIMER1_COMPA_vect)
{
    //PORTB ^= PINB5;
    static uint16_t on = 0;
    if (on == 1){
        PORTB = 0b00100000;
        on = 0;
    }
    else {
        PORTB = 0b00000000;
        on = 1;
    }
}

Когда функция SetTimer1() отключена, DCA работает должным образом. Таким образом, по отдельности оба ISR работают нормально, но вместе - нет. Может ли кто-нибудь помочь мне решить эту проблему?

1 Ответ

0 голосов
/ 18 июня 2020

У вас разрешено прерывание сравнения выходов для Timer0:

// enable timer compare interrupt
TIMSK0 |= (1 << OCIE0A);

, но нет обработчика ISR для этого прерывания.

По умолчанию обработчик __ bad_interrupt просто выполняет переход к нулевому вектору прерывания, то есть перезапускает программу.

Это означает, что если у вас включено прерывание, для этого должна быть ISR прерывание.

...