Частотомер на микроконтроллере

   Введение

  В одной из предыдущих статей, посвященных изучению микроконтроллеров AVR, на примере проекта частотомера мы рассмотрели использование 16-ти разрядного таймера/счетчика Т1 и прерывания по событию захват. В качестве дополнения к этому материалу, предлагаю улучшенную версию частотомера. В этом проекте тоже используется блок захвата и дополнительно еще задействован тактовый вход 8-ми разрядного таймера. 
    Недостатки старого проекта заключались в маленьком диапазоне измеряемых частот (~сотни киллогерц), что было связано со способом измерения периода сигнала. 
   Вы, наверное, помните, что в прерывании по событию захват счетный  регистр 16-ти разрядного таймера обнулялся, а захваченное значение, соответствующее количеству импульсов тактового генератора микроконтроллера, укладывающихся в один период входного сигнала,  сохранялось в переменной. На основе этого значения и выполнялись расчеты. 
   При повышении частоты входного сигнала микроконтроллер не успевал обрабатывать прерывания, пропускал их, и показания частотомера начинали резко расходиться с действительностью.   
   В новом проекте вычисление частоты выполняется по нескольким периодам входного сигнала и без постоянного использования прерывания по событию захват. Это уменьшает накладные расходы микроконтроллера и позволяет измерять значительно большие частоты — в идеале до 1/2 Fcpu (частоты тактирования микроконтроллера). 
   Итак, перейдем к описанию нового проекта частотомера. 

   Схема


   Входной сигнал подается на вход схемы захвата таймера Т1 и счетный вход таймера Т0. Для того чтобы таймер Т0 тактировался от внешнего сигнала, он должен быть соответствующим образом настроен.  

   Структура проекта

   Проект состоит из 4-ех программных модулей. 
bcd.c – содержит функцию  для вывода двоичных чисел на дисплей 
timer.c – содержит функцию инициализации таймеров T0 и Т1, обработчики прерываний, функцию захвата значений счетных регистров таймеров и программных счетчиков и, наконец, функцию вычисления частоты. 
lcd_lib.c – это библиотека для работы с символьным дисплеем.
main.c -  основная программа.

   Метод измерения частоты

   Частота входного сигнала измеряется методом временных ворот. Суть метода заключается в подсчете количества импульсов измеряемого и опорного сигналов за определенный промежуток времени. 
   Для подсчета количества импульсов измеряемого сигнала используется счетный вход аппаратного таймера. В качестве опорного сигнала используется тактовый сигнал микроконтроллера.   
   Интервал времени, в течение которого выполняются подсчеты импульсов, отмеряется с помощью схемы захвата аппаратного таймера Т1 и программной задержки. 
   Формула для расчета частоты по методу временных ворот такая:
 
Fx = Fo * (M/N),
 
где Fx – частота входного сигнала, Fo – частота опорного сигнала, M – количество импульсов входного сигнала за время измерения, N – количество импульсов опорного сигнала за время измерения.

  Алгоритм программы

     В проекте используются два таймера — 8-ми разрядный таймер/счетчик Т0 и 16-ти разрядный Т1. Таймер T1 подсчитывает количество тактовых импульсов микроконтроллера (baseImp), укладывающихся в определенный временной интервал, а таймер Т0 считает импульсы измеряемого сигнала (mesurImp).
   Временной интервал, в течение которого выполняются подсчеты импульсов, порядка одной секунды. Поскольку за это время оба таймера успевают много раз переполнится, в программе используются дополнительные программные счетчики (timer0, timer1). Это 16-ти разрядные переменные, которые  инкрементируются в прерываниях таймеров Т0 и Т1. 
    Общий вид циклограммы работы таймеров представлен на рисунке ниже.

Циклограмма работы таймеров Т0 и Т1
 
Алгоритм программы выглядит следующим образом.
 
1. Выполняется инициализация таймеров и дисплея
2. Микроконтроллер ожидает установки флага схемы захвата таймера Т1, или, выражаясь простым языком, ловит передний фронт измеряемого сигнала. 
3. Дождавшись установки флага (момент Capture1 на рисунке), микроконтроллер сохраняет значения счетных регистров таймеров Т0 и Т1, а также значения программных счетчиков. 
4. Вызывается программная задержка длительностью в одну секунду. Оба таймера продолжают работать. 
5. По окончанию задержки микроконтроллер ожидает установки флага схемы захвата 
6. Дождавшись установки флага (момент Capture2 на рисунке), микроконтроллер сохраняет значения счетных регистров Т0 и Т1 и значения программных счетчиков. 
7. Вычисляется значение частоты и выводится на дисплей 
8. Возврат на шаг номер 2.
 
   Несколько слов о вычислении частоты. 
 Для расчета количества  импульсов опорного сигнала используется следующая формула. 
 
  //количество переполнений программного счетчика
  saveTimer12 = saveTimer12 – saveTimer11;
 
  //количество импульсов опорного сигнала
  baseImp = (icr12 + (unsigned long)saveTimer12*65536) – icr11;
 
где  saveTimer12, saveTimer11 — значение программного счетчика timer1 в моменты Capture2, Capture1 соответственно;   icr12,  icr12 — значение счетного регистра TCNT1 таймера Т1 в моменты Capture2, Capture1 соответственно; 65536 — емкость счетчика Т1
     
   Расчет количества импульсов входного сигнала выполняется по аналогичной формуле, только там емкость счетчика равна 256.
 
  saveTimer02 = saveTimer02 - saveTimer01;
  mesurImp = (tcnt02 + (unsigned  long)saveTimer02*256) — tcnt01;
 
   Расчет частоты входного сигнала производится по формуле:
 
  result = (16000000UL*(unsigned long long)mesurImp*10)/baseImp;
 
где 16000000 — тактовая частота микроконтроллера, а mesurImp и baseImp количество импульсов входного и опорного сигналов соответственно.
   Результат умножается на 10 для отображения одного знака после запятой. 
   
   Переменные  baseImp,  mesurImp и  result типа unsigned long. Для избежания переполнения переменных при выполнении операций умножения,  переменные приводятся к типам более высокой разрядности (unsigned long в первых двух формулах и unsigned long long в последней).  

  Частотомер на AVR – проекты

 
PS: С проектами для WinAVR и CodeVison у меня возникли некоторые проблемы. И  WinAVR и CodeVison неадекватно вели себя при использовании типа unsigned long long в формуле вычисления частоты. Не было времени разбираться в чем дело и я немного упростил формулу, пожертвовав точностью вычислений.

У вас недостаточно прав для комментирования.