Можно ли использовать Arduino Uno для измерения частоты прямоугольной волны до 600 кГц?

Я делаю проект с датчиком цвета, где выходной сигнал датчика цвета представляет собой прямоугольную волну ШИМ.

Чтобы измерить его частоту с помощью Arduino Uno, я использую функцию pulseIn(), но не могу получить правильный результат.

Может ли Arduino Uno измерять частоту до 600 кГц с помощью функции pulseIn()?

, 👍0

Обсуждение

Я не могу получить правильный результат... что это значит? ... какой результат вы получите?, @jsotola

Вы хотите измерить частоту или рабочий цикл?, @Nick Gammon


1 ответ


3

В документации для pulseIn указано, что его можно использовать для интервалов от 10 микросекунд до 3 минут.

600 кГц частота будет иметь интервал 1,6 микросекунды и поэтому не подходит для этого приложения. (1/600000 = 0,000001666).

У меня есть код на моей веб-странице о таймерах для скетча, который может измерять до 8 МГц только с 0,5% ошибка.

Этот код воспроизводится ниже:

// Пример таймера и счетчика
// Автор: Ник Гэммон
// Дата: 17 января 2012 г.

// Вход: контакт D5

// они проверяются в основной программе
volatile unsigned long timerCounts;
volatile boolean counterReady;

// внутри подпрограммы подсчета
unsigned long overflowCount;
unsigned int timerTicks;
unsigned int timerPeriod;

void startCounting (unsigned int ms) 
  {
  counterReady = false;         // время еще не истекло
  timerPeriod = ms;             // сколько 1 мс отсчитывает сделать
  timerTicks = 0;               // сброс счетчика прерываний
  overflowCount = 0;            // пока нет переполнения

  // сбросить Таймер 1 и Таймер 2
  TCCR1A = 0;             
  TCCR1B = 0;              
  TCCR2A = 0;
  TCCR2B = 0;

  // Таймер 1 - считает события на выводе D5
  TIMSK1 = bit (TOIE1);   // прерывание при переполнении Таймера 1

  // Таймер 2 - дает нам интервал счета в 1 мс
  // Тактовая частота 16 МГц (62,5 нс на тик) — предварительно масштабирована на 128
  // счетчик увеличивается каждые 8 мкс.
  // Итак, мы насчитали 125 из них, что дает ровно 1000 мкс (1 мс)
  TCCR2A = bit (WGM21) ;   // режим СТС
  OCR2A  = 124;            // считать до 125 (относительно нуля!!!!)

  // Таймер 2 - прерывание при совпадении (т.е. каждые 1 мс)
  TIMSK2 = bit (OCIE2A);   // включить прерывание от Таймера 2

  TCNT1 = 0;      // Оба счетчика обнулены
  TCNT2 = 0;     

  // Сброс предделителей
  GTCCR = bit (PSRASY);        // сбросить предварительный делитель сейчас
  // запускаем Таймер 2
  TCCR2B =  bit (CS20) | bit (CS22) ;  // прескалер 128
  // запускаем Таймер 1
  // Внешний источник синхронизации на выводе T1 (D5). Часы на переднем фронте.
  TCCR1B =  bit (CS10) | bit (CS11) | bit (CS12);
  }  // конец startCounting

ISR (TIMER1_OVF_vect)
  {
  ++overflowCount;               // подсчитываем количество переполнений Counter1
  }  // конец TIMER1_OVF_vect


//*************************************************** ******************
// Служба прерывания Таймера 2 вызывается аппаратным Таймером 2 каждые 1 мс = 1000 Гц
// 16 МГц / 128 / 125 = 1000 Гц

ISR (TIMER2_COMPA_vect) 
  {
  // получить значение счетчика до того, как оно изменится
  unsigned int timer1CounterValue;
  timer1CounterValue = TCNT1;  // см. техническое описание, стр. 117 (доступ к 16-битным регистрам)
  unsigned long overflowCopy = overflowCount;

  // смотрим, достигли ли мы периода времени
  if (++timerTicks < timerPeriod) 
    return;  // еще нет

  // если только что пропустили переполнение
  if ((TIFR1 & bit (TOV1)) && timer1CounterValue < 256)
    overflowCopy++;

  // конец времени стробирования, измерение готово

  TCCR1A = 0;    // остановить таймер 1
  TCCR1B = 0;    

  TCCR2A = 0;    // остановить таймер 2
  TCCR2B = 0;    

  TIMSK1 = 0;    // отключить прерывание от Таймера 1
  TIMSK2 = 0;    // отключить прерывание от Таймера 2
    
  // подсчитываем общее количество
  timerCounts = (overflowCopy << 16) + timer1CounterValue;  // каждое переполнение на 65536 больше
  counterReady = true;              // устанавливаем глобальный флаг для окончания периода счета
  }  // конец TIMER2_COMPA_vect

void setup () 
  {
  Serial.begin(115200);       
  Serial.println("Frequency Counter");
  } // конец настройки

void loop () 
  {
  // останавливаем прерывания Таймера 0 от сброса отсчета
  byte oldTCCR0A = TCCR0A;
  byte oldTCCR0B = TCCR0B;
  TCCR0A = 0;    // остановить таймер 0
  TCCR0B = 0;    
  
  startCounting (500);  // сколько мс считать

  while (!counterReady) 
     { }  // цикл до окончания счета

  // настроить счетчики по интервалу счета, чтобы получить частоту в Гц
  float frq = (timerCounts *  1000.0) / timerPeriod;

  Serial.print ("Frequency: ");
  Serial.print ((unsigned long) frq);
  Serial.println (" Hz.");
  
  // перезапустить таймер 0
  TCCR0A = oldTCCR0A;
  TCCR0B = oldTCCR0B;
  
  // давайте закончим работу с последовательным интерфейсом
  delay(200);
  }   // конец цикла

Может ли Arduino UNO измерять частоту до 600 кГц, если мы используем функцию pulseIn()?

Нет. Без использования pulseIn. Однако см. приведенный выше код для измерения такой частоты.

,