Skocz do zawartości

[Arduino][Timer millis()][Pętle]Problem z odmierzaniem czasu podczas wykonywania pętli


Bertek

Pomocna odpowiedź

Witam !

Jest to mój pierwszy post, tak więc przejdę szybciutko do rzeczy:

- Chciałbym wykonać pętlę do...while która wykonuje się wtedy, kiedy warunek "Decyzja" przyjmuje wartość false, a przerywa ją w momencie gdy wartość zmienia się na "True". Napisałem dwie funkcje, funkcja Timer oraz funkcja "Otworz_Brame" która po uaktywnieniu uruchamia również zadaną funkcję Timer, zaś funkcja Timer wpływa na wartość zmiennej Decyzja.

- Problem polega na tym, że odmierzony czas w 70% jest błędny, tj. zadając 10 sekund zazwyczaj przerywa w momencie 4,2,5,7,1 sekund, jednak nigdy nie przekracza wartości 10 sekund.

- Nadmienię, że w momencie gdy włączę ten timer w "void loop()" sprawdzając jej działanie(tj. wyświetlanie co 5 sekund tekstu) działa ona niemalże idealnie. Problem dotyczy jedynie, gdy zastosuję ją w funkcji.

Zamieszczam kody:

boolean Timer(unsigned long czas) {
 boolean TimerON = false;
 aktualnyCzas = millis();
 if (aktualnyCzas - zapamietanyCzas >= czas) {
   zapamietanyCzas = aktualnyCzas;
   TimerON = true;
 }
 return TimerON;
}
boolean Otworz_Brame(void) {
 boolean Otwarta = false;
 boolean Decyzja = false;
 byte obiekt = digitalRead(PIRPIN);
 do {
   Decyzja = Timer(10000);
   if (obiekt == LOW) {
     analogWrite(ENA, 200);
     digitalWrite(IN1, LOW);
     digitalWrite(IN2, HIGH);
   } else {
     digitalWrite(ENA, HIGH);
     digitalWrite(IN1, HIGH);
     digitalWrite(IN2, HIGH);
   }
   if(Decyzja == true) { 
     Otwarta = true;
     break;
     }
 } while (Decyzja == false);
 digitalWrite(ENA, LOW);
 digitalWrite(IN1, LOW);
 digitalWrite(IN2, LOW);
 return Otwarta;
}

Prosiłbym o łagodne potraktowanie, gdyż wciąż się uczę i tak naprawdę wciąż korzystam z wielu poradników(głównie z Waszego na blogu, jest świetny 😃)

Link do komentarza
Share on other sites

A możesz dać kompletny minimalny program w którym występuje problem? Bo po pierwsze, nie jest powiedziane, że problem jest właśnie w kodzie, który wkleiłeś, a po drugie, fajnie by było móc samemu uruchomić i zbadać.

Link do komentarza
Share on other sites

Przepraszam, myślałem że tyle wystarczy, wkleiłem na pastebin:

https://pastebin.com/STiLJVPx

Jeśli już wkleiłem całość, to chciałbym jeszcze zadać pytanie odnośnie funkcji "Odczytaj_Temperature" > Chciałem zwracać tablicę z tej funkcji, wyczytałem że dobrym sposobem jest zwrot przez wskaźniki, jednak kompletnie nie miałem o tym pojęcia, wzorowałem się na przykładach i tłumaczeniach. Czy wykonałem to w poprawny sposób ? Czy taki sposób jest odpowiedni i mogę go w przyszłości stosować z powodzeniem w innych projektach ?

Link do komentarza
Share on other sites

To niby zadziała, ale dynamiczna alokacja i usuwanie zasobu w każdej iteracji to słaby pomysł.

Zamiast tego możesz w loop zadeklarować tablicę i do funkcji przekazywać wskaźnik do niej.

  • Pomogłeś! 1
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

Pomijając to, że kod, który wkleiłeś teraz jest inny niż ten, który wkleiłeś wcześniej, nie widzę oczywistego powodu dla którego oryginalny kod miałby nie działać. W takich momentach podejrzewam albo konflikt z którąś z bibliotek, albo źle ustawioną przy kompilacji prędkość taktowania, albo jakiś memory overflow gdzieś, który nadpisuje tobie zmienne. Możesz spróbować powstawiać w kluczowych miejscach Serial.print() z wartościami tych zmiennych, żeby zobaczyć czy mają takie wartości, jak się spodziewasz.

Link do komentarza
Share on other sites

Jasny gwint,

Rzeczywiście kod jest delikatnie inny - Już tłumaczę czemu:

Szukałem przykładów zastosowania właśnie timera i testowałem różne możliwości rozpaczliwie szukając powodu błędu. Teraz poprawiłem dynamiczną alokację pamięci na wskazanie tablicy wg. porady Lukaszm,
Kod który powinienem wstawić, teraz już z poprawkami wygląda tak:

https://pastebin.com/PGnq04uk

Sprawdziłem również wyświetlanie zmiennej "Decyzja", rzeczywiście w momencie losowego(z przedziału 2-10 sekund, gdzie powinno trwać wszystko 10 sekund) pojawia się ta magiczna "1" przerywająca pętlę.

Zauważyłem że zazwyczaj ścina 4 sekundy gdy zadam mu 10 sekund. Mam takie pytanko, może uda się zastosować zegar RTC DS3231 który jest tu obecny do odmierzania czasu ?

Link do komentarza
Share on other sites

Nie mam w tej chwili pod ręką Arduino, żeby to zrobić samemu, ale możesz spróbować wypisać w funkcji Timer wewnątrz if-a jeszcze wartości aktualnyCzas - zapamietanyCzas oraz czas. Być może to coś wyjaśni.

Tak przy okazji, w C/C++ (a więc także w Arduino) przyjęło się taką zasadę, że nazwy funkcji i zmiennych zaczynają się z małej litery, a nazwy klas z wielkiej (a nazwy stałych i makr pisane są samymi wielkimi). Warto się przyzwyczaić do obowiązujących konwencji, bo wtedy się też potem te programy łatwiej czyta.

  • Pomogłeś! 1
Link do komentarza
Share on other sites

Funkcja Timer() zwraca true jeśli od jej ostatniego wywołania minęło 10s lub więcej - i to jest ok. Ale o ile rozumiem chciałbyś żeby minęło 10s od otwarcia bramy, a nie od wywołania Timer, które miało miejsce przy poprzednim otwieraniu bramy?

Spróbuj w funkcji Otworz_brame() wywołać Timer(0) przed pętlą do-while. To powinno pomóc.

  • Pomogłeś! 1
Link do komentarza
Share on other sites

Funkcja Timer() zwraca true jeśli od jej ostatniego wywołania minęło 10s lub więcej - i to jest ok. Ale o ile rozumiem chciałbyś żeby minęło 10s od otwarcia bramy, a nie od wywołania Timer, które miało miejsce przy poprzednim otwieraniu bramy?

Spróbuj w funkcji Otworz_brame() wywołać Timer(0) przed pętlą do-while. To powinno pomóc.

Miałem koledze napisać o tym, że chciałbym wykonywać pętlę właśnie przez 10 sekund. Wywołanie funkcji Timer(0) rozwiązało problem i teraz czas jest odmierzany poprawnie. Jednak chciałbym tutaj zapytać co właściwie uzyskuję poprzez takie wywołanie funkcji, czy ja tak naprawdę zeruje ten Timer i z powodzeniem mogę to polecenie wrzucić w funkcję "zerujTimer()" by wykorzystywać ją w budowaniu kolejnych funkcji opartych na Timerze ?

Zainteresuj się tym dobrze działającym rozwiązaniem:

https://starter-kit.nettigo.pl/2016/04/biblioteka-timers-16-4-0/

Myślę, że problem leży w unsigned long zapamietanyCzas = 0;

Cytując ostatni z poradników dot. programowania Arduino "W internecie znajdziemy wiele gotowych bibliotek odmierzających czas, jednak warto poznać sposób ich działania". Takim właśnie tropem podążam pisząc ten kod. Chciałbym w przyszłości przesiąść się na AVR całkowicie hobbystycznie, a Arduino jest swoistym wprowadzeniem do języka C, przynajmniej dla mnie. Bardzo dziękuję za podpowiedź w każdym razie !

Nie mam w tej chwili pod ręką Arduino, żeby to zrobić samemu, ale możesz spróbować wypisać w funkcji Timer wewnątrz if-a jeszcze wartości aktualnyCzas - zapamietanyCzas oraz czas. Być może to coś wyjaśni.

Tak przy okazji, w C/C++ (a więc także w Arduino) przyjęło się taką zasadę, że nazwy funkcji i zmiennych zaczynają się z małej litery, a nazwy klas z wielkiej (a nazwy stałych i makr pisane są samymi wielkimi). Warto się przyzwyczaić do obowiązujących konwencji, bo wtedy się też potem te programy łatwiej czyta.

Bardzo dziękuję za rady odnośnie stylu pisania, są one logiczne i jak najbardziej zamierzam się do nich stosować od teraz, kod również poprawiłem.

Chciałbym zapytać jeszcze o przerwania, czytając o nich wskazywano, że jest to użycie ostateczne gdyż utrudnia / uniemożliwia debuggowanie kodu.

Wpadłem na pomysł użycia ich w dwóch przypadkach:

- W odbiorniku radiowym prócz pinów D0-3 mam również pin VT który zmienia ze stanu niskiego w wysoki gdy odbiera jakikolwiek sygnał(którykolwiek z przycisków) - Myślę że zniwelowało by to problem opóźnionej reakcji na naciśnięcia przycisków(pojawia się ta sekunda gdy aktualnie jest wykonywany inna linijka)

- W przyszłości chciałbym dodać tutaj komunikację UART z modułem BLE, tak więc inicjując tę komunikację stworzyć przerwanie które wywoła funkcję odczytu informacji UART(RX RISING) i zwróci ją w postaci stringa.

Czy jest to dobry pomysł, czy powinienem go rozwiązać całkiem inaczej ? Jeśli tak, czy mógłbym poprosić jakieś podpowiedzi ?

Poprawiony kod:

https://pastebin.com/3XUkrB4g

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.