Свежие обсуждения
Микроконтроллеры

Частотомер на AVR

1 6 7

Заново просматривал теорию по поводу метода захвата, изложеную GM, на electronix.ru. Немогу понять почему число подсчитываемых импульсов входной частоты М точное число, а N гуляет +/-1. У меня полуячается что гуляют оба.
Вот теория, от GM:

ИЗМЕРЕНИЕ ЧАСТОТЫ С ПОМОЩЬЮ АВР МИКРОКОНТРОЛЛЕРА

1) Введём определения
Fо - сигнал опорной частоты,
То - период опорной частоты, То=1/Fо,
Fx - входной сигнал (меандр) неизвестной частоты, подлежащей измерению,
Тх - период входной частоты, Тх=1/Fx,
Тизм - период измерения входной частоты,
N - количество импульсов опорной частоты за время измерения,
M - количество импульсов входной частоты за время измерения.

2) Формула вычисления частоты Fx = Fо*М/N (поскольку очевидно, что То*N=Тх*М за Тизм).

3) Формула для Fx применима как к варианту с "воротами", так и к варианту со схемой захвата. При использовании схемы захвата М является точным числом, а N "гуляет" в пределах (-1,+1). При использовании "ворот" N является точным числом, а М "гуляет" в пределах (-1,+1).

Вот всё, что нам нужно знать из теории для измерения частоты.

4) Применим наши знания на практике. Выберем период измерения Тизм примерно равным одной секунде. (Примерно потому, что Тизм должен быть ТОЧНО кратен М*Тх). Пусть Fx=170 кГц, а Fо=16МГц. Тогда М=170000, а N=16000000.

Вычислим частоту по нашей формуле Fxвыч = Fо*М/N=16000000*170000/16000000=170000 Гц.
Вычислим погрешность метода. Не буду вас мучить выводом соответствующей формулы с помощью частных дифференциалов, кто захочет пусть сам потренируется, скажу только, что относительная погрешность будет суммой модулей относительных погрешностей отдельных составляющих.
Ну и ещё упростим задачу, приняв ΔFo/Fo =0 (На самом деле, кратковременная нестабильность кварцевой опоры порядка 10^(-8) или лучше).

Итак, Fx = Fо*М/(N±1)=170000±0.010625 Гц. Что нам и требовалось показать. Относительная погрешность составит 6*10^(-8). Можно добавить 10^(-8) нестабильности опоры, если требуется уточнить погрешность. Кстати, для варианта с "воротами" Fx = Fо*(М±1)/N=170000±1 Гц, как и было сказано.

5) Перейдём теперь к реализации алгоритма на микроконтроллере. В принципе, всё и так уже ясно, просто поставим точки над ϊ и чёрточки на t(. Сколько нам нужно захватов таймера, чтобы вычислить частоту? Два - один для захвата начала секундного интервала, и второй для захвата конца того же интервала. Пусть захват работает по прерыванию. При захвате, т.е. при положительном фронте импульса входной частоты, содержимое таймера перепишется в регистр ICR. Прекрасно, в этом же прерывании запомним в регистрах или в памяти два числа – количество импульсов Мнач и Nнач, запрещаем прерывание и выходим из него (замечу в скобках, схема захвата "молотит" по-прежнему, но прерывания запрещены), оно нам понадобится только через секунду, займёмся другими делами, скажем, расчетом частоты предыдущего цикла. Через примерно секунду работы (или вынужденного безделья, можно по таймеру) ОПЯТЬ разрешаем прерывания от схемы захвата. Как только оно произойдёт, опять запоминаем два числа – количество импульсов Мкон и Nкон, запрещаем прерывание по захвату и выходим из него, вычисляем М=Мкон-Мнач, N=Nкон-Nнач.

Вот так это всё и работает. Я, конечно многого не упомянул. Все переменные для расчета должны быть соответствующей разрядности, как минимум 32, умножение надо делать до деления, чтобы не потерять точность, вычисление частоты можно вести непрерывно, достаточно просто после вычисления частоты переписать переменные Мнач=Мкон, Nнач=Nкон. Обязателен учёт переполнения таймеров.

 

Y@rik: Заново просматривал теорию по поводу метода захвата, изложеную GM, на electronix.ru. Не могу понять, почему число подсчитываемых импульсов входной частоты М точное число, а N гуляет +/-1
Точное число получается по определению, поскольку весь процесс начинается с фронта входного импульса и заканчивается фронтом же. Естественно, между фронтами будет целое число импульсов. Тактовая частота процессора никак не связана с входной частотой, т.е. асинхронна по отношению к нему, поэтому в схеме захвата может быть защелкнуто либо некое число Ni, либо следующее Ni+1. Поскольку захватов два, для начала и конца периода измерения, то разница полученных чисел может лежать от N до N+2, ну или N±1.

Насколько я помню вашу программу, вы М получаете по прерыванию. Если это так, то у вас может быть такая ситуация, пришёл фронт входного импульса, возникло прерывание захвата, пока прерывание, написанное на си, доходило до чтения М, возникал новый захват, и вы считывали не М, а М+1 или даже М+2. Ну сами посудите, для 1 МГц входной частоты фронты идут через 1 мкс или 8 машинных циклов (МЦ). А у вас вход в прерывание не менее 0-1-2 МЦ (на завершение текущей команды) ПЛЮС 4 МЦ(на сохранение СчК) ПЛЮС 2 МЦ (на переход на подпрограмму) = 7-8 МЦ. Вывод: обеспечьте равные задержки как для начала цикла измерения, так и для конца. Например, чтобы исключить неравномерность от завершения текущей команды, надо бы чтобы программа в моменты прерываний шла по однотактным командам, скажем по нопам.

 

GM: Просто вам надо силой воли отказаться от прерываний. Что можно сделать. Пусть пока прерывания захвата приходят с частотой 1 МГц, т.е. каждые 8 МЦ. В си-программе открываете ваш ключ разрешения захвата, скажем, на 1 мс. Что произойдёт? Прилетит порядка 1000 фронтов, последний останется в ICR1 и его можно использовать для вычисления N. Далее, надо определить содержимое счётчика0, соответствующее последнему фронту. Навскидку так например, читаете 4 раза содержимое счётчика0, закрываете ключ, ещё 4 раза читаете и смотрите, где произошли изменения, простая логика и М у вас в кармане. Будет работать и на 4 МГц, и даже на си. Ну и всё, остальную часть вы знаете.

Попробывал, как Вы и говорили реализовать программу без прерывания, кажется работает. Так как я пишу на СИ, есть вопрос, если эти сохранения сделать вставками ассеблерных команд в тело Си программы, сохранение лучше проводить в регистры или в ОЗУ. Мене кажется, что лучше будет в регистры (т.к. сохранение происходит за 1 такт).

 

Возьмите МК с двумя схемами захвата, я вам уже говорил на электрониксе, и пишите всё на си, если вам это си так полюбилось. И будет вам щастье, и программа у вас будет белая и пушистая, как у меня норвежская лесная кошка(. С регистрами поаккуратней, шут его знает, как компилер ими распоряжается...

 

Сразу записывать в регистры попробывал, пока программа работает . Пробывал подставлять значения сохранненых регистров в формулу вычисления частоты, получается, что частота не зависит от того, какую пару сохранненых регистров я возьму Т0_1, Т0_2 и т.д. для вычисления М1 и М2.
Но мне не понятно как можно детектировать, что за время открытия ключа, допустим 1мс прошел хоть один импульс.

GM: Возьмите МК с двумя схемами захвата, я вам уже говорил на электрониксе, и пишите всё на си, если вам это си так полюбилось.
Я уже спрашивал у Вас, какие контроллеры имеют 2 схемы захвата, кроме мега128 - да и дороговата она у нас.

 

Y@rik: Но мне не понятно как можно детектировать, что за время открытия ключа, допустим 1мс прошел хоть один импульс
У вас же схема захвата взводит флаг, вот за ним и следите.

Y@rik: Я уже спрашивал у Вас, какие контроллеры имеют 2 схемы захвата, кроме мега128 - да и дороговата она у нас
Ну, голубчик, вам уже лень ручками поработать? Дороговата, значит, обходитесь одной схемой захвата, пишите на ассемблере. Вот видите, знание ассемблера даже помогает напрямую уменьшить расходы...Кстати, ещё одно сравнение си и асма по быстродействию. На электрониксе у одного товарища программный уарт не работает на 115200 на приём, а на ассемлере можно написать для 2Мбод, разница в 17 раз...

 

Кстати я тут тоже столкнулся с проблемой реализации частотомера. У меня диапазон изменения входной частоты 50 Гц - 500 кГц нужно измерять с точностью хотя-б +/-1 Гц и временем измерения 0,1 сек не более. Параллельно ведя обширную "переписку" по UART.

Контроллер ATMEGA8 при тактовой 12 МГц. Таймеры 0 и 1 свободны. Сейчас тактирую измеряемой частотой таймер 1, а время отмеряю таймером 0 по прерываниям. Работает, но нельзя-ли как-то поизящнее. Импульсы имеют скважность близкую к 2.

ЗЫ ищу примеры реализации ПИД регулятора на ассемблере AVR (Элм Ченовскую уже изучал).

ЗЫ номер 2 - на 2 недели правда ухожу в загул.

 

Абсолютная погрешность моего метода равна ±(Fx/Fo)*(1/Tизмерения)=±(0.5/12)*(1/0.1)=±0.4Гц за 0.1с или можете уменьшить время измерения в два раза, до 50мс, точность будет ±0.8Гц. Почитайте на электрониксе, я там новый способ статистической обработки предложил для этого метода.

 

Сделал частотомер реализован по етому алгоритму на Мега8. В протеусе(7.4 SP3) симулируется норьмально. Диапазон 0.3гц - 1мгц. В железе не проверял. Может кому пригодится.

206723.rar

 

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

MovfStart = ICR1; // Запоминаем начальное состояние М счетчика

вы почему-то игнорируете Movf, а счётчик переполняется каждые 4 мс и в цикле ожидания первого импульса вполне может быть перенос из таймера в Movf.