Прерывание переполнения таймера AVR не работает
Моя проблема — процедура обработки прерываний (ISR), которая, похоже, никогда не выполняется! Вот некоторая информация о моей настройке: Я прошиваю avr attiny85. На данный момент у меня есть скелет проекта, состоящий просто из main.c и двух модулей: timer и hardwareInit. В модуле таймера у меня есть функция timer0_init, которую я использую для настройки таймера 0 для режима CTC на переполнение каждые 1 мс. Вот функция:
void timer0_init( void )
{
cli();
TCCR0B |= 3; // выбор часов делится на 64.
TCCR0A |= 2; //устанавливаем режим CTC
OCR0A = 0x7C; //устанавливает TOP равным 124, поэтому таймер будет переполняться каждые 1 мс.
TIMSK |= 2; //Включаем прерывание переполнения
sei(); //включаем глобальные прерывания
}
После настройки таймера я добавил ISR для увеличения тиков каждый раз, когда счетчик переполняется, чтобы я мог отслеживать, сколько времени прошло и т. д.
ISR(TIMER0_OVF_vect)
{
cli();
//ticks ++;
PORTB |= ( 1 << PORTB0 );
sei();
}
как видите, я закомментировал галочки++, потому что они не работали, и заменил их на PORTB |= ( 1 << PORTB0 );
, который просто включает светодиод, поэтому, если прерывание когда-либо будет выполнено, я узнаю об этом по доказательству горящего светодиода.
К сожалению, я не могу его включить и не вижу, чего мне не хватает. (чтобы доказать, что у меня 1. установлен светодиод на правом контакте и 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(){
//Инициализируем оборудование ЗДЕСЬ
DDRB |= ( 1 << PORTB0 ); //устанавливаем этот вывод как выход для светодиода
SetClockPrescale(1); //внутренняя тактовая частота, деленная на 1 = 8 МГц, из hardwareInit
timer0_init(); //настраиваем таймер 0 на переполнение на 1 мс
while(1)
{
/* if( getTicks() > 0 )
{
PORTB |= ( 1 << PORTB0 );
_delay_ms(1000);
PORTB &= ~( 1 << PORTB0 );
_delay_ms(1000);
} */
}
return 0;
}
Итак, то, что вы видите в бесконечном цикле, это то, что я попробовал первым, но после того, как это не сработало, я попробовал что-то более простое, просто имея пустой цикл (закомментировав предыдущий материал) и ожидая прерывания, чтобы получить срабатывает, что включает светодиод.
Любая ваша помощь будет очень признательна. Я очень озадачен, почему это не сработало.
@chen, 👍1
Обсуждение1 ответ
Лучший ответ:
Вы не понимаете, что такое прерывание переполнения. Это происходит, когда таймер переполняется (т. е. достигает TOP, который в случае 8-битного таймера равен 255). Поскольку вы считаете до 124, этого никогда не произойдет, и, следовательно, прерывание не сработает.
Вы хотите «сравнить вектор A», который вызывается, когда регистр «A» сравнивается с пределом. Пример кода:
void timer0_init( void )
{
TCCR0B = bit (CS01) | bit (CS00); //выбор часов делится на 64.
TCCR0A = bit (WGM01); //устанавливает режим CTC
OCR0A = 0x7C; //что считать
TIMSK = bit (OCIE0A); //Включить прерывание сравнения совпадений A
}
ISR(TIMER0_COMPA_vect)
{
PINB = bit (PINB0); // переключить контакт 5
}
int main(){
DDRB |= bit (DDB0); //установить этот вывод как выход для светодиода
timer0_init(); //устанавливаем timer0 на переполнение в 1 мс
sei (); // разрешить прерывания
while(true) { } // навсегда
return 0;
}
Я изменил его на переключение контакта 5 (что происходит очень быстро), поэтому он будет казаться включенным, но немного тусклым. Вы можете увидеть на осциллографе или логическом анализаторе, что он переключается быстро.
Вам не нужно выключать или включать прерывания внутри ISR. Вам лучше использовать имена битов, а не «магические числа» в вашем коде, как показывает мой пример.
Также обратите внимание, как Ник изменил TCCR0B |=
на TCCR0B =
. Поскольку код arduino использует timer0 для millis
, TCCR0B
не является значением по умолчанию., @Gerben
Да, никогда не думайте, что вы знаете, какие значения содержатся в регистрах, если только вы не установили их самостоятельно., @Nick Gammon
Отлично! Я упустил суть режима CTC. Когда я установил OCR0A на 124, я думал, что поскольку TOP был изменен на 124, таймер переполнится, когда достигнет 124. Теперь мне ясно, что переполнение происходит только тогда, когда таймер достигает «истинного» максимума, в данном случае 255. Спасибо за помощь., @chen
@Gerben и Nick, можно ли предполагать значение регистров, когда я прошиваю сам attiny, отдельно от Arduino или чего-либо еще, что уже установило бы их? Я основывался на техническом описании attiny85, в котором показаны начальные значения каждого бита в каждом регистре: http://screencast.com/t/ry9FSpyWQt9, @chen
Вероятно, так и есть. Однако я не вижу смысла в "или", когда за меньшее (или то же) количество машинных циклов можно просто установить желаемое значение. Если вы назначаете, то определенно получаете то, что хотите, если "или", то вы просто надеетесь., @Nick Gammon
Обратите внимание, что переполнение происходит при попытке увеличения до 256, что приводит к 0. Кроме того, здесь вполне можно использовать фактическое прерывание переполнения, просто предварительно загружайте в TCNT0 разницу между TOP и желаемыми циклами каждый раз, когда происходит переполнение., @mystery
- PCINT0, PCINT1, PCINT2 и т. д. на ATtiny45/85
- Какие Arduino поддерживают ATOMIC_BLOCK?
- Как назначить прерывание на нажатие кнопки с помощью ATtiny? (прерывание не срабатывает с моим кодом)
- AVR (Arduino Uno) Serial.print и Serial.println печатают только 1 или 2 символа
- ATtiny85 AC Phase Control для регулировки яркости лампочки
- Как использовать прерывание в Arduino для получения данных с последовательного входа
- Attiny85 не распознается при запуске Windows
- Как обрабатывать одновременный HTTP-запрос при использовании прерывания
Все это не Ардуино., @Ignacio Vazquez-Abrams
cli()
иsei()
бесполезны в вашем ISR, поскольку прерывания автоматически отключаются при запуске ISR и снова включаются при возвращении., @jfpoilpret@jfpoilpret Спасибо! Мне сказали, что хорошей практикой является отключать, а затем снова включать прерывания в ISR, чтобы у вас не было прерываний, прерывающих ваш ISR. Можете ли вы указать мне источник, в котором говорится, что ISR делает это автоматически?, @chen
Попробуйте прокомментировать значение регистра OCR0, чтобы прерывание переполнения сработало. У меня это сработало., @Arvind Bhosle