Arduino Polska Forum

Pełna wersja: czujnik odbiciowy TCRT5000 miernik obrotów sie nie zeruje
Aktualnie przeglądasz uproszczoną wersję forum. Kliknij tutaj, by zobaczyć wersję z pełnym formatowaniem.
Witam

Chciałbym zrobić miernik obrotów na podstawie czujnika odbiciowego TCRT5000.
Działam na podstawie przykładu:
Kod:
const int dataIN = 7; //IR sensor INPUT

unsigned long prevmillis; // To store time
unsigned long duration; // To store time difference
unsigned long refresh; // To store time for refresh of reading

int rpm; // RPM value

boolean currentstate; // Current state of IR input scan
boolean prevstate; // State of IR sensor in previous scan

void setup()
{
 pinMode(dataIN,INPUT);      
 prevmillis = 0;
 prevstate = LOW;  
 Serial.begin(9600);
}

void loop()
{
// RPM Measurement
 currentstate = digitalRead(dataIN); // Read IR sensor state
if( prevstate != currentstate) // If there is change in input
  {
    if( currentstate == HIGH ) // If input only changes from LOW to HIGH
      {
        duration = ( micros() - prevmillis ); // Time difference between revolution in microsecond
        rpm = (60000000/duration); // rpm = (1/ time millis)*1000*1000*60;
        prevmillis = micros(); // store time for nect revolution calculation
      }
     
  }
 
 prevstate = currentstate; // store this scan (prev scan) data for next scan
 
 // LCD Display
 if( ( millis()-refresh ) >= 1000 )
   {  
       Serial.println(rpm);  
   }  

}
Działa ok, niestety jak odsunę obracający się przedmiot od czujnika zapamiętuje ostatnią wartość.

Jak zrobić żeby po upływie np 1s bez obracania się przedmiotu, wyświetlało 0 RPM?
Najprościej zeruj rpm po ostatnim wydruku. Jak już ogarniesz kurs Arduino z Forbota to sobie zmień warunek kiedy wchodzi do obliczania RPM, a właściwie to powinieneś mierzyć czas od ostatniego pomiaru i jeśli przekroczy jakąś wartość, to zeruj RPM.
próbowałem, jak dodam na sam koniec
rpm = 0;
to odczyt np dla 200 obrotów, jest taki:
200
200
200
0
0
200
200
to zero wcina się w pomiar jak nie powinnoSad
No to zrób sobie jakąś zmienną, zeruj ją po wyliczeniu rpm i zwiększaj po wydruku, jak będzie większa niż 2 (lub ile tam sekund powinno być by uznać, że jest już zerem) to przypisuj do rpm 0.
Założenie tego programu jest takie, że w pętli
Kod:
if( prevstate != currentstate) // If there is change in input
 {
   if( currentstate == HIGH )

liczony jest czas pomiędzy aktualnym i ostatnim impulsem, a następnie na podstawie obliczeń aktualizowana jest zmienna RPM.
Jeśli zatrzymać obroty, to program nie doczeka się warunku ( prevstate != currentstate) i nie zmieni RPM.
Rozwiązanie jest bardzo proste. Wywalić ten program i napisać taki, który w przerwaniu liczy impulsy w określonej jednostce czasu, na przykład w ciągu sekundy. Program był by o wiele dokładniejszy i o wiele prościej jest go napisać i optymalizować.

Po co jest zmienna refresh, skoro jest równa zero?
I w ogóle, po co ta pętla
Kod:
if( ( millis()-refresh ) >= 1000 )
   {  
       Serial.println(rpm);  
   }
Przecież po sekundzie działania programu, warunek jest spełniony zawsze.
Jak zwykle, ja i kaczakat, jesteśmy bardziej zainteresowani rozwiązaniem niż autor tematu.
Napisałem taki kawałek kodu, który oblicza częstotliwość(obroty na sekundę) w przerwaniu i zachowuje się tak, jak tego oczekuje autor:
Kod:
#include "LiquidCrystal_I2C.h"
LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);
int prevmillis=0;
volatile int i;
const byte interruptPin = 2;

void setup()
{
    pinMode(interruptPin, INPUT);
    attachInterrupt(digitalPinToInterrupt(interruptPin), licznik, RISING);
    lcd.setBacklight(255); //jasnosc podswietlenia od 0 do 255
    lcd.begin(20,4);
}

void loop()
{
    if (millis()-prevmillis>1000)
    {
        lcd.setCursor(0,0);
        lcd.print("     ");
        lcd.setCursor(0,0);
        lcd.print(i);
        i=0;
        prevmillis=millis();
    }
    
}

void licznik() {
    i++;
}
Wszystko zależy co to ma mierzyć, jak szybkie rzeczy to ilość w stałym czasie i ten kod w przerwaniach jest super, jak wolne to ja wolę mierzyć czas między "pikami" , kiedyś Elektromaras pokazywał swój kod do wiatromierza i miał pomiar typu V=pik x 2,4 km/h: https://www.youtube.com/watch?v=slzOhgBeQjc .
Założenie jest takie, że ten obrotomierz liczy pełne obroty (RPM jest typu int) w określonej jednostce czasu.
Mój kod liczy w sekundzie, autor chce liczyć w minucie.
Jeśli chcieli byśmy liczyć realne obroty na minutę, to faktycznie może się zdarzyć, że będzie na przykład jeden obrót na minutę i powinniśmy liczyć czas pomiędzy impulsami, oraz odświeżać ekran co minutę. No i czekać minutę na wynik, jeśli nie ma impulsu, to dać zero.
Mój kod czeka sekundę na wynik i odświeża LCD, można wpisać aby czekał minutę, albo i rok.
Można czekać sekundę i mnożyć wynik przez 60, wtedy będzie wynik w obrotach na minutę, ale aktualizowany co sekundę. To się nazywa interpolacja, prędkość chwilowa. Na tej zasadzie działają na przykład obrotomierze w samochodach.
Można dodać kilka warunków do pętli z mojego kodu, w ten sposób aby na przykład jeśli zdarzy się jakiś impuls w ciągu minuty, to prędkość chwilowa będzie zero, ale faktyczna będzie jeden na minute i to można spokojnie zrealizować lekko przerabiając mój kod. No i nie obciążamy procesora.

Ufff.... ale chaotycznie piszę, muszę napić się kawy. Big Grin
Może miałoby to sens po zastosowaniu krążka encodera z naciętymi np. 20 szczelinami. Dałoby to 20(40)x więcej impulsów /s. Inaczej odczyty byłyby typu 0/60/120 obrotów/min.
Ja cały czas mam na myśli obrotomierz do śmigieł samolotów RC, a tam są obroty powyżej 10000/min.
Ja taki mam i jest bardzo dokładny.