Прерывание режима CTC Arduino Uno не срабатывает

Я пытаюсь сгенерировать мигание светодиода через 4 секунды с помощью прерывания, но прерывание не срабатывает ни разу. Просьба: если у вас есть arduino uno r3, пожалуйста, проверьте на своем конце и сообщите мне результат. Я несколько раз читал раздел счетчика таймера и применял все, что мог, например: -

  • Включено глобальное прерывание
  • Выберите режим CTC
  • Включить прерывание для OCIE0A
  • Предварительное масштабирование до clk/1024
  • Инициализация OCR0A
  • Когда OCR0A равен TCNT0, генерируется прерывание
int var;
void setup() {
  // поместите сюда код установки для однократного запуска:
    SREG = SREG | (1<<7);          // Глобальное прерывание разрешено
    TCCR0A = TCCR0A | (1<<WGM01); // Очистить счетчик в режиме сравнения совпадений
    OCR0A = 255; // при равенстве TCNT будет сгенерировано прерывание OCR0
    TIMSK0 = TIMSK0 | (1<<OCIE0A); // Сравнение выходных данных соответствует разрешению прерывания
    TCCR0B = TCCR0B | (1<<CS01) | (1<<CS02);  // Предварительное масштабирование на 1024
    DDRB = DDRB | (1<<5); 
    Serial.begin(9600);      // Тестирование
    Serial.println("Start");   // Тестирование
}

void loop() {
  // поместите сюда ваш основной код для многократного запуска:

}

ISR(TIMER0_COMPA_vect){
    var++;
    Serial.print(var); // Тестирование
    volatile long unsigned i;
    if(var == 246){
        PORTB = PORTB | (1<<5);
        for(i=0; i<30000; i++);
        PORTB = PORTB & ~(1<<5);
        for(i=0; i<30000; i++);
        var=0; 
    }
}
  • часы 16 00 00 00 Гц
  • Предварительное масштабирование на 1024 = 15 625
  • 1 тик = 1/15625 = 0,00 00 64 сек.
  • OCR0 инициализируется значением 255.
  • TCNT0 — 255
  • Общее время, необходимое для генерации одного прерывания = 255 * 0,00 00 64 = 0,01632 сек., что означает, что через каждые 0,01632 сек. прерывание должно генерироваться
  • Сколько прерываний требуется для генерации светодиода через 4 секунды => 4/0,01632 = 246

Обновить рабочий код

int var;
void setup() {
  // поместите сюда код установки для однократного запуска:
  SREG = SREG | (1<<7);          // Глобальное прерывание разрешено
  TCCR0A =(1<<WGM01); // Очистить счетчик в режиме сравнения совпадений
  OCR0A = 255; // при равенстве TCNT будет сгенерировано прерывание OCR0
  TIMSK0 = (1<<OCIE0A); // Сравнение выходных данных соответствует разрешению прерывания
  TCCR0B = (1<<CS00) | (1<<CS02);  // Предварительное масштабирование на 1024


  DDRB = DDRB | (1<<5); 

    Serial.begin(9600);      // Инициализируем USART
    Serial.println("Start");   // Пишем приветственное сообщение

}

void loop() {
  // поместите сюда ваш основной код для многократного запуска:

}

ISR(TIMER0_COMPA_vect){
  var++;
 // Serial.print(var);
  volatile long unsigned i;
  if(var == 246){
        PORTB = PORTB | (1<<5);
        for(i=0; i<300000; i++);
        PORTB = PORTB & ~(1<<5);
        var=0; 
  }
}

, 👍0


1 ответ


Лучший ответ:

0

Есть несколько проблем с вашим кодом:

Во-первых, вы должны полностью перезаписать регистры управления таймером. вместо изменения отдельных битов. Например, когда вы пишете

TCCR0A = TCCR0A | (1<<WGM01); // Очистить счетчик в режиме сравнения совпадений

Вы получаете режим таймера, являющийся результатом комбинации биты, которые уже были установлены там, и те, которые вы устанавливаете. Судейство из комментария вы предполагаете, что это будет режим СТС, но это не разрешено, потому что процедура инициализации Arduino уже установила некоторые бит в этом регистре. Поскольку вы берете таймер за свой собственный использования, просто перезапишите все регистры управления:

TCCR0A = (1<<WGM01); // Очистить счетчик в режиме сравнения совпадений

то же самое для TCCR0B и TIMSK0.

Вторая проблема заключается в том, что вы неправильно прочитали «Clock Select Bit». Описание» из таблицы данных. Ваш таймер отсчитывается от внешний источник синхронизации на выводе T0. видимо у тебя ничего нет подключен туда, поэтому таймер не увеличивается. Вы, вероятно, имели в виду

TCCR0B = (1<<CS00) | (1<<CS02);  // Предварительное масштабирование на 1024

Небольшая проблема — цикл задержки. Программа будет проще понять, если вы вместо этого используете правильную функцию задержки. Ардуино delay() не будет работать, так как вы перенастроили Таймер 0, но вы можете используйте _delay_ms() из avr-libc, если вы #include <util/delay.h>.

,

Большое спасибо, вы правы, я скучаю по битам предварительного масштабирования. мой код работает сейчас, @user143252