Skocz do zawartości

Sprawdzenie stanu pinu w określonym czasie i decyzja co robić dalej


Arthuur

Pomocna odpowiedź

Dzień dobry,

od pewnego czasu walczę z kodem do samonapełniającej się miski dla psa.

Chcę to zrobić jak najprościej, czyli:

- miska jest metalowa, więc czujnik poziomu wody zrobiony,
- pompa 12v jest,
- arduino nano jest,
- dioda LED - do sygnalizacji pracy pompy jest,
- dioda LED - do sygnalizacji ERRORU jest,

- zasilania, wszystko jest.

Mogę zakończyć program pisząc kod:

#define wlacznik 7
#define pompa 6 
#define LED 5

void setup() {
 pinMode(pompa, OUTPUT);                // Pompa na 12v - uruchomienie przekaźnika
 pinMode(wlacznik, INPUT_PULLUP);       // "Czujnik" poziomu wody
 pinMode(LED, OUTPUT);                  // LED sygnalizujący włączenie pompy
} 

void loop() {  

  if (digitalRead(wlacznik) == HIGH) {  // Jeśli brak zwarcia - niski poziom wody
   digitalWrite(LED, HIGH);             // Włącz LED
   digitalWrite(pompa, HIGH);           // Włącz pompę
   delay(6000);                         // Pompa działa 6 sek - do napełnienia miski
   digitalWrite(pompa, LOW);            // Wyłączamy pompę
   digitalWrite(LED, LOW);              // Wyłączamy LED
   delay(xxx);                              // Dla bezpieczeństwa czekamy xxx czasu, żeby w przypadku błędu pompa nie włączyła się od razu i nie zalała mieszkania ;)
  } else {
   digitalWrite(pompa, LOW);
   digitalWrite(LED, LOW);
} 
} 

Wszystko działa jak powinno, z tym, że chciałbym zrobić zabezpieczenie. Wymyśliłem sobie, że : jeśli po zadanym czasie po zadziałaniu pompy sprawdzę stan "czujnika" i będzie on wskazywał pustą miskę, to ma przerwać działanie loop i cały czas błyskać czerwonym LEDem, jeśli zaś po zadanym czasie po zadziałaniu pompy okaże się, że jest pełna to zostaje w loop :

tak sobie to wymyśliłem i nie mogę znaleźć pomocy albo chociaż wskazówki. A jeśli widziałem wskazówkę, to jej nie zrozumiałem.

Proszę Was o pomoc.

Pozdrawiam,
Artur

Link do komentarza
Share on other sites

Słabo szukałeś. Poczytaj tu: https://forbot.pl/blog/kurs-arduino-ii-wielozadaniowosc-opoznienia-z-millis-id18418 lub tu: https://starter-kit.nettigo.pl/2016/04/biblioteka-timers-16-4-0/

Zapomnij o delay().

Tak na marginesie to program cały czas jest w nieskończonej pętli loop(), może się w niej co najwyżej zatrzymać - czyli "zawiesić" np. while(1); lecz z pewnością nie chcesz pisać programów, które się "wieszają".

Pozdrawiam,

  • Lubię! 1
Link do komentarza
Share on other sites

To znaczy czego nie rozumiesz? Tego, że funkcja loop() wykonuje się bez przerwy w kółko tzn. najpierw instrukcja1, potem instrukcja2, az na koniec instrukcjaN i zaczyna od początku? Czy tego, że w czasie trwania delay() nie jesteś w stanie wykonywać żadnych inych instrukcji Lepiej złapać moment (czas np. millis()) włączenia pompy i go zapamiętać. Zakładasz sobie określony czas maksymalnego działania, a w tym czasie możesz wykonywać inne instrukcje np. sprawdzenie czujnika poziomu wody. Oczywiście w czasie sprawdzania znowu mierzysz czas (znowu np. millis()), obliczasz różnicę (tych czasów - czyli jak długo pompa już działa) i sprawdzasz czy nie przekroczyłeś założonego maksimum. Na tej podstawie (czasu) odpowiednio reagujesz.

Link do komentarza
Share on other sites

Zarejestruj się lub zaloguj, aby ukryć tę reklamę.
Zarejestruj się lub zaloguj, aby ukryć tę reklamę.

jlcpcb.jpg

jlcpcb.jpg

Produkcja i montaż PCB - wybierz sprawdzone PCBWay!
   • Darmowe płytki dla studentów i projektów non-profit
   • Tylko 5$ za 10 prototypów PCB w 24 godziny
   • Usługa projektowania PCB na zlecenie
   • Montaż PCB od 30$ + bezpłatna dostawa i szablony
   • Darmowe narzędzie do podglądu plików Gerber
Zobacz również » Film z fabryki PCBWay

Ćwiczę z Forbotem od pierwszej lekcji, więc zasadę loop() rozumiem, delay() też.

Millis() to dla mnie nowość.

Chciałem zrobić z pozoru prostą rzecz, a przerasta mnie póki co ta sprawa.

Nie chcę drążyć tematu, o którym nie mam za wiele pojęcia, dostałem wskazówki, więc odrobię pracę domową i jeśli sobie nie poradzę to będę szukał odpowiedzi na forum.

Bardzo Ci dziękuję za pomoc.

Pozdrawiam,
Artur

Link do komentarza
Share on other sites

Funkcja millis() zwraca aktualny "czas" procesora. To tak jakbyś uruchomił stoper tylko startujesz nie od 0 lecz od pewnej wartości. Kolejne wywołania millis() to tak jakbyś łapał międzyczasy, a różnica pomiędzy nimi to oczywiście czas jaki upłyną w milisekundach. Jest również dokładniejszy "stoper" - micros() - działa tak samo, lecz mierzy czas w mikrosekundach.

Narysuj sobie jak ten program ma działać za pomocą "kwadracików" i strzałek, które je połączą, W każdym "kwadraciku" napisz co ma zrobić program, a strzałką połącz z kolejnym "kwadracikiem" zawierającym dalszą część programu - narysujesz w ten sposób jego algorytm. Przeanalizuj jego prawidłowość i zamień symbole graficzne na instrukcje programu. W programie utwórz zmienne, które będą przechowywać ważne dane np. czy pompa jest włączona, kiedy ją włączyłeś (millis()), czy wystąpiła awaria itp. Z pewnością sobie poradzisz.

Pozdrawiam,

Link do komentarza
Share on other sites

Witaj,

zrobiłem tak jak zasugerowałeś i bardzo Ci za to dziękuję, wiem dokładniej czego potrzebuje.

Z tą pewnością do poradzenia sobie jest jako tako 🙂

if (digitalRead(IN)== HIGH) jeśli tak to - włącz pompę na 6 sek, jeśli nie, to nie włączaj pompy.

jeśli pompa uruchomiona (i przyjmijmy, że pomiar ma być zrobiony po 2 sek od uruchomienia pompy) to:

if (digitalRead(IN) == HIGH) jeśli tak to włącz alarm, jeśli nie, to nie włączaj alarmu.

przespałem się z tym problemem i po artykule na forbocie nie potrafię więcej niż z przykładu podanego w ćwiczeniu - co nie napawa mnie zbytnio optymizmem.

#define POMPA 4
#define IN 5
#define LED 6

unsigned long aktualnyCzas = 0;
unsigned long zapamietanyCzasPOMPY = 0;
unsigned long czasPracyPOMPY = 6000;
unsigned long czasNaBADANIE = 2000;

void setup(){
 Serial.begin(9600);
 pinMode(POMPA, OUTPUT);    // Włączenie przekaźnika
 pinMode(IN, INPUT_PULLUP); // IN jako stan wody w misce
}

void loop(){
 //Pobierz liczbe milisekund od startu
 aktualnyCzas = millis();


 if (digitalRead(IN) == HIGH) {    //Jeśli poziom wody spadnie

   zapamietanyCzasPOMPY = aktualnyCzas; //Zapamietaj czas <--- zapamiętał czas w którym momencie zabrakło wody

   digitalWrite(POMPA, HIGH); //Włacz pompę  <--- i tutaj niestety nie potrafię zadać mu zadania, by działała 6 sek.

}

Myśląc w prosty sposób aktualnyCzas - zapamietanyCzasPOMPY >= czasPracyPOMPY - wydaje mi się, że to powinno działać ale nie wiem jak umieścić to w kodzie.

idąc tym tropem aktualnyCzas - zapamietanyCzasPOMPY >= czasNaBADANIE - powinno wywołać funkcję:

if (digitalRead(IN) == HIGH) {

digitalWrite(LED, HIGH);

}

i powinno się zatrzymać - czyli albo migać ledem albo wpaść w jakąś czarną dziurę i tylko albo reset arduino albo inny guziczek z oznaczeniem reset wróci do początku kodu - nie chcę tego komplikować, chętnie sprawdzę co nie działa i zresetuje arduino.

Poniższa część kodu mówi o tym, że po zwarciu pompa po 3 sek się wyłączy - wszystko działałoby ale tylko w idealnym świecie - a potrzebne jest zabezpieczenie.


  if (aktualnyCzas - zapamietanyCzasPOMPY >= 3000UL) { // Po zamknięciu stanu niech pompuje przez 3 sek
   digitalWrite(POMPA, LOW);
 }

}

Mój problem tkwi raczej w rozumieniu wywoływania funkcji i umieszczania ich w kodzie. Jestem w stanie sobie wyobrazić, że startujemy zegar i w zasadzie się na czasie opieramy. Nie interesuje nas zbytnio jaki to czas, ważne żeby od momentu pomiaru upłynęło tyle ile nam jest potrzebne.

w moim przypadku, czas musimy zmierzyć na początku - tak żeby mieć na czym liczyć

w momencie uruchomienia pompy - bo nie wiemy kiedy się skończy woda w misce.

musimy ustalić czas pracy pompy

musimy opóźnić badanie, by sprawdzić czy woda wlewa się do miski

Pozdrawiam

Link do komentarza
Share on other sites

Może taki ogólny szkic Twojego programu?


   #define POMPA 4
   #define IN 5
   #define LED 6

   #define POMPA_TIME_MAX 6000   //maksymalny czas pracy pompy 6 s = 6000 ms

   //zmienne przedstawiające stan pompy
   int pompa=0;  //0 - wyłączona   1 - włączona  2 - error (awaria)
   #define OFF 0
   #define ON  1
   #define ERR 2

   //zmienne zawierające czas
   unsigned long time_on = 0;       //czas włączenia pompy
   unsigned long aktualny_czas=0;   //aktualny czas

   void setup()
   {
     Serial.begin(9600);
     pinMode(POMPA, OUTPUT);    // Włączenie przekaźnika
     pinMode(IN, INPUT_PULLUP); // IN jako stan wody w misce
     pompa = 0;
     time_on = 0;
   }

   void loop()
   {
     //Pobierz liczbe milisekund od startu
     aktualny_czas = millis();

     //w pętli switch w zależności od wartości zmiennej pompa wykonujemy nasz program
     switch(pompa)
     {
       //----------------------------------------------------------------------------
       case OFF:
         //pompa wyłączona więc sprawdzimy czy jest woda
         if(digitalRead(IN)==HIGH)             //jeśli brak wody
           {
             time_on=aktualny_czas;             //zapamiętaj czas włączenia
             digitalWrite(POMPA, HIGH);        //włącz pompę
             digitalWrite(LED,LOW);            //zapalamy LED - LOW czy HIGH zależy od podłączenia LED do Arduino
             pompa=ON;
           }
         break;    //wyjście ze switch
        //----------------------------------------------------------------------------
        case ON:
          //pompa włączona więc sprawdzimy czy jest woda
          if(digitalRead(IN)==LOW)             //jeśli jest wode
           {
             digitalWrite(POMPA, LOW);         //wyłącz pompę
             pompa=OFF;
             digitalWrite(LED,HIGH);            //gasimy LED - LOW czy HIGH zależy od podłączenia LED do Arduino
           }
          else if(aktualny_czas>=time_on+POMPA_TIME_MAX)    //wody nie ma więc sprawdzimy czy pompa nie pracuje za długo
           { //czas minął więc jest awaria!
              digitalWrite(POMPA, LOW);       //wyłącz pompę na wszelki wypadek
              pompa=ERR;
           }
          break;   //wyjście ze switch
        //----------------------------------------------------------------------------
        case ERR:
              digitalWrite(POMPA, LOW);       //wyłącz pompę na wszelki wypadek          
        defalut:
         //jeśli pompa jest różna od ON, OFF i ERR to nie rób nic - wyjdź z pętli switch
         break;
     } //koniec switch
   }

UWAGA: Po ok. 50 dniach "stoper" zwracany przez millis() się wyzeruje - zacznie liczyć od 0 - pomyśl jak się przed tym zabezpieczyć. Ja bym się jeszcze zastanowił nad wiarygodnością wskazań czujnikia - to chyba jest ważne.

Co do funkcji - to najbardziej ogólnie mówiąc jest to fragment kodu programu ujęty w nawiasy klamrowe, który posiada swoją nazwę. Do funkcji możesz przekazywać parametry, lub nie. Funkcja może także zwracać wynik lub nie - to zależy jak swoją funkcję zadeklarujesz. Na przykład funkcja, które nie zwraca wyniku i nie oczekuje parametrów:

void MojaFunkcja() //void oznacza że niczego funkcja nie zwraca MojaFunkcja to jej nazwa () oznacza, brak parametrów przekazywanych do funkcji
{
 Serial.println("wykonuje się MojaFunkcja()");
}

Funkcje to "podprogramy", które wywołuje się z programu głównego za pomocą ich nazw. Po zakończeniu pracy funkcja wraca do miejsca skąd została wywołana i główny program kontynuuje swoją pracę.

Przykład:

void setup()
   {
     Serial.begin(9600);
     pinMode(POMPA, OUTPUT);    // Włączenie przekaźnika
     pinMode(IN, INPUT_PULLUP); // IN jako stan wody w misce
     pompa = 0;
     time_on = 0;
    MojaFunkcja();
   }

Pozdrawiam,

  • Lubię! 1
Link do komentarza
Share on other sites

Bardzo dziękuję za ogromną pomoc i z ogromnym zapałem czytam kod i staram się go pojąć.

Zmieniam zmienne, żeby widzieć jak reaguje i jak można go modyfikować.

Dłubię i dłubię, jak go przerobie na ten, który mi odpowiada, to napiszę go tutaj, tak dla sprawdzenia, czy myślę w dobry sposób.

Do tego kodu, który napisałeś, muszę zdefiniować LIMIT - tj. gdy pompa w ciągu tych 6 sek. nie dopompuje wody do określonej wysokości w misce.

Włączyłem lutownicę i składam póki co elementy.

Chętnie podzielę się wynikami mojej pracy i Twojego kodu 🙂

Jeszcze raz dziękuję

Link do komentarza
Share on other sites

Do tego kodu, który napisałeś, muszę zdefiniować LIMIT - tj. gdy pompa w ciągu tych 6 sek. nie dopompuje wody do określonej wysokości w misce.

Chyba nie musisz bo wtedy program wykryje błąd.

else if(aktualny_czas>=time_on+POMPA_TIME_MAX) //wody nie ma więc sprawdzimy czy pompa nie pracuje za długo

{ //czas minął więc jest awaria!

digitalWrite(POMPA, LOW); //wyłącz pompę na wszelki wypadek

pompa=ERR;

}

Link do komentarza
Share on other sites

Wszystko się zgadza, błąd będzie.

Z tym, że próbując już na płytce prototypowej zasymulować daną sytuację, nie działało tak jakbym chciał.

W czym problem?

Jeśli blisko dna miski jest czujnik (IN) - niefortunna nazwa - to gdy tylko zabraknie wody, włączy się pompa i woda zasłoni czujnik (IN) - pompa przestanie działać, czyli napełni się tylko ok 1cm wody w misce.

W sytuacji gdy dołożę czujnik (LIMIT) i wrzucę go w "case:ON"

case ON: 
          //pompa włączona więc sprawdzimy czy jest woda 
          if(digitalRead(LIMIT)==LOW)             //jeśli woda osiągnie poziom MAX w misce ale czas pracy pompy nie przekroczy 6 sek 
           { 
             digitalWrite(POMPA, LOW);         //wyłącz pompę 
             pompa=OFF; 
             digitalWrite(LED, LOW);            //gasimy LED - LOW czy HIGH zależy od podłączenia LED do Arduino 
           } 
          else if(aktualny_czas>=time_on+POMPA_TIME_MAX)    //wody nie ma więc sprawdzimy czy pompa nie pracuje za długo 
           { //czas minął więc jest awaria! 
              digitalWrite(POMPA, LOW);       //wyłącz pompę na wszelki wypadek 
              pompa=ERR; 
           } 
          break;   //wyjście ze switch 

w tym przypadku pompa wyłączy się po osiągnięciu poziomu "LIMIT" ale napełni się krócej niż 6 sek - jeśli nie osiągnie tego pułapu - wskoczy nam ERR

Co jest jak najbardziej pożądane!!! 🙂

Czy może jestem w błędzie?

Link do komentarza
Share on other sites

w tym przypadku pompa wyłączy się po osiągnięciu poziomu "LIMIT" ale napełni się krócej niż 6 sek - jeśli nie osiągnie tego pułapu - wskoczy nam ERR

Troszeczkę Cię nie rozumiem. Ten czas 6 sekund jaki sobie określiłeś to rozumiem czas max. do napełnienia miski i nie ma nic wspólnego z tym jak ona szybko się napełni - to musisz wykryć czujnikiem(ami).

Polecenie digitalRead(COS_TAM) nie mierzy poziomu sygnału (wody) lecz tylko odczytuje stan pinu cyfrowego Arduino, który sobie nazwałeś LIMIT. Pisząc o dołożeniu czujnika rozumiem, że tak jak w misce olejowej samochodu będziesz wykrywał poziom MIN i MAX wody w misce. Jeśli tak to osiągnięcie MAX oczywiście powinno pompę wyłączyć (sprawdzane w case ON), a zejście poniżej MIN pompę włączyć (sprawdzane w case OFF:). Tak na marginesie gdzieś widziałem zastosowanie czujnika ultradźwiękowego do pomiaru poziomu napełnienia zbiornika, ale czy przy misce czujnik miałby wystarczającą rozdzielczość? Nie wiem. No i zawsze Azor może miskę przesunąć, uszkodzić czujniki .... i co wtedy?

Pozdrawiam,

Link do komentarza
Share on other sites

Być może, że w pewnym momencie się nie zrozumieliśmy, choć to co napisałeś jest właściwie tym czego potrzebuje.

Jest zabezpieczenie w formie tych 6 sek. Jest pin, jak określiłeś MIN (stan zamknięty i otwarty) i MAX - wszystko się zgadza i teoretycznie działa - teoretycznie, bo na płytce prototypowej.

Przechodzę do praktyki i powoli składam elementy w całość.

Jestem Ci ogromnie wdzięczny. Teraz będę próbował opierać nowe rzeczy na czasach i na case.

Jeśli chodzi o ultradźwiękową czujkę, to można ją przymocować na stałe do miski, ale nie chce aż tak komplikować sprawy. Ultradźwiękowa czujka odległości sprawdza się w baniaku z wodą, z której woda jest pompowana do miski - jako wskaźnik poziomu wody i to się sprawdza - najprościej na błyskającej ledzie, która informuje nas o niskim stanie wody w baniaku. Do tego można dorzucić wyświetlacz OLED, czy 1602 i wszystko pokazywać co się dziej i w jakim case jesteśmy, dołożyć klawiaturę i zmieniać czas pompy, przypadku innych misek - możliwości jest dużo 🙂

Link do komentarza
Share on other sites

Dołącz do dyskusji, napisz odpowiedź!

Jeśli masz już konto to zaloguj się teraz, aby opublikować wiadomość jako Ty. Możesz też napisać teraz i zarejestrować się później.
Uwaga: wgrywanie zdjęć i załączników dostępne jest po zalogowaniu!

Anonim
Dołącz do dyskusji! Kliknij i zacznij pisać...

×   Wklejony jako tekst z formatowaniem.   Przywróć formatowanie

  Dozwolonych jest tylko 75 emoji.

×   Twój link będzie automatycznie osadzony.   Wyświetlać jako link

×   Twoja poprzednia zawartość została przywrócona.   Wyczyść edytor

×   Nie możesz wkleić zdjęć bezpośrednio. Prześlij lub wstaw obrazy z adresu URL.

×
×
  • Utwórz nowe...

Ważne informacje

Ta strona używa ciasteczek (cookies), dzięki którym może działać lepiej. Więcej na ten temat znajdziesz w Polityce Prywatności.