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

06/03/2011 - 19:00

   Введение

  В одной из предыдущих статей, посвященных изучению микроконтроллеров 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 в формуле вычисления частоты. Не было времени разбираться в чем дело и я немного упростил формулу, пожертвовав точностью вычислений.

Comments   

# Crafter76 2011-03-07 05:05
А вот и косяк будет в настоящем-то устройстве... Проблема в том, что частота - это случайный процесс, и померить ее без использования дисперсии - неправильно...
# Pashgan 2011-03-07 08:17
Материал носит обучающий характер. Мы не создаем здесь девайс на продажу.
Quote:
Проблема в том, что частота - это случайный процесс
Объясните популярно (или дайте ссылку) почему частота случайный процесс и где написано как ее правильно измерять.
# RA_DU_GA 2013-03-10 16:36
Человек видимо имел ввиду, что любое измерение есть процесс получения случайных величин :)
Так это уже второй вопрос - чем достовернее хочешь померить, тем просто большее количество измерений проводишь (получая децл разные результаты), сводишь в таблицу,
а там считаешь дисперсию и все прочее :)
# den3z 2012-11-17 08:12
частота это не процесс, а физ. величина.
# Crazy Synergetic 2011-03-07 05:25
А какова максимальная измеряемая частота???? Мне из этого поста сие совсем не ясно...
P.S. Конечно хотелось бы еще узнать какова максимальная частота измерений на практике:)))
# Pashgan 2011-03-07 08:07
Читаем внимательно
Quote:
в идеале до 1/2 Fcpu (частоты тактирования микроконтроллера).
# AtMega8 2011-03-07 16:16
Ужас для начинающих..
Я вот не пойму если один счетчик подсчитывае количество импульсов измеряемого сигнала за определенный промежуток времени(то что надо), зачем тогда некая опорная частота?))
# Pashgan 2011-03-07 21:11
Один счетчик считает импульсы входного сигнала, второй - импульсы опорной частоты укладывающийся в "определенный промежуток времени". А промежуток этот складывается из программной задержки и двух "хвостиков" - первый от Capture1 до программной задержки, второй от программной задержки до Capture2.
# Brigadir 2011-03-07 20:37
Довольно экзотический алгоритм измерений. Pashgan, и как ты до такого додумался?
И, действительно, почему бы просто не считать кол-во входных импульсов за определенный интервал времени? В таком случае, тактовая частота МК не играла бы роли.
# Pashgan 2011-03-07 20:54
Идея не моя. Я прочитал об этом методе на форуме electronix.ru.
В идеале метод должен давать точность +-1 такт контроллера. На практике получается хуже.
Думаю на XMEGA хорошо получилось бы реализовать - там несколько 16-ти разрядных счетчиков и их можно каскадировать в 32 разрядные.
# add 2011-03-10 05:54
Quoting Pashgan:
Идея не моя. Я прочитал об этом методе на форуме electronix.ru.

уф, а я уж читая, подумал что ссылки на первоисточник не будет)))
# TarasH 2011-08-30 11:35
Quoting Pashgan:
Идея не моя. Я прочитал об этом методе на форуме electronix.ru.
В идеале метод должен давать точность +-1 такт контроллера. На практике получается хуже.
Думаю на XMEGA хорошо получилось бы реализовать - там несколько 16-ти разрядных счетчиков и их можно каскадировать в 32 разрядные.



http://electronix.ru/forum/index.php?showtopic=29796&view=findpost&p=234466
# Technician 2011-03-09 03:23
Отличная статья! Именно то, чем занимаюсь сейчас. Всвязи с этим есть несколько вопросов:
1. Можно ли величину программной задержки в 1 секунду снизить хотя бы до 0,5 секунды? Мне необходимо реализовать ПИД алгоритм для контроля частоты вращения двигателя, и за секунду частота может сильно "уплыть"
2. Необходимо измерять частоту одновременно с 2х устройств. Можно ли после получения стартовых Мнач и Nнач и завершающих пар Мкон и Nкон для одной частоты подключить к МК мультиплексором другую частоту?(идея с форума electronix.ru).
# Pashgan 2011-03-09 22:18
1. Можно
2. Не пробовал, но думаю, что можно
# Гость 2011-03-12 05:42
Здравствуйте. Статья понравилась. Несколько дополнений, если можно
-в выражение вычисления частоты правильнее вводить точно измеренное значение Fcpu генерации системы
резонатор+контроллер.
-согласно выражения определения абсолютной погрешности метода A_ERR>=Fx/(Fcpu *Tизмер.) десятые доли будут измеряться правильно до частоты Fx
# Гость 2011-03-12 05:47
будут измеряться правильно до частоты Fx
# Валентин 2011-03-13 17:46
Фух, с трудом но освоил. Спасибо за статью, очень благодарен!
# kitekat 2011-04-06 03:48
В файлах timer.c есть описка в инициализации таймера Т1, а именно - вместо операции сдвига - знак "меньше" : TCCR1B=(0
# Pashgan 2011-09-17 21:11
Да, мой косяк. Но по счастливой случайности на правильность работы он не влияет.
# Zorkiy 2011-08-23 04:27
В статье, к данному методу вычисления частоты не сказано главное преимущество данного метода, это точность вычисления, которая составляет при измерении, ну к примеру сигнала частотой 1МГц, за время измерения 0,1 сек дать точность до 0,01 Гц и более. То есть с помощью данного метода за 0,1сек вы можете измерить сигнал 7999999,99Гц!!! Каким еще методом можно этого добиться?! Стандартным методом подсчета сигнала для такой точности понадобится считать 100сек!, а здесь измеряйте частоту хоть непрерывно, каждые 0,01сек или чаще.
Книга, где описываются алгоритмы: Касаткин А.С. Обработка сигналов частотных датчиков. – М.: Энергия, 1966. – 120 с.
# Pashgan 2011-09-17 21:10
Мне не удалось добиться такой точности
# John Walker 2011-09-20 14:55
Quoting Pashgan:
Мне не удалось добиться такой точности


У меня этот алгоритм работает так, как заявлено автором с сайта electronix.ru
# DM 2011-10-01 05:37
Сначала я тоже считал кол-во входных импульсов за определенный интервал времени, но при низких частотах-от 10 до 100 гц-быстродейств ие моего девайса уже будет никакой, поэтому я решил чситать время между импульсами,так уже нормально, импульсы поступают на вход внешнего прерывания, а таймер считает время между прерываниями.Пр остейший код- 3 строки.
Code: // External Interrupt 1 service routine
interrupt [EXT_INT1] void ext_int1_isr(void)
{
a=1; // при поступлении импульса
}

// Timer 0 overflow interrupt service routine
interrupt [TIM0_OVF] void timer0_ovf_isr(void)
{
tik++; if(a){chast=tik; tik=0; a=0;} //измеряем время между импульсами
}

Ftek=(2600/(chast/12))*60; //переводим в об/мин
# Roger 2012-02-25 11:20
Quoting DM:

Code: // External Interrupt 1 service routine
interrupt [EXT_INT1] void ext_int1_isr(void)
{
a=1; // при поступлении импульса
}

// Timer 0 overflow interrupt service routine
interrupt [TIM0_OVF] void timer0_ovf_isr(void)
{
tik++; if(a){chast=tik; tik=0; a=0;} //измеряем время между импульсами
}

Ftek=(2600/(chast/12))*60; //переводим в об/мин

Поясните формулу?И с какой частотой у вас прерывание TIM0_OVF
# pitato 2011-10-19 07:15
pitato/ Здравствуйте. А как перевести программу на ATMEGA16? Не могу найти 8535.
# Dmitrii 2011-12-01 20:42
Как должны быть прошиты fuze bits?
# GM 2011-12-04 12:56
Ещё один вариант программы частотомера на си http://electronix.ru/forum/index.php?showtopic=77251&st=30
# Слава 2011-12-25 18:16
Скажите пожалуйста, а фьюз биты как выставить?
# Слава 2011-12-25 18:17
Некоректно спросил, какие выставить и в какие состояния?
# SeNiMal 2012-11-05 16:18
В схеме проекта Proteus к данной статье показано подсоединение генератора частоты к ножкам PD6(ICP1) и PB0(T0). Разве недостаточно подключить генератор только к PD6(ICP1)?
# Pashgan 2012-11-06 21:12
Недостаточно. В этом алгоритме вычисления частоты используется и вход захвата таймера Т1 и тактовый вход таймера Т0. Объяснение алгоритма в статье.
# SeNiMal 2012-11-07 07:22
Спасибо! Разобрался.
# TRON 2012-11-20 23:25
Не понял смысла в дополнительных программных счетчиках, которые заполняются при прерываниях. Они физически получается в микроконтроллер е не существуют? И как их указать в программе?
Объясните пожалуйста чайнику).
# Pashgan 2012-11-23 21:16
Разрядности аппаратных счетчиков не хватает для подсчета числа импульсов. Поэтому используются дополнительные переменные, которые считают число переполнений аппаратных таймеров. Физически они существуют только в виде ячеек оперативной памяти. Указываются (объявляются) как обычные переменные.
# DmAlex 2013-01-06 13:07
Спасибо автору за статью и ее разжевывание.
У себя большие частоты от 32кГц до 4Мгц я не мерил и естественно не знаю погрешность измерений, но когда измерял частоту в 4096Гц с ds1307 погрещность у меня составила 1,5%(4030 - 4110). Возможно при больших частотах измерений она будет составлять меньше.
# Vadis 2013-03-25 12:00
Запустил этот частотомер на Mege128 на 7.3728 мгц. Возникли вопросы с точностью результатов, в проекте протеуса в приложении частота считается точно, но если перемножить показания счетчиков по формуле то видна ошибка в 4 гц на 4 кГц то есть одна тысячная, когда я повторил алгоритм то получил ту же ошибку, она вполне компенсируется но проблеа в том что у меня она постоянна до 60 кГц. На частотах выше она возрастает до 100 Гц. в общем случае у меня частотомер работал до частоты в 2 МГц. Думаю как оптимальнее скомпенсировать ошибку.
# Pashgan 2013-03-25 20:48
Надо разобраться откуда она берется. У меня не удалось добиться заявленной точности метода. Может я где-то допустил ошибку.
# Vadis 2013-03-25 12:07
Да и забыл сказать большое спасибо за сайт и за материалы.
# Pashgan 2013-03-25 20:49
Пожалуйста.
# Vadis 2013-03-25 21:29
Сегодня пытался найти закономерность, но так и не смог, частотомер является частью прибора в котором стоят еще 2 синтезатора, так что проблемы формирования эталонной частоты у меня нет, сначала делал ради освоения синтезаторов, теперь пытаюсь довести это до полноценного прибора. надеюсь доведу.
# SeNiMal 2013-03-26 05:01
Алгоритм теоретически отличный, но на практике его мне реализовать не удалось, т.к. нет повторяемости результатов даже в Proteus. Большая полемика по этой теме шла на electronix.ru, но работающего кода так никто и не представил. Пришлось ставить медианный фильтр для отбрасывания "выбросов". Но это заказчику не понравилось. Пришлось вернуться на старый алгоритм.
# foxit 2013-04-20 13:23
Quoting Vadis:
Сегодня пытался найти закономерность, но так и не смог, частотомер является частью прибора в котором стоят еще 2 синтезатора, так что проблемы формирования эталонной частоты у меня нет, сначала делал ради освоения синтезаторов, теперь пытаюсь довести это до полноценного прибора. надеюсь доведу.

Расскажите подробнее про ваш прибор
# Vadis 2013-04-20 20:56
В общем то тайны не делаю, задача была освоение синтезаторов, в результате получилась неплохая заготовка которой чуть не хватает до полезного прибора, причем если павел не будет возражать т можно его опубликовать здесь, я готов предоставить черновик(чистов ик статьи + исходники и фото) вкратце что получилось, проц авр64 + dds AD9834 + DDS AD9850 + индикатор 16x2 + Энкодер + частотомер отсюда, тестовый прототип на протеусе, сейчас я это собрал в конструктив, на очереди управления уровнем сигнала DDS (уже решено) ну и отображение уровня на индикаторе, + интерфейс с компом, это пока откладывается, хотя сложностей нет, просто некогда.
# Pashgan 2013-04-22 19:53
Quote:
причем если павел не будет возражать т можно его опубликовать здесь
Я только за.
# foxit 2013-04-25 11:35
Quoting Pashgan:
Quote:
причем если павел не будет возражать т можно его опубликовать здесь

Я только за.
Ждем появления интересной статьи!
# foxit 2013-04-21 03:43
Quoting Vadis:
если павел не будет возражать т можно его опубликовать здесь, я готов предоставить черновик(чистовик статьи + исходники и фото)


+1
# Vadis 2013-04-25 18:36
Статья в процессе написания, но фотки смогу сделать когда дома появлюсь те после 10го
# Pashgan 2013-08-19 21:55
Сорвалась статья (
# Novomatik 2013-09-28 10:07
Для чего выводы DOWN UP и ENTER на принципиальной схеме? Их использование в программе я не нашел, они лишние?
# Pashgan 2013-09-28 20:04
Да. Рисуя эту схему, взял одну из старых и забыл убрать эти цепи.
# _lex 2014-11-12 13:22
хочу сделать частотомер для 220В на stm8. Будет ли нормально работать вход с обвязкой как http://www.atmel.com/images/doc2508.pdf , или надо ставить защитные диоды и снаружи?
# Nikolayyyy 2015-09-07 20:46
Так как счетчик Т1 не асинхронный, накопится погрешность из-за схемы захвата входного сигнала, проще взять 4 8битных двоичных счетчика + регистр сдвига, запускать все это от высокоточного секундного генератора, в паузе перегонять данные из счетчиков по 2 проводному послед. интерфейсу в микроконтроллер .
# ptol 2015-09-27 22:12
Запустил на Mega8(кварц на 14.7456МГц) Работает отлично правда только до 2МГц, оно и понятно, т.к. система захвата съедает 2,5такта (это по даташиту). Проверить на точном генераторе пока не было возможности, но показания стабильны. Программу писал сам на асемблере (моя певая на асемблере). Результатом доволен. Алгоритм отличный
# Boussel 2016-04-10 10:48
Уважаемый админ, подскажите, почему прошивка cymometer.hex из chastotomer-pro teus на частоте 10 кГц считает правильно(часто та-0009999.7, число тиков-16013131) , а прошивка из chastotomer-cv- avr считает с погрешностью (частота-000996 2.9, число тиков-16021335) ?
# plotik 2016-10-07 10:09
bcd.c +48 для чего?

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