Введение
В одной из предыдущих статей, посвященных изучению микроконтроллеров 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.
Общий вид циклограммы работы таймеров представлен на рисунке ниже.
Алгоритм программы выглядит следующим образом.
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
Quote: Объясните популярно (или дайте ссылку) почему частота случайный процесс и где написано как ее правильно измерять.
Так это уже второй вопрос - чем достовернее хочешь померить, тем просто большее количество измерений проводишь (получая децл разные результаты), сводишь в таблицу,
а там считаешь дисперсию и все прочее :)
P.S. Конечно хотелось бы еще узнать какова максимальная частота измерений на практике:)))
Quote:
Я вот не пойму если один счетчик подсчитывае количество импульсов измеряемого сигнала за определенный промежуток времени(то что надо), зачем тогда некая опорная частота?))
И, действительно, почему бы просто не считать кол-во входных импульсов за определенный интервал времени? В таком случае, тактовая частота МК не играла бы роли.
В идеале метод должен давать точность +-1 такт контроллера. На практике получается хуже.
Думаю на XMEGA хорошо получилось бы реализовать - там несколько 16-ти разрядных счетчиков и их можно каскадировать в 32 разрядные.
уф, а я уж читая, подумал что ссылки на первоисточник не будет)))
http://electronix.ru/forum/index.php?showtopic=29796&view=findpost&p=234466
1. Можно ли величину программной задержки в 1 секунду снизить хотя бы до 0,5 секунды? Мне необходимо реализовать ПИД алгоритм для контроля частоты вращения двигателя, и за секунду частота может сильно "уплыть"
2. Необходимо измерять частоту одновременно с 2х устройств. Можно ли после получения стартовых Мнач и Nнач и завершающих пар Мкон и Nкон для одной частоты подключить к МК мультиплексором другую частоту?(идея с форума electronix.ru).
2. Не пробовал, но думаю, что можно
-в выражение вычисления частоты правильнее вводить точно измеренное значение Fcpu генерации системы
резонатор+контроллер.
-согласно выражения определения абсолютной погрешности метода A_ERR>=Fx/(Fcpu *Tизмер.) десятые доли будут измеряться правильно до частоты Fx
Книга, где описываются алгоритмы: Касаткин А.С. Обработка сигналов частотных датчиков. – М.: Энергия, 1966. – 120 с.
У меня этот алгоритм работает так, как заявлено автором с сайта electronix.ru
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
Объясните пожалуйста чайнику).
У себя большие частоты от 32кГц до 4Мгц я не мерил и естественно не знаю погрешность измерений, но когда измерял частоту в 4096Гц с ds1307 погрещность у меня составила 1,5%(4030 - 4110). Возможно при больших частотах измерений она будет составлять меньше.
Расскажите подробнее про ваш прибор
+1
RSS feed for comments to this post