Как заставить встроенный светодиод мигать с частотой 5 Гц с помощью прерываний

Задача такая: после пяти нажатий на ОК встроенный светодиод начинает мигать с частотой 5Гц с использованием прерывания. После восьмого нажатия на ОК мигание (и свечение) должно прекратиться. Почему не работает мигание

bool ledState = false;
volatile bool ledOn = true;

void setup(){
TCCR2A = 0;
  TCCR2B = 0;
  TIMSK2 = 0;
  TCNT2 = 0;
  OCR2A = 77;
  TCCR2B |= (1 << CS22) | (1 << CS21) | (1 << CS20);
  TIMSK2 |= (1 << OCIE2A);
 pinMode(13, OUTPUT);
}

void loop(){
 if(button5.buttonPressedCount >= 5 && button5.buttonPressedCount < 8){
    ledState = true;
  }

  if(button5.buttonPressedCount > 7){
    ledState = false;
  }
}

ISR(TIMER2_COMPA_vect){
  if(ledState){
  digitalWrite(13, ledOn);
  ledOn = !ledOn;
  }
}

, 👍1

Обсуждение

Почему OCR2A = 77;?, @Edgar Bonet

Значение для получения частоты 5 Гц с делителем 1024, @Good York

Не могли бы вы объяснить в вопросе, как вы переходите от «f = 5 Гц» к «OCR2A = 77»?, @Edgar Bonet

таймер будет работать на частоте 16 МГц / 1024 = 15,625 кГц, поэтому желаемая частота прерывания = (77 + 1) * 15,625 кГц / 1024 = 5 Гц, @Good York

Этот расчет неверен., @Edgar Bonet

тогда какие должны быть значения?, @Good York

15,625 кГц / 5 Гц = 3125. Поэтому я бы установил OCR2A на 3125. Значение 77 будет примерно 203 Гц., @chrisl

Я установил 3125, если это правильный сигнал: [ссылка](https://imgur.com/a/N4wQMrl), @Good York

Не могли бы вы использовать Таймер 1 вместо Таймера 2?, @Edgar Bonet

да могу, тогда какие значения ставить?, @Good York


1 ответ


2

На Uno (микроконтроллер ATmega328P) таймеры 0 и 2 только 8-битные: они не могут считать больше 255. Таймер 1, с другой стороны, 16-битный. Это самый удобный таймер для генерации низких частот.

Кстати, о частотах... Один период светодиода включает два переключателя (включить, затем выключите). Таким образом, если вы хотите, чтобы светодиод мигал с частотой 5 Гц, переключатель действие должно происходить на частоте 10 Гц. Учитывая, что процессор работает на частоте 16 МГц, это означает, что вы должны переключать светодиод каждые 1 600 000 циклов процессора.

Если вы установите для предварительного делителя значение 1024, вам придется считать 1 600 000/1 024 = 1 562,5 цикла таймера. Вы не можете считать нецелое число кол-во тактов, но вас наверное не волнует такая точность. Если вам не все равно, установите прескалер на 256 и посчитайте 1 600 000/256 = 6250 циклов таймера, установив для регистра соответствия сравнения значение 6249.

И последнее: имейте в виду, что в обычном режиме подсчета таймер считает до своего максимального значения (65 535 или 255 на 8-битном таймере) и затем перезагружается с нуля. Если вы хотите, чтобы он подсчитывал только значение, установленное в регистр соответствия сравнения, вы должны выбрать соответствующую форму волны режим генерации: быстрый режим PWM, который позволяет вам контролировать значение TOP с OCR1A.

,

тогда это должно выглядеть так? TCCR1A = 0; TCCR1B = 0; ТИМСК1 = 0; ТЦНТ1 = 0; ОКР1А = 6249; // Установить значение совпадения сравнения для прескалера 256 TCCR1B |= (1 << CS12); // Установить прескалер на 256 TIMSK1 |= (1 << OCIE1A); // Разрешить прерывание при сравнении соответствия A, @Good York

@GoodYork: прочитайте техническое описание и узнайте, как установить соответствующий режим генерации сигналов., @Edgar Bonet

примерно так: TCCR1A = (1 << WGM11) | (1 << COM1A0); TCCR1B = (1 << WGM12) | (1 << WGM13) | (1 << CS12); TIMSK1 = (1 << OCIE1A); OCR1A = 6250;, @Good York