Как использовать Timer1 (AT328Mega) для измерения времени между восходящими фронтами двух входных сигналов

Я хотел бы использовать Timer1 для измерения времени между восходящими фронтами двух входных сигналов. В частности, используйте Tn для запуска счетчика таймера и IPCn для фиксации времени, прошедшего с момента нарастающего фронта входного сигнала Tn. Цель состоит в том, чтобы измерить время между восходящими фронтами двух входных сигналов. Есть ли там библиотека Timer1, которая alread делает это? Предложения по коду приветствуются.

, 👍3

Обсуждение

Какова минимальная ожидаемая длительность между двумя последовательными восходящими фронтами вашего сигнала?, @jfpoilpret

`// ICNC1: Enable Input Capture Noise Canceler // ICES1: =1 for trigger on rising edge // CS10: =1 set prescaler to 1x system clock (F_CPU) TCR1A = 0; TCR1B = (0<, @mypgp


2 ответа


2

Это не идеально подходит для вашей более простой задачи, но вот ссылка на скетч, который я использовал для записи импульсов, используя захват ввода Timer1.

Короче говоря, настройте прерывание

void initTimer(void) {

  // ICNC1: Включить Шумоподавитель захвата ввода
  // ICES1: =1 для триггера на восходящей кромке
  // CS10: =1 установка прескалера на 1x системных часов (F_CPU)
  TCCR1A = 0;
  TCCR1B = (0<<ICNC1) | (0<<ICES1) | (1<<CS10);
  TCCR1C = 0;

  //catchFallingEdge(); // инициализируйте, чтобы поймать
  { TCCR1B &= ~(1<<ICES1); TIFR1 |= (1<<ICF1); rising = 0; }

  // Настройка прерывания
  // ICIE1: Захват ввода
  // TOIE1: Переполнение Timer1
  TIFR1 = (1<<ICF1) | (1<<TOV1);        // очистить очередь
  TIMSK1 = (1<<ICIE1) | (1<<TOIE1); // и задействовать

  // Настройте входной вывод захвата, ICP1, который соответствует PIN
  pinMode(8, INPUT);
  digitalWrite(8, 0);       // оставьте плавающим, чтобы считать 60 Гц и т. Д.
  //digitalWrite(8, 1); // или включите съемный пакет

Затем обслужите его

ISR(TIMER1_CAPT_vect) {
  union twobyte {
    uint32_t word;
    uint8_t  byte[2];
  } timevalue;

  timevalue.byte[0] = ICR1L;        // захватить захваченное значение таймера
  timevalue.byte[1] = ICR1H;        // захватить захваченное значение таймера

  // следите за другим краем, чтобы уловить ширину полуимпульса
  //rising ? catchFallingEdge() : catchRisingEdge();
  if (rising) {
    TCCR1B &= ~(1<<ICES1);
    TIFR1 |= (1<<ICF1);
    rising = 0;
  }
  else {
    TCCR1B |= (1<<ICES1);
    TIFR1 |= (1<<ICF1);
    rising = 1;
  }
}
,

0

Для получения дополнительной помощи и информации, а также многих примеров различных подробных аспектов таймеров, ознакомьтесь со статьями Ника Гэммона здесь: http://www.gammon.com.au/interrupts и вот здесь: http://www.gammon.com.au/timers

По первой ссылке выполните поиск "Скетча ниже, умножающего интервалы между прерываниями ПОДЪЕМА", например, чтобы найти один сегмент кода.

Теперь важный вопрос: каково минимальное время, которое вам нужно измерить между событиями? Мы говорим о миллисекундах, микросекундах или наносекундах? В первом случае вы можете использовать опрос контактов, внешние прерывания или прерывания смены контактов, а также функции millis() или micros() Arduino для захвата временных меток. Для разрешения в микросекундах все зависит от обстоятельств. Даже функция micros() имеет разрешение только 4us, поэтому вам придется настроить таймер самостоятельно, если вы хотите получить метки времени с разрешением выше 4us, или вы можете использовать библиотеку timer2_counter (http://electricrcaircraftguy.blogspot.com/2014/02/Timer2Counter-more-precise-Arduino-micros-function.html) или ваше собственное решение по индивидуальному таймеру для временных меток с разрешением 0,5 мкс.

Для наносекундного разрешения (с временными шагами до 62,5 нс) вы можете. необходимо использовать захват ввода Timer1, как показано в другом ответе. Вы также можете выполнить поиск "Определение времени интервала с помощью блока захвата ввода" по 2-й ссылке выше, для другого сегмента кода в этом.

,