Skocz do zawartości

Wielozadaniowość, millis, automatyka domowa


Philip

Pomocna odpowiedź

No to ja mam troszkę inne podejście - wolę wywalić kod do kosza (czy wyjaśnić, dlaczego tam jest jego miejsce) niż próbować łatać coś, co łatane być nie powinno. Wbrew pozorom, napisanie kodu od zera z zupełnie nowymi założeniami może być (i z reguły jest) szybsze niż poprawianie poprawek po poprawianych poprawkach 🙂

Czyli - Ty pokazujesz co da się z tym zrobić, ja pokazuję czego się nie da 🙂

A wracając do przerabianego delaya:

To akurat bardzo niebezpieczne podejście. Przede wszystkim - jeśli program ma robić równolegle dwie rzeczy, trzeba wybrać która z nich będzie w głównym kodzie. Dalej: milcząco zakładamy, że ów pseudoDelay będzie wywoływany regularnie (no bo przecież jest to potrzebne do działania pobocznego wątku) - a to wcale nie jest takie oczywiste.

A co zrobić jeśli program ma robić trzy rzeczy? Cztery? Pięć? Pikać przy otwarciu drzwi, podlewać kwiatki jak mają mało wody, odsłaniać/zasłaniać rolety w określonej porze dnia lub na sygnał z pilota, to samo ze światłem, a na schodach to światło ma już działać absolutnie automatycznie bez żadnych wyłączników, i jeszcze żeby wyświetlał na wyświetlaczy temperaturę w Pernambuco?

Niebezpieczeństwo tkwi w braku elastyczności rozwiązania.

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

ethanak, ma rację. Używanie delay'a jest bez sensu, jeśli mamy w między czasie robić kilka innych rzeczy. Chyba, że wiemy, że chcemy w danym momencie zatrzymać program i na pewno nic w tym momencie Arduino nie będzie robić innego.

Z waszej rozmowy wyszła mała kłótnia 😉

Poczytałem o tych automatach skończonych i zrozumiałem o co w tym chodzi. W moim przypadku daje to dużo do myślenia co do samego programowania i jest bardzo pomocne. Zrobiłem graf dla mojej sytuacji. Mam nadzieję, że dobrze.

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

Philip, od dziś jestem Twoim fanem. Jesteś chyba pierwszą osobą tutaj, która na sugestię poczytania o automatach zadała sobie trud, zrobiła to i co więcej - spróbowała tego użyć w rozwiązaniu swojego problemu. Oby tak dalej chłopie. Moim zdaniem odkrycie FSM-ów na jakimś etapie amatorskiej kariery programistycznej całkowicie zmienia sposób podejścia do planowania i implementacji algorytmów oraz raz na zawsze uwalnia od klepania arduinowego kanonu "zróbcoś-delay-zróbcoś-delay-zróbcoś..". Mam nadzieję, że podrążysz temat i pod okiem ethanaka zaprezentujesz wkrótce ładny program.

A gdy jeszcze zrozumiesz jak na małym procesorku puszczać wiele automatów robiących różne rzeczy jednocześnie, będziesz się dziwił jak można było tak dreptać w miejscu jak kiedyś.

Link do komentarza
Share on other sites

@Philip: Jest OK!

Ja bym tylko kosmetycznie zmienił punkt startowy o jeden w tył (na oczekiwanie na zamknięcie drzwi) - po prostu żeby mi nic nie wyło w momencie, kiedy drzwi są otwarte i włączam zasilanie Arduino. Ale to kwestia Twojego wyboru, być może z jakichś przyczyn chcesz aby wyło (np. włączając Arduino chcesz wiedzieć, czy drzwi są otwarte).

No, to teraz kod.

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

Wszystko się da - jeden ruski żołnierz jak wrócił narąbany z przepustki to udowodnił, że da się włożyć hełm na lewą stronę...

Piszesz, że Ty robisz tak a tak... A ja np. nie bawię się w rysowanie kółeczek, rozpisywanie algorytmów w jakichś tam wymyślnych językach tylko siadam i piszę od razu w C czy Pythonie, algorytmy mam w głowie a kod sam spod palców wychodzi...

Tyle że ja mam prawie 40 lat praktyki w programowaniu i w związku z tym ani mi w głowie polecanie takiego podejścia młodym ludziom, którzy dopiero się uczą podstaw.

Nie odpowiada Ci to że chcemy tu młodych nauczyć prawidłowego podejścia? Dlaczego?

Link do komentarza
Share on other sites

marek1707, dzięki za miłe słowa. 😉 Mam nadzieję, że będzie jak piszesz.

ethanak, w końcu jest kod. Automat działa tak jak napisałeś jeszcze wcześniej, tylko jakim cudem przy zamykaniu drzwi te dwa dźwięki się odtwarzają. To nie jest ta sytuacja co była przy moim poprzednim kodzie. Teraz przy otwarciu tak jak chciałem: dźwięk 1, dźwięk 2, cisza i nic nie chodzi, a przy zamknięciu się to powtarza. Jest progress przynajmniej, ale nie do końca działa tak jak powinno.

#define KONTAKTRON 16
#define BUZZER 17

unsigned long aktualnyCzas = 0;             //Zmienne do liczenia czasu
unsigned long zapamietanyCzas = 0;
int glosnosc1 = 500;                        //Zmienna do zmiany glośności buzzera
int glosnosc2 = 1000;
int stan = 1;

void setup() {
 Serial.begin(9600);  
 pinMode(BUZZER,OUTPUT);
 pinMode(KONTAKTRON,INPUT_PULLUP);
}

void loop() { 
 aktualnyCzas = millis();  

  switch(stan){
   case 1:
   if(digitalRead(KONTAKTRON)==HIGH){              //Jeśli drzwi otwarte
       if(aktualnyCzas - zapamietanyCzas >=500UL){ //Ile upłynęło
       zapamietanyCzas = aktualnyCzas;
       tone(BUZZER,glosnosc1);                     //Odtwarzam dźwięk1
       stan = 2;                                   //Przełączam na stan2
     }
   }
   break;

   case 2:
   if(aktualnyCzas - zapamietanyCzas >=500UL){    //Jeśli upłynął czas
       zapamietanyCzas = aktualnyCzas;
       tone(BUZZER,glosnosc2);                    //Odtwarzam dźwięk2
       stan = 3;                                  //Przełączam na stan3
     }
    break;

     case 3:
     if(aktualnyCzas - zapamietanyCzas >=500UL){  //Jeśli upłynął czas
       zapamietanyCzas = aktualnyCzas;
       noTone(BUZZER);                            //Nie odtwarzam dźwięków
       stan = 4;
     }
     break;

     case 4:
     if(digitalRead(KONTAKTRON)==HIGH){           //Jeśli drzwi otwarte
     } else {                                     //Nic nie robię
     stan = 1;                                    //Jeśli nie przełączam na stan1
     }
     break;
  } 
}

Odkryłem jeszcze, że przy wolnym zamknięciu drzwi występuje ten dźwięk, a przy szybkim zamknięciu go nie ma. Może program traktuje to "wolne zamknięcie" jako otwarcie ... a jest to wynikiem tego właśnie, że robię to wolno.

Biblioteka bounce2, o której wcześniej wspomniałeś do czego ona w rzeczywistości służy? Ściągnąłem ją sobie i popatrzyłem na przykłady i tak nie do końca rozumiem do czego ona jest przydatna.

Link do komentarza
Share on other sites

Przecież ani razu nie powiedziałem, żeby nie robił tak jak mu radzicie :f

Zawsze istnieje szansa, że przy zamykaniu może być tak, że czujnik złapie otwarcie/zamknięcie/otwarcie/zamknięcie lub coś w podobie, a przy obiegu pętli wystarczy tyle, żeby przejść dalej.

EDIT. Dla testu między stanem 4 a 1 dałbym opóźnienie i zobaczył, czy problem występuje.

EDIT2. http://mirekk36.blogspot.com/2012/10/drgania-stykow-to-bajki-wiec-jak-to.html np.

Link do komentarza
Share on other sites

Biblioteka Bounce2 służy m.in. do tego, abyś nie miał dźwięku przy zamykaniu drzwi.

A teraz pomyśl dlaczego. Zacznij od porady @BananWszyscy i wrzuć (na razie oczywiście) delay(500) przed ustawieniem stanu z 4 na 1. Jeśli nie będzie dźwięku to wszystko jasne. Jeśli będzie to masz popsuty lub źle założony kontaktron.

Link do komentarza
Share on other sites

Philip, zamiast używać armaty na wróbla, czyli biblioteki Bounce2 możesz też po prostu poprawić program. Proponuję się przyjrzeć zmiennej zapamietanyCzas. Jaką ma wartość i znaczenie gdy wchodzi się do stanu 1? Jak to poprawisz to będziesz miał eliminację styków w gratisie 🙂

Inna sprawa że to piękny przykład na wady programowania w oparciu o automaty stanów - łatwo o trudne do zauważenia błędy.

Link do komentarza
Share on other sites

Nie ma tego jednego dźwięku. Trzeba równo przykładać kontaktron, bo przypuszczam, że po prostu czasami wyłapuje to jako otwarcie. Cieszę się, że działa 😃 W końcu.

Jak buzzer nie chodzi to słychać z niego takie bardzo ciche brzękanie. To jest to wasze drganie styków.

Elvis, co dopiero się nauczyłem tych automatów i znowu źle 😃 (żart)

Link do komentarza
Share on other sites

Philip, nie odbieraj tego jako krytyki, po prostu masz drobny błąd - który można łatwo poprawić i chociaż drgania styków nie będą problemem (o ile w ogólne nim były).

[ Dodano: 01-08-2018, 16:49 ]

Ale podpowiem, masz taki kod:

    case 1:
   if(digitalRead(KONTAKTRON)==HIGH){              //Jeśli drzwi otwarte
       if(aktualnyCzas - zapamietanyCzas >=500UL){ //Ile upłynęło 

Nie wiem po co to dodałeś, ale zakładam że chcesz zareagować dopiero jak drzwi są otwarte przez 500ms. Niestety zmienna zapamiętanyCzas ma najpierw 0, co może i jest ok, ale po pierwszym cyklu automatu ma wartość zapisaną ostatnio w stanie 3. Więc to opóźnienie 500ms może nie zadziałać - a gdyby działało to wyliminowałoby drgania styków niejako w gratisie.

Link do komentarza
Share on other sites

Nie rozumiem trochę co masz na myśli. Chodzi ci, że automat może nie wejść w stan 1 po otworzeniu drzwi?

Nie ma pomysłu jak to zmienić. Moim zdaniem wszystko z tym jest OK 🙂

Cóż tu można zmienić. Czas ten się odlicza po to, aby buzzer wydał z siebie pierwszy dźwięk.

Link do komentarza
Share on other sites

Trochę chyba chodzi o to, że za 1. obiegiem stanów ten zapamiętanyczas jest jakaś, potem już nigdzie nie jest zapisana (na końcu). Ale niezbyt wiem na co miałaby mieć wpływ, że przez nią wchodzimy w część kodu od ding dong. Raczej chodzi tu o to, że on jest kilka razy załączany.

Dla wyobrażenia sobie tych styków możesz kiedyś dla treningu napisać kodzik dla samego kontraktronu z licznikiem, ile razy zmienia swój stan z jednego na drugi tylko przy zamknięciu drzwi, a może coś zaobserwujesz.

EDIT. poprawiłęm gapę 😋

Link do komentarza
Share on other sites

Nie, nie jest ok - niestety. Pomyśl, albo narysuj co dzieje się ze zmienną zapamietanyCzas.

O ile rozumiem taki kod:

 if(aktualnyCzas - zapamietanyCzas >=500UL){

Służy do wprowadzania opóźnienia, czyli to odpowiednik prostego i bezawaryjnego delay(500).

Niestety żeby to zadziałało na "początku czasu" trzeba przypisać aktualną wartość do zmiennej zapamiętanyCzas.

Poprawnie robisz np. tutaj:

      case 3:
     if(aktualnyCzas - zapamietanyCzas >=500UL){  //Jeśli upłynął czas
       zapamietanyCzas = aktualnyCzas;
       noTone(BUZZER);                            //Nie odtwarzam dźwięków
       stan = 4;
     }

Przy następnym obrocie pętli zmienna będzie miała poprawną wartość i opóźnienie w stanie 4 zadziała prawidłowo.

Po prostu przy wyjściu ze stanu 4 zabrakło ustawienia wartości tej nieszczęsnej zmiennej.

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.