• Witaj na Forum Arduino Polska! Zapraszamy do rejestracji!
  • Znajdziesz tutaj wiele informacji na temat hardware / software.
Witaj! Logowanie Rejestracja


Ocena wątku:
  • 0 głosów - średnia: 0
  • 1
  • 2
  • 3
  • 4
  • 5
Pomiar częstotliwości wejściem DC
#1
BRY Smile

Napisałem sobie prosty kod - pomiar częstotliwości PWM na wejściu cyfrowym
Mierzę czas stanu LOW, HIGH, dodaje i obliczam częstotliwość.

Działa, ale co jakiś czas otrzymuję wynik z d..y Wink
Jako źródła zastosowałem sygnał 1kHz z oscyloskopu.

Wykres w kreślarce wygląda tak: https://photos.app.goo.gl/WgpsWkbwcpmHir3J9

Finalnie będę mierzył częstotliwości gdzieś do 100Hz max.
Możecie zerknąć na kod (brudnopis jakby co)? Mam gdzieś błąd?
Czy też to kwestia zbyt wysokiej już częstotliwości???

Z góry dzięki...

Kod:
int RPM_pin = 44; boolean RPM_state=false;  boolean RPM_state_=false; float RPM_low_time=0; float RPM_high_time=0;
float time=0; float RPM; float msLICZNIK; float licznik; float msBT; float FRQ;

void setup()
  {
    Serial.begin(115200);
    Serial3.begin(38400);
    pinMode(RPM_pin, INPUT);
  }

void loop() {

  RPM_state = digitalRead(RPM_pin);
 
  if (RPM_state != RPM_state_) // jeśli zmienił się stan pinu RPM_pin
    {
      if (RPM_state) // jeśli RPM_pin HIGH
        {
          RPM_low_time=micros()-time; // jak długo [us] trwał stan LOW
        }
      else
        {
          RPM_high_time= micros()-time; // jak długo [us] trwał stan HIGH
        }
        time=micros(); // reset licznika czasu
        RPM_state_=RPM_state; // zapis stanu pinu RPM
        FRQ=1000000/(RPM_high_time+RPM_low_time);
    }

  if (millis() > msBT + 10)
    {
      // Serial.print(RPM_low_time); Serial.print(" "); Serial.println(RPM_high_time);
      //Serial.println(1000000/(RPM_high_time+RPM_low_time));
      Serial.println(FRQ);
      msBT = millis();
    }

  //delay(10);

}
 
Odpowiedź
#2
Zrób to na przerwaniu z timerem a najlepiej użyj ICP.. Użycie mils i lop nigdy nie będzie poprawnie... Widze AVR Mega wiec ma 4 ICP porty..
Arduino zostało wymyślone po to, by robić dobrze jedną prostą rzecz – migać diodą. 
 
Odpowiedź
#3
Zapomniałem napisać, że na razie nie chcę na przerwaniach. Raz, że nie umiem Wink
ale to nie problem - kiedyś i tak muszę się nauczyć Smile dwa, że co to znaczy,
że "mils i lop nigdy nie będzie poprawnie" - możesz rozjaśnić?

Ps. No i ważniejsze - mam sporo nietypowych płytek Mega z dostępnymi tylko
niektórymi pinami, a docelowo program ma pracować na 328 więc liczę programowo,
żeby nie być zależnym od procesora...

Jakub
 
Odpowiedź
#4
Bo w lopie trafić zmianę pinu to już będą opóźnienia wiec bez sensu odczytywać czas. A po drugi jak rozbudujesz program to trafić w czas w mills to też będzie z dużym opóźnieniem nawet dla 10ms mogą być pomyłki 50%... A chyba nie chcesz miernika częstotliwości z pomyłka 50% prawda??
Arduino zostało wymyślone po to, by robić dobrze jedną prostą rzecz – migać diodą. 
 
Odpowiedź
#5
To wiem - trafić w zbocze może się nie udać Wink ale to nie jest powodem TAKICH błędów. Chyba Wink

Sprawdzałem - digitalRead() realizuje się około 100.000x na sekundę.
Mierzyć będę <> 100Hz więc...

Zerknij na wykres - tam pojawiają się pojedyncze strzały zamiast 1000Hz dostaje
2x lub kilka razy więcej... To raczej nie jest spowodowane opóźnieniem wprowadzonym
przez resztę kodu.

Chyba, że coś blokuje pętle na kilka tysięcznych sekundy...

J.
 
Odpowiedź
#6
Szkoda ze nie obliczyłeś ile czasu trwa operacja na float.. Więcej się nie dało??
Arduino zostało wymyślone po to, by robić dobrze jedną prostą rzecz – migać diodą. 
 
Odpowiedź
#7
Obliczę wieczorem Wink
 
Odpowiedź
#8
Zrobiłem coś takiego:

Kod:
// int IN_pin=2; // pin wejsciowy
volatile float RPM_time; volatile long time; long msBT; volatile float FRQ;
int ZEGAR_pin=7; long msZEGAR;

void setup()
  {
    Serial.begin(115200);
    Serial3.begin(38400);
    pinMode(ZEGAR_pin,OUTPUT);
    //pinMode(2,INPUT);
    attachInterrupt(0, cykl, RISING);
    analogWrite(ZEGAR_pin,128);
  }

void loop() {

  /*
  if (millis() > msZEGAR + 2)
    {
      digitalWrite(ZEGAR_pin,!digitalRead(ZEGAR_pin));
      msZEGAR=millis();
    }
  */

  if (millis() > msBT + 333)
    {
      Serial.println(FRQ,3);
      msBT = millis();
    }
}

void cykl()
  {
    RPM_time=micros()-time;
    time=micros(); // reset licznika czasu
    FRQ=1000000/RPM_time;
  }

Sygnał PWM mierzy stabilnie - pokazuje 492Hz równiutko, bez względu na to jak często wysyłam
coś na serial czy nawet jak wstawię delaya() w loop(). Nie wiem, czy te brakujące 8Hz gdzieś 
gubi się w liczeniu, czy po prostu procesor nie daje 500Hz jak niby powinien.

Muszę zrobić jakieś stabilne źródło częstotliwości do około 200Hz żeby dalej pisać...

Ps. Jeśli można zaufać tone() to działa spokojnie do kilkudziesięciu kHz Smile

Dzięki narazie Wink
 
Odpowiedź
#9
Sam program nie ma błędów, sprawdzałem na 328p 16Mhz i działa, na 1Khz sygnał 50%PWM rozrzut mam na 10% bez tych "dziwadeł" błędem będzie u ciebie coś z generatorem albo z połączeniem.



O widzisz na przerywaniu już lepiej Wink
Arduino zostało wymyślone po to, by robić dobrze jedną prostą rzecz – migać diodą. 
 
Odpowiedź
#10
Inna wersja.

Robię obrotomierz do skuterka Smile

Układ analogowy podający stan wysoki na pin wejściowy gdy świeci iskra już mam.

Na przerwaniu zawieszę funkcję zliczającą iskry.
Liczba iskier/czas pracy daje obroty, tyle że niestety średnie z całego czasu pracy Wink

Mogę zamiast liczyć iskry mierzyć czas między iskrami - niestety w przypadku
wyłączenia silnika pomiar się nie zaktualizuje (jeśli będzie czekał na RISING).

Chciałbym, żeby to była średnia z powiedzmy ostatniej 1/10 sekundy, żeby przy okazji
odfiltrowały się ew. zakłócenia pomiaru.

Zapamiętywać przy każdej iskrze czas jej wystąpienia, żeby wiedzieć ile zliczać
to chyba słaby pomysł - obroty mogą być spore, powiedzmy 9000rpm co oznaczałoby
zapamiętanie dodatkowo 15 zmiennych...

Mogę prosić o podpowiedź jak się do tego sensownie zabrać? Smile


Jakub
 
Odpowiedź
  


Skocz do:


Przeglądający: 1 gości