2016-11-20 12 views
4

Привет, хорошие люди переполнения стека. Моя проблема - это процедура обслуживания прерываний (ISR), которая, по-видимому, никогда не выполняется! Вот некоторые сведения о моей настройке: Я сверкаю avr attiny85. У меня есть голые кости проекта, созданного до сих пор с помощью простого main.c и двух модулей: timer и hardwareInit. В модуле таймера у меня есть функция timer0_init, которую я использую для настройки таймера0 для режима CTC для переполнения всего 1 мс. Вот функция:Прерывание переполнения таймера AVR не работает

void timer0_init(void) 
{ 
    cli(); 
    TCCR0B |= 3; //clock select is divided by 64. 
    TCCR0A |= 2; //sets mode to CTC 
    OCR0A = 0x7C; //sets TOP to 124 so the timer will overflow every 1 ms.  
    TIMSK |= 2;  //Enable overflow interrupt 
    sei();   //enable global interrupts 
} 

с таймером установленным, я добавил ISR для увеличения клещей каждый раз, когда счетчик переполнения, так что я могу отслеживать, сколько времени прошло, и т.д.

ISR(TIMER0_OVF_vect) 
{ 
    cli(); 
    //ticks ++; 
    PORTB |= (1 << PORTB0); 
    sei(); 
} 

Как вы можете видеть, я прокомментировал тики ++, потому что он не работал, и заменил его на PORTB |= (1 << PORTB0);, который просто включает светодиод, поэтому, если прерывание выполняется, я узнаю, что светодиод включен.
К сожалению, я не могу заставить его включиться и не вижу, что мне не хватает. (чтобы доказать, что у I есть светодиод, установленный на правом штифте, и 2. я манипулирую правильным битом в правильном регистре, я поставил только это заявление PORTB |= (1 << PORTB0); в моем бесконечном цикле и подтвердил, что загорелся светодиод)

Для дальнейшего объяснения, вот мой main.c:

/*================================= main.c =================================*/ 

#define F_CPU 8000000UL 

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

#include "timer.h" 
#include "hardwareInit.h" 


int main(){ 

    //Initialize hardware HERE 
    DDRB |= (1 << PORTB0); //set this pin as an output for an LED 

    SetClockPrescale(1); //internal clock divided by 1 = 8 MHz, from hardwareInit 

    timer0_init();   //set up timer0 for 1 ms overflow 


    while(1) 
    { 
     /* if(getTicks() > 0) 
     { 
      PORTB |= (1 << PORTB0); 
      _delay_ms(1000); 
      PORTB &= ~(1 << PORTB0); 
      _delay_ms(1000); 
     } */ 

    } 
    return 0; 
} 

Итак, что вы видите в бесконечном цикле, что я попробовал первый, но после этого не работал, я пытался что-то более простое, просто имеющий пустую петлю (прокомментировал предыдущий материал) и ожидал, что прерывание начнет срабатывать, и включит светодиод.

Любая помощь, которую вы могли бы дать, была бы действительно оценена. Я очень озадачен, почему это не работает.

+2

Попробуйте изменить 'TIMSK | = 2,' в 'TIMSK | = (1 < <4); 'и' TIMER0_OVF_vect' - 'TIM0_COMPB_vect'. Однако никаких гарантий нет. – andars

+0

Альтернативно, оставьте инициализацию таймера тем же и просто попробуйте изменить вектор на 'TIM0_OVF_vect' – andars

ответ

8

Вы используете неправильный ISR, указав @andars правильно. В режиме CTC «Clear Timer on Compare» таймер никогда не будет переполняться, поскольку он будет очищен при сравнении.

Таким образом, вы включили неправильное прерывание таймера. Бит 1 регистра TIMSK позволяет прерывать переполнение таймера по таймеру0. Это не будет вызвано по предыдущей причине. Взято с datasheet.

enter image description here

Как вы используете OCR0A установить значение сравнения, вы должны включить Бит 4 - OCIE0A: Таймер/Counter0 Выход Сравнить Совпадение Interrupt Enable.

Назад к ISR, вам необходимо указать ISR(TIMER1_COMPA_vect) или ISR(TIMER1_COMPB_vect) в зависимости от того, какой бит вы установили в TIMSK. Обратите внимание, что значение сравнения должно быть записано в соответствующие регистры, OCR0A или OCR0B.


Обратите внимание, что, вы можете использовать битовые имена в коде так же, как имена регистров, на мой взгляд, это делает код более прозрачным.

Ваш код должен быть изменен следующим образом, чтобы включить соответствующее прерывание:

void timer0_init(void) 
{ 
    cli();   
    TCCR0B |= (1<<CS01) | (1<<CS00); //clock select is divided by 64. 
    TCCR0A |= (1<<WGM01);    //sets mode to CTC 
    OCR0A = 0x7C;      //sets TOP to 124 so the timer will overflow every 1 ms.  
    TIMSK |= (1<<OCIE0A);    //Output Compare Match A Interrupt Enable 
    sei();        //enable global interrupts 
} 

ИСР:

ISR(TIMER0_COMPA_vect) 
{ 
    cli(); 
    //ticks ++; 
    PORTB |= (1 << PORTB0); 
    sei(); 
} 
+1

Отлично! Мне не хватало точки режима CTC. Когда я установил OCR0A на 124, я подумал, что, поскольку TOP был изменен на 124, таймер переполнится. Теперь мне ясно, что переполнение происходит только тогда, когда таймер достигает «истинного» верха, в этом случае 255. Что касается других вещей, которые вы сказали, были неправы, позвольте мне прояснить это. Вы сказали: «Вы также включили неправильное прерывание неправильного таймера», но я этого не сделал. I ORed в регистре TIMSK со значением 2, которое в двоичном формате 00000010, эффективно устанавливая бит TOIE0 равным 1. Следующие строки эквивалентны: TIMSK | = 2; TIMSK | = (1 << TOIE0); – chen

+1

То же самое касается второй половины вашего ответа, где вы перечисляете несколько исправлений. «Бит 3 регистра не имеет ничего общего с делением часов». Я не устанавливал бит 3, я использовал ORing для всего регистра со значением 3 или 00000011, чтобы установить первые 2 бита (CS00 и CS01), чтобы получить деление на 64. То же самое для исправления 2. Я знаю, что это мой ошибочно для того, чтобы быть ленивым и смешивать мои обозначения между ORing со значением и ORing с битом, сдвинутым до имени бита. Извините за путаницу. Имеет ли это смысл? – chen

+0

Если вы пересмотрите свой ответ, чтобы исправить это, я отвечу и приму ваш ответ. Спасибо за вашу помощь! – chen

 Смежные вопросы

  • Нет связанных вопросов^_^