Юрец

Частотомер На Atmega

53 сообщения в этой теме

Юрец    7

здравствуйте!

делаю частотомер-тахометр.

использую atmega16, частота от кварца 14,7456000 MHz. таймер по прерыванию 1 сек .

в программе:

int p,i=0;

в теле таймера:

interrupt [TIM0_OVF] void timer0_ovf_isr(void)

{if (p==225) {p=0;printf(" F = %u\r\n",i);i=0;}else p++;

;}

(14,7456000 MHz / 256 / 256=225). при TCCR0=0b00000100;

теоретически таймер тикает правильно (смотрел в протеусе).

в обработчике int0, на который тикают входящие проверяемые импульсы так:

interrupt [EXT_INT0] void ext_int0_isr(void)

{i++;}

трабла в следующем:

при симуляции (подав частоту 6000Гц в протеусе) на терминале вижу:

F=5988

F=6018

F=6018

F=6017

F=6018 и т.д.

что это? глюк протеуса или ошибка в программе? или я неправильно сделал алгоритм подсчета импульсов?

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Быстрый заказ печатных плат

Полный цикл производства PCB по низким ценам!

  • x
    мм
Заказать Получить купон на $5.00
Zenner    1

А почему бы не использовать ещё один таймер для счета импульсов ?

Если ты подашь на внешнее прерывание больше ~150кГц то программа просто застрянет в нем...

Глюки протеуса имеют место быть. Я делал частотомер до 5МГц, тоже на меге. В реале меряет 5МГц с точностью 1-2гц, в протеусе - частота скачет сильнее, намного...

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
demonchik    0

Здравствуйте. Алгоритм вашей программы ясен - подсчет импульсов по прерыванию за единицу времени. а как вы включаете таймер с приходом импульса? вель нам надо его включить с приходом 1-го импульса и считать их количество... вроде верно? ;)

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
Юрец    7
1.А почему бы не использовать ещё один таймер для счета импульсов ?

2.Если ты подашь на внешнее прерывание больше ~150кГц то программа просто застрянет в нем...

3.Глюки протеуса имеют место быть. Я делал частотомер до 5МГц, тоже на меге. В реале меряет 5МГц с точностью 1-2гц, в протеусе - частота скачет сильнее, намного...

1.может я что-то недопонимаю, но ЗАЧЕМ?

2.фактически это алгоритм автомобильного тахометра. скажем до 8000 оборотов. 8000 * 4 цилиндра = 32кГц. пока это будет максимумом.

3.частотомер до 5МГц своя разработка? можно взглянуть на исходник (если можно, то на Си, т.к. в ассемблере не силен...)

Здравствуйте. Алгоритм вашей программы ясен - подсчет импульсов по прерыванию за единицу времени. а как вы включаете таймер с приходом импульса? вель нам надо его включить с приходом 1-го импульса и считать их количество... вроде верно? ;)

у меня получается так: прерывание по INT0 постоянно срабатывает по входящему импульсу, а таймер тикает постоянно (TIMSK=0X01 - запуск таймера при инициализации), причем обнуляя накопившееся значение каждую секунду.

можно ввести доп. переменную, скажем first_impulse=1 при подаче питания на микроконтроллер, а при первом срабатывании interrupt [EXT_INT0] void ext_int0_isr делаем так: включаем таймер, потом first_impulse=0.

фактически в автомобиле так: сперва вставляем ключ зажигания, поворачиваем, заводим. пусть между подачей питания на микроконтроллер и до момента "зеведенного двигателя" пройдет 0,5-2сек. тогда проверку на "первый импульс" для корректного отображения частоты можно и не делать.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
Zenner    1
1.может я что-то недопонимаю, но ЗАЧЕМ?

2.фактически это алгоритм автомобильного тахометра. скажем до 8000 оборотов. 8000 * 4 цилиндра = 32кГц. пока это будет максимумом.

3.частотомер до 5МГц своя разработка? можно взглянуть на исходник (если можно, то на Си, т.к. в ассемблере не силен...)

1,2. Внешних прерываний у меги увы, не много. Могут куда-нибудь ещё пригодиться. А если есть свободный таймер - почему бы не использовать? Тем самым разгрузив проц для занятия чем-нибудь более полезным.

3. Да, своя. См. ЛС.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
demonchik    0

познавательно... спасибо. будьте добры- скиньте свой исходный код. охота посмотреть. собираюсь собрать нечто похожее. ваш код очень поможет. заранее благодарю. ;)

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
Юрец    7
1,2. Внешних прерываний у меги увы, не много. Могут куда-нибудь ещё пригодиться. А если есть свободный таймер - почему бы не использовать? Тем самым разгрузив проц для занятия чем-нибудь более полезным.

3. Да, своя. См. ЛС.

спасибо! разбираюсь.

познавательно... спасибо. будьте добры- скиньте свой исходный код. охота посмотреть. собираюсь собрать нечто похожее. ваш код очень поможет. заранее благодарю. ;)

Zenner любезно предоставил : http://kb.3bb.ru/viewforum.php?id=5

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
mazzi    3
interrupt [TIM0_OVF] void timer0_ovf_isr(void)

{if (p==225) {p=0;printf(" F = %u\r\n",i);i=0;}else p++;

;}

Я думаю проблема в функции printf

зафиксируй полученное значение в буферной переменной и вынеси printf в основной цикл

{if (p>224) {p=0; i_view=i;i=0; flag=1;}else p++;}

а в основном цикле добавь следующую строку

if (flag) {
   flag=0;
   printf("F=%u\r\n",i_view);
}

и будет тебе счастье :-)

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
Юрец    7
и будет тебе счастье :-)

попробовал так, как вы советовали.

получаю:

F=5988

F=6028

F=6028

F=6028

F=6028

F=6029

F=6028

F=6028

F=6028

F=6028

F=6028 и т.д.

все больше склоняюсь к тому, что это глюк протеуса.

Изменено пользователем Юрец

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
mazzi    3
и будет тебе счастье :-)

попробовал так, как вы советовали.

все больше склоняюсь к тому, что это глюк протеуса.

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
Юрец    7
Возможно. Я протеусом не пользуюсь, всё делаю в железе и симуляторе.

в каком? не vmlab случайно?

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

А не проще использовать функцию захвата таймера, перевести в обратный код и преобразовать в десятичное значение. Все это делается в основном цикле. Внешнее прерывание будет освобождено "про запас"..

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
Юрец    7
А не проще использовать функцию захвата таймера, перевести в обратный код и преобразовать в десятичное значение. Все это делается в основном цикле. Внешнее прерывание будет освобождено "про запас"..

имеете ввиду использовать внешнее прерывание таймера по нарастающему фронту? при его появлении запускать другой таймер, и считать кол-во импульсов его?

есть пример для ознакомления?

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Я имею ввиду использовать вход ICP и функцию захвата таймера/счетчика. При возникновении прерывания по данному входу (фронт/спад конфигурируются) достаточно прочитать состояние таймера и вычесть из него предыдущее. Получится измерение периода, правда результат будет получаться обратнопропорциональный. Потребуется перевести полученный результат в обратный код, а так как счетчик работает в двоичном коде, то для читаемости результата потребуется преобразовать двоичный в десятичный. Но все это уже можно делать в основном цикле не нагружая прерывания. 

  • Одобряю 1

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
Юрец    7
Я имею ввиду использовать вход ICP и функцию захвата таймера/счетчика. При возникновении прерывания по данному входу (фронт/спад конфигурируются) достаточно прочитать состояние таймера и вычесть из него предыдущее. Получится измерение периода, правда результат будет получаться обратнопропорциональный. Потребуется перевести полученный результат в обратный код, а так как счетчик работает в двоичном коде, то для читаемости результата потребуется преобразовать двоичный в десятичный. Но все это уже можно делать в основном цикле не нагружая прерывания. 

спасибо!

Вас понял.

з.ы. а случайно нет кода на си - не хочется изобретать велосипед (а то пока разберусь)...

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
Goodefine    92

Чего то непонятно, в чем нашли проблему.

interrupt [TIM0_OVF] void timer0_ovf_isr(void)
{if (p==225) {p=0;printf(" F = %u\r\n",i);i=0;}else p++;
;}

В соответствии с Вашим алгоритмом проверки и инкрементирования счетчика р, таймер на самом деле оттикает 226 интервалов (на один больше чем константа в условии, в этом легко убедится, заменив 225 на, скажем на число 2 - будет три цикла. ). Это и дает погрешность в плюс 26-27. Поэтому и в проверку надо ставить число не единицу меньше. Т.е. 224. И будет не 6028, а гораздо более точное значение. А сам алгоритм далеко не лучший по точности...

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
Юрец    7
А сам алгоритм далеко не лучший по точности...

а какой лучше? (хотя-бы теорию)

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
Zenner    1

А чем Вам собственно не понравился подсчет импульсов за секунду с помощью ещё одного таймера?

Захват - херня ИМХО. Больно уж низкое разрешение получим(т.к. этот режим не юзал - предполагаю что минимум два такта, а это много.).

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
Юрец    7
А чем Вам собственно не понравился подсчет импульсов за секунду с помощью ещё одного таймера?

Захват - херня ИМХО. Больно уж низкое разрешение получим(т.к. этот режим не юзал - предполагаю что минимум два такта, а это много.).

тупо держу перед собой даташит на мегу16. пытаюсь вникнуть в регистры таймеров. пока дается с трудом.

я совсем замучил google своими поисками "даташит на мегу16 на русском"... пока безрезультатно...

p.s. все пытаюсь воткнуться в программу.

Изменено пользователем Юрец

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
Zenner    1

Вот эта книга есть что-то похожее на даташит. На русском.

Там описание всей периферии можно найти...Ну или почти всей...

1000472731.jpg

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
Юрец    7
Вот эта книга есть что-то похожее на даташит. На русском.

Там описание всей периферии можно найти...Ну или почти всей...

большое СПАСИБО!

скачал. разбираюсь.

а пока вопрос по программе: однократный положительный импульс на вход Т1 вызывает однократный "тик" таймера, или все-таки запускает его счет?

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
Zenner    1

Раз выбрано внешнее тактирование - значит однократный "тик".

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Создайте аккаунт или войдите в него для комментирования

Вы должны быть пользователем, чтобы оставить комментарий

Создать аккаунт

Зарегистрируйтесь для получения аккаунта. Это просто!

Зарегистрировать аккаунт

Войти

Уже зарегистрированы? Войдите здесь.

Войти сейчас


  • Сообщения

    • О чем и говорилось ранее. Кажущаяся усложненность такой схемы, (по сравнению с одиночным компаратором), компенсируется легкой её настройкой.
    • Интересное изделие, 4 Ампера не хватает для запитки "пары реле"... У Вас где-то 4,5Вх4А=18 Ватт выделятся должно, ищите по запаху. Или проверьте потребление от ИИП. Если "просадка"  (кстати, в какой точке? на выводах Mean Well? или где-то на плате? две большие разницы...) не зависит от подключенной нагрузки, значит, с большой вероятностью, Ваш Mean Well неисправен. Или на плате косяк. Сколько потребляет Ваша плата?
    • Первая схема - просто выпрямитель с вольтметром - амперметром, срисовано с ошибкой. Вторая - тиристорный регулятор мощности, видимо по первичке трансформатора, типа такого: Я бы эту порнуху выкинул, и собрал нормальную схему.
    • Относительно чего, какой шины делались измерения? Вот это вообще не понял:  
    • Колл-бак функция HAL_ADC_ConvCpltCallback() вызывается при окончании каждого преобразования, для всех каналов одна и та же. А функция HAL_ADC_GetValue(hadc1) просто перекладывает готовый результат преобразования в массив adcResult[], она не вызывает новое преобразование. Поэтому, чтобы отличить результат какого канала лежит в АЦП, нужно завести переменную-индекс, которая будет увеличиваться на 1 при каждом вызове HAL_ADC_ConvCpltCallback(). И этот индекс будет индексом массива результатов. После преобразования всех каналов этот индекс надо сбросить в 0, чтобы в следующий раз начать с начала массива. Признак последнего канала - флаг окончания сканирования каналов ADC_FLAG_EOS. uint8_t index = 0; void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc1)   { if (__HAL_ADC_GET_FLAG(hadc1, ADC_FLAG_EOC))    {   adcResult[index] = HAL_ADC_GetValue(hadc1);    index++;   } if (__HAL_ADC_GET_FLAG(hadc1, ADC_FLAG_EOS))     {   index=0; } }  
    • У меня в детстве, в начале 90-х, был двухкассетный Samsung, наподобие того, что на картинке (чуть-чуть другого дизайна). Тоже белый и чисто корейский - отцу знакомые из Финки подогнали... Тогда это был "попсатас" жуткий - после "Весны"... С перезаписью, с автостопом, с приемником и встроенным микрофоном! Аппаратец, кстати, до сих пор живет на даче - кассет уже не играет, а радио - только так...
    •   В Охотском море тоже