• 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
Obsługa przerwań w Arduino Mini PRO
#1
Witam

Zmagam się z programem i nie bardzo wiem jak z tego wybrnąć. Mianowicie program działa tak jak chcę poza momentem w którym następuje wykasowanie licznika przerwań i ponowne zliczanie. Wtedy na ułamek sekundy LED gaśnie mimo ciągłego przepływu i zliczania impulsów. Zauważyłem że od czasu wyzerowania licznika do kolejnej pętli nie zlicza impulsów. Gdzie zrobiłem błąd i jak zlikwidować gaśnięcie LEDa?
Kod:
const int flowPin = 2;  // przepływomierz podłączony do pinu 2
const int wiatrak = 5;

void(*resetFunc) (void) = 0;

volatile unsigned int flowCount = 0; // zmienna do przechowywania liczby impulsów (volatile oznacza, że zmienna jest modyfikowana w przerwaniu)
unsigned long flowMillis = 0; // zmienna do przechowywania czasu
unsigned long aktualnyCzas = 0;
unsigned long opuznienie = 1;
unsigned long opuznienie2 = 1;
int woda = 0;
const unsigned long czasReset = 604800000UL;
unsigned long czasRReset = 0;


void setup() {
  Serial.begin(9600);
  pinMode(flowPin, INPUT_PULLUP); // ustawienie pinu 2 jako wejście
  pinMode(wiatrak, OUTPUT);
  attachInterrupt(digitalPinToInterrupt(flowPin), flowISR, RISING); // dodanie przerwania do pinu 2 na stan wysoki
  digitalWrite(wiatrak, LOW);
  czasRReset = millis();
  opuznienie = millis();
  opuznienie2 = millis();
  pinMode(13, OUTPUT);

}
void loop() {
        aktualnyCzas = millis();         
             
    Serial.print("1 przeplyw = ");
    Serial.println(flowCount);

    woda = flowCount;
    Serial.print("3 woda  =");
    Serial.println(woda);

    if (woda >1){
      Serial.println("4 otwarty wiatrak");
      digitalWrite (wiatrak, HIGH);
      digitalWrite (13,HIGH);
    woda = 0;
    }
   
    else {
      Serial.println("5 Else  ");
      digitalWrite (wiatrak,LOW);
      digitalWrite (13, LOW);
    }

      if (aktualnyCzas - opuznienie >= 300) {
        Serial.println("6 kasuj czas  ");
        opuznienie = aktualnyCzas;
        flowCount = 0;
      }
     if (aktualnyCzas - czasRReset >= czasReset) {
        resetFunc();
}

}

void flowISR() {
  flowCount++; // zwiększ liczbę impulsów o 1
}
 
Odpowiedź
#2
Nie musi być błędu, pętla w Arduino może wykonywać się 16 mln x /sekundę, choć już sama funkcja millis() u Ciebie trwa kilka us, to i tak jest duża liczba częstotliwości, z 200 tys x. I tak powinno być, choć w sumie nie jest, bo wykonujesz i tak za wiele rzeczy w każdym obiegu loop - serial np. Ale jak masz kilka impulsów na sekundę, a tylu się spodziewam, skoro zauważasz okiem zgaśnięcie led, to może się zdarzyć, że pętla wykona się tysiące razy między wyzerowaniem, a pojawieniem się pierwszego impulsu.
Może coś tylko źle założyłeś działanie programu. Jeśli coś jest sterowane od przepływu wody, to powinien być cykl pomiarowy, zliczasz impulsy przez 1s, to podejmujesz decyzję po wykonaniu pomiarów i obliczeń czy wiatrak ma się kręcić czy nie po zakończeniu, raz na 1s. A Ty zmieniasz stan zasilania wiatraka w każdym obiegu loop, w każdym obiegu loop drukujesz coś na serial, co jest bez sensu.
Bardziej precyzyjnie można mierzyć czas między impulsami, jeśli jest ich kilka/s, bo inaczej, by to miało sens, trzeba wydłużyć czas pomiarowy i czas reakcji mocno rośnie.
Miło być decenianym https://buycoffee.to/kaczakat
 
Odpowiedź
#3
Wróciłem do pierwszej wersji programu z millis przed if (woda > 1). i o dziwo zadziałało tak jak chcę aby było. Nie rozumiem tylko czemu to samo wczoraj działało inaczej niż dzisiaj... ważne że działa tak jak tego oczekuję Smile
 
Odpowiedź
#4
(24-08-2023, 20:17)kaczakat napisał(a): Bardziej precyzyjnie można mierzyć czas między impulsami, jeśli jest ich kilka/s, bo inaczej, by to miało sens, trzeba wydłużyć czas pomiarowy i czas reakcji mocno rośnie.

To jest właściwa uwaga - do pomiaru czasu pomiędzy impulsami można wykorzystać wejście (funkcję) timerów - ICP - czyli możliwość zapamiętania stanu licznika/timera w momencie zmiany stanu wejścia ICP. Wartość ta jest pamiętana w dedykowanym rejestrze (i tak tkwi - więc jest sporo czasu na reakcję) i dodatkowo zgłaszane może być przerwanie. Potrzeba jeden z timerów ustawić na pracę w maksymalnym zakresie w kółko i podłączyć sygnał z przepływomierza na jego wejście ICP. W przerwaniu odczytuje się rejestr ICP, odejmuje poprzednią wartość a aktualną zapamiętuje. Gdy impulsy mogą mieć przerwy dobrze jest zabezpieczyć się wprowadzając przerwania od przepełnienia licznika - będą odmierzały "kolejne cykle licznika" i ewentualnie obsługiwały braki impulsów. Trochę podobnie działa licznik od roweru lub odbiornik IR. Konkretne nastawy timera można obliczyć na podstawie tego, czego spodziewasz się na wejściu - jakich przepływów oczekujesz.

Z kolei przy sterowaniu wiatraka można zastosować histerezę - różne wartości progów dla włączania i wyłączania. Jest pewien zakres gdy "nic się zmienia, obojętnie czy wiatrak jest włączony czy nie.". W ten sposób unikniesz "szamotania" wiatrakiem, co zwykle szybko niszczy różne urządzenia.

Natomiast co do pokazanego pierwotnie kodu: jest tam błąd (przynajmniej ja taki zauważyłem):
  1. w jednej linii (uwaga do adminów - czy kody mogą mieć numerowanie linii) czyta się zmiennią flowCount: woda = flowCount;
  2. Potem coś tam jest wypisywane serialem (co trwa).
  3. Znowy trochę dalej jest sprawdzenie czasu i ewentualne zerowanie flowCount.
Jeśli w czasie pomiędzy 1 a 3 (a nie jest mały) wystąpi przerwanie i zwiększy się flowCount to program tego nie odnotuje. Skasuje zmienna, której wartości jeszcze nie odczytał.
Tak na szybko należy zamienić miejscami czynności 2 i 1. A najlepiej byłoby wprowadzić symetrie - skoro w przerwaniu inkremetuje się, to w kodzie powinno się dekrementować. Ale to wymaga większych zmian.

I jeszcze drobiazg - nie należy wołać funkcji sprawdzających czas wielokrotnie w "jednym obiegu pętli" - wynik może się w międzyczasie zmienić. Przeczytać raz i skopiować już uzyskany wynik.
 
Odpowiedź
  


Skocz do:


Przeglądający: 1 gości