Настройка таймера ATMega328p (Arduino)

Я пытаюсь измерить мощность переменного тока с помощью Arduino с Atmega328p. Вкратце, я хочу использовать timer1 для создания прерывания каждые 400us, где я измеряю два канала АЦП (A0 и A1) и помещаю их в массив. Проблема в том, что вместо измерения пяти периодов сети (частота сети = 50 Гц, то есть 20 мс * 5), я получаю вместо этого 13 таких периодов (260 мс). Что я делаю не так?

volatile int sample_incremental = 0;

void setup() {
      Serial.begin(115200);
      pinMode(voltagePin, INPUT);
      pinMode(currentPin, INPUT);
      set_sample_interrupt();
      sei();
    }

void set_sample_interrupt() {
  //Считаем до 400us
  OCR1A = 99;
  //Режим 4, CTC
  TCCR1B |= (1 << WGM12);
  //Включить прерывание
  TIMSK1 |= (1 << OCIE1A);
  //Предделитель 64
  TCCR1B |= (1 << CS11) | (1 << CS10);
}

ISR (TIMER1_COMPA_vect) {
  // действие, которое будет выполняться каждые 400 мкс
  current_sample[sample_incremental] = analogRead(currentPin) - 504;
  voltage_sample[sample_incremental] = analogRead(voltagePin) - 512;
  if (sample_incremental < (SAMPLES * PERIODREADS))
    sample_incremental++;
  else {
    //Отключить прерывание
    TIMSK1 &= ~(1 << OCIE1A);
    sample_incremental = 0;
    finishedReading = true;
  }
}

Где после того, как я сделаю одно чтение, я останавливаю прерывание, и SAMPLES * PERIODREADS = 250.

, 👍1

Обсуждение

пожалуйста, опубликуйте график того, что вы ожидаете, и того, что вы фактически получаете, @jsotola


1 ответ


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

1

Библиотека ядра Arduino настраивает Таймер 1 для корректной по фазе ШИМ на около 490 Гц. Затем вы устанавливаете некоторые биты конфигурации в регистры управления таймером без очистки ранее хранившихся битов установлен ядром Arduino. Если вы хотите использовать таймер для своих собственных целей, и настроить его самостоятельно, вы должны полностью перезаписать конфигурации ядра на свою собственную. Для этого используйте оператор = а не |=, как в:

OCR1A  = 99;                         //Считаем до 400us
TIMSK1 = (1 << OCIE1A);              //Включить прерывание
TCCR1A = 0;
TCCR1B = (1 << WGM12)                //Режим 4, CTC
       | (1 << CS11) | (1 << CS10);  //Предделитель 64
,