Почему частотомер на arduino получается медленным?

osetroff
Offline
Зарегистрирован: 27.08.2014

Дано: два arduino pro mini на atmega328p 16Mhz.

Один генерирует на pin13 переменный сигнал (high, low) в течение нескольких секунд.

Потом отображает через терминал частоту выданного сигнала:

количество пар (high,low) делим на период в микросекундах и умножаем на 1000000.

Получается 2137629Hz.

Второй используется как частотомер, принимая сигнал с pin13 первого на свой pin8 (ICR1).

Код второго:

#include "CyberLib.h"
ulong l1;
volatile ulong l3;
void setup(){
  Serial.begin(115200);
  //инициализация таймера  
  d8i;digitalWrite(8, HIGH);// включить подтяжку входа  
  cli();
  TIMSK1=(1<<ICIE1);    
  TCCR1A=(0<<COM1A1)|(0<<COM1A0)|(0<<WGM11)|(0<<WGM10);  
  TCCR1B=(1<<ICNC1)|(1<<ICES1)|(0<<WGM13)|(0<<WGM12)|(0<<CS12)|(1<<CS11)|(1<<CS10);
  TCCR1C=0;
  TCNT1=0;
  ICR1=0;
  sei();
}
//прерывание по внешнему импульсу
ISR(TIMER1_CAPT_vect) {l3++;}
void loop(){ 
  l3=0; //обнулили счетчик импульсов
  dms(1000); //производим захват импульсов 1 секунду
  l1=l3; //сохраняем количество импульсов в секунду
  Serial.print("f=");Serial.print(l1,DEC);Serial.println(" Hz");
 dms(1000);
}

Второй на выходе показывает, например "f=13877 Hz" или "f=12931Hz".

Значит ли это, что программно мегагерцовый сигнал я с помощью arduino не смогу измерить?

Благодарю за подсказки.

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

osetroff пишет:

Значит ли это, что программно мегагерцовый сигнал я с помощью arduino не смогу измерить?

Благодарю за подсказки.

Скорее не значит. Всё дело в  методиках. Есть такой проект на меге328 "Транзистортестер" , который среди прочего измеряет частоту, потолок измерения  к сожалению назвать не могу, но точно больше мегагерца. 

vov4ik
Offline
Зарегистрирован: 10.09.2013

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

Попробуйте добавить пару команд  void loop() { Start /* что-то выполняется */ End }

osetroff
Offline
Зарегистрирован: 27.08.2014

А зачем мне бесконечный цикл (Start End)?

Просто, подумал, что плохо разобрался в документации.

Что можно захватывать внешний сигнал, но не вызывать каждый раз прерывание (т.к. это медленно),

а иметь лишь прерывание по переполнению.

Еще вариант - десассемблировать код и посмотреть, вдруг в прерывании все регистры в стек, а потом - обратно?

Мне всего-то нужно инкремент делать в прерывании (в байте памяти, потом в следующем при переполнении и тд).

На ассемблере получится захватывать мегагерцовый сигнал или нет, кто сталкивался?

 

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

osetroff, вы сходите по той ссылочке что я дал, там есть файлик GetFrequency.c , посмотрите как там сделано измерение.

Logik
Offline
Зарегистрирован: 05.08.2014

osetroff пишет:

Значит ли это, что программно мегагерцовый сигнал я с помощью arduino не смогу измерить?

Надо настроить таймер в режим счета внешних событий. Тогда импульсы по входу будут увеличивать таймер  он будет теперь просто счетчиком, прерываний не будет, или будут но по переполнению таймера. Подробности смотрите в pdf-ке на микроконтроллер. Это не по "ардуиновски", но ниче не попишеш, хочеш эффективности - учи "железо".

osetroff
Offline
Зарегистрирован: 27.08.2014

dimax пишет:

osetroff, вы сходите по той ссылочке что я дал, там есть файлик GetFrequency.c , посмотрите как там сделано измерение.

Благодарю, покопал.

Там все 3 таймера используются, а это как-то неправильно для такой простой задачи.

Если не ломать функционал arduinовских библиотек, то timer0 занят.

 

osetroff
Offline
Зарегистрирован: 27.08.2014

Благодарю всех за пинки, заработало :)



#include "CyberLib.h"
ulong l1;
volatile ulong l3;
void setup(){
  Serial.begin(115200);
  //external clock source to D5 (T1) (D4/T0)
  d5i;digitalWrite(5, HIGH);// включить подтяжку входа  
  cli();
  //int on ovfl
  TIMSK1=(1<<TOIE1);    
  TCCR1A=0;//(0<<COM1A1)|(0<<COM1A0)|(0<<WGM11)|(0<<WGM10);  
  TCCR1B=(0<<ICNC1)|(1<<ICES1)|(0<<WGM13)|(0<<WGM12);
  //external clock source on T1. Clock on rising edge
  TCCR1B|=(1<<CS12)|(1<<CS11)|(1<<CS10);
  TCCR1C=0;
  sei();
}
ISR(TIMER1_OVF_vect) {l3++;d13inv;}  
void loop(){ 
  //обнулили счетчики
  cli();l3=0;TCNT1=0;sei();
  dms(1000); //производим захват импульсов 1 секунду
  cli();l1=l3*65535+TCNT1;sei();
  
  Serial.print("f=");Serial.print(l1,DEC);Serial.println(" Hz");
  dms(1000);
}

Предел частоты входного сигнала по datasheet 16000000/2,5= 6,4Mhz

Теперь проблема - как это оттарировать, т.е. проверить точность (полученная частота слегка не совпадает)?

Пока мысль - задействовать micros() и ждать в цикле 1секунду.