Skocz do zawartości
kris2k

Arduino i CanShield - programowe usprawnienia auta

Pomocna odpowiedź

Cześć Wszystkim.

Od pewnego czasu bawię się Arduino i nakładką w postacie tzw. CanShielda.

Celem tych zabaw, z jednej strony jest poszerzenie swojej własnej wiedzy z zakresu elektryki/elektroniki i programowania mikro-kontrolerów a z drugiej, wzbogacenie swojego leciwego Grande Punto o pewne funkcje których brak mnie irytuje.

Pewne kroki już zostały poczynione, ich ślady można podglądnąć na moim kanale na YT: https://www.youtube.com/channel/UCw2ESPv-JkCw7IwaaS1Ac2A?view_as=

Na początek postawiłem sobie niby proste zadanie, a mianowicie, dołożenie tzw. TripLinka zwanego też "komfortowym kierunkowskazem".

Czyli chwilowe przytrzymanie dźwigienki powoduje automatyczne trzykrotne mrugnięcie kierunkowskazu.

Teraz tak, w Grande Punto, proces migania kierunkowskazami inicjowany jest poprzez zwarcie z sobą 2 przewodów, w przypadku mrugania w lewo zwarcie jest do masy, w przypadku mrugania w prawo ta sama para przewodów zwierana jest dodatkowo przez opornik. Efektem jest to, że BCM rozpoznaje poziom napięcia na tych przewodach i podaje bezpośrednio na inne przewody +12V (na lewą bądź prawą stronę auta).

Jestem na etapie na którym walczę z funkcją millis(), mój kod na którym ćwiczę programowanie wygląda tak:


unsigned long aktualnyCzas = 0;
unsigned long zapamietanyCzas01 = 0;
unsigned long zapamietanyCzas02 = 0;
int licznik = 0;
boolean click1 = false;

void setup() {
  pinMode(6, INPUT_PULLUP); //Przycisk jako wejście
  pinMode(7, INPUT_PULLUP); //Przycisk jako wejście
  pinMode(2, OUTPUT);
  
  Serial.begin(115200);
  Serial.println("POWITANIE");
}

void loop() {

  aktualnyCzas = millis();
  
  if (digitalRead(6) == LOW ) { //Jeśli przycisk wciśnięty
    zapamietanyCzas01 = aktualnyCzas;
    click1 = true;
    licznik = 1;
    //Serial.println(aktualnyCzas - zapamietanyCzas01); //zero caly czas
    //Serial.println(aktualnyCzas - zapamietanyCzas02); //wartosc zeruje sie w momencie klikniecia i rosnie z czasem    
  } else {
    zapamietanyCzas02 = aktualnyCzas; //warunek zawsze sie spelnia w naturalny sposob po odpaleniu Arduino i daje ZERO od razu!!!
    click1 = false;
    //Serial.println(aktualnyCzas - zapamietanyCzas01); //wartosc zeruje sie w momencie klikniecia i rosnie z czasem
    //Serial.println(aktualnyCzas - zapamietanyCzas02); //zero caly czas
  }

  if (aktualnyCzas - zapamietanyCzas02 <= 1000UL and click1 == true) {
    Serial.println("Czynność A < ponizej 1 sek.");  
  } else if (aktualnyCzas - zapamietanyCzas02 > 1000UL and click1 == true) {
      Serial.println("Czynność B > ponad 1 sek.");
    }
  
 delay(100);
}

Efekt jaki wypluwa z siebie monitor portu szeregowego jest taki:

POWITANIE
Czynność A < ponizej 1 sek.
Czynność A < ponizej 1 sek.
Czynność A < ponizej 1 sek.
Czynność A < ponizej 1 sek.
Czynność A < ponizej 1 sek.
Czynność A < ponizej 1 sek.
Czynność A < ponizej 1 sek.
Czynność A < ponizej 1 sek.
Czynność A < ponizej 1 sek.
Czynność A < ponizej 1 sek.
Czynność A < ponizej 1 sek.
Czynność B > ponad 1 sek.
Czynność B > ponad 1 sek.
Czynność B > ponad 1 sek.
Czynność B > ponad 1 sek.
Czynność B > ponad 1 sek.
Czynność B > ponad 1 sek.
Czynność B > ponad 1 sek.
Czynność B > ponad 1 sek.
Czynność A < ponizej 1 sek.
Czynność A < ponizej 1 sek.
Czynność A < ponizej 1 sek.
Czynność A < ponizej 1 sek.
Czynność A < ponizej 1 sek.
Czynność A < ponizej 1 sek.
Czynność A < ponizej 1 sek.
Czynność A < ponizej 1 sek.
Czynność A < ponizej 1 sek.


Oznacza to nic innego,  że dopóki warunki czasowe są spełnione, to non-stop wykonywana jest Czynność A lub Czynność B.

A ja to bym chciał aby w takich warunkach czynność A lub B wykonała się ale tylko RAZ, a najlepiej 3 RAZY w odpowiednim odstępie czasowym... nie ciągle w koło, jak to poprawnie zrobić?

W domyśle, pod czynnością A będzie moje trzykrotne mignięcie kierunkiem, czyli w praktyce nadanie stanów 1/0/1/0/1/0 na jedno z wyjść którym wysteruje przekaźnik zwierający przewody.

 

Udostępnij ten post


Link to post
Share on other sites
1 godzinę temu, kris2k napisał:

A ja to bym chciał aby w takich warunkach czynność A lub B wykonała się ale tylko RAZ

To może zapamiętaj, że już została wykonana?

Udostępnij ten post


Link to post
Share on other sites

A inaczej: niech czynność A wykona się RAZ, ale będzie się składała z sześciu etapów (włącz - wyłącz - włącz - wyłącz- - włącz - wyłącz).

Robiłem latem coś podobnego kumplowi do motocykla, wyglądało to mniej więcej tak (nie mam kodu przed sobą, ale jakoś podobnie):

digitalWrite(PRZEKAZNIK, (millis() - startTime) % CZAS_MIGNIECIA < CZAS_MIGNIECIA / 2);

I oczywiście nie mam żadnych delajów w loop 🙂 - kręci się aż millis() - startTime będzie większa niż 2.5 * CZAS_MIGNIECIA.

 

 

Udostępnij ten post


Link to post
Share on other sites
(edytowany)
21 godzin temu, Belferek napisał:

To może zapamiętaj, że już została wykonana?

Panowie, dwa posty i dwie bardzo cenne dla mnie rady. Chciałbym przedyskutować obie, zacznę od pierwszej. Zrobiłem to tak jak w kodzie poniżej i mam pewien efekt uboczny który nie wiem skąd się bierze 😕 (Myślałem że to mój tactile switch drga, podmieniłem na inny, to samo, podmieniłem na kabelek którym sam robię stycznik, dalej to samo.)

  if (digitalRead(6) == LOW ) { //Jeśli przycisk wciśnięty
    licznikA++; // zmienna która ma mi dawać gwarancję że warunek wykona się tylko raz przy == 1
    zapamietanyCzas01 = aktualnyCzas;
    click1 = true; 
  } else {
    zapamietanyCzas02 = aktualnyCzas; 
    click1 = false;
  }


  if (aktualnyCzas - zapamietanyCzas02 <= 1000UL and click1 == true) {
    if (licznikA == 1) {
    Serial.println("Czynność A < ponizej 1 sek.");  
    }
  } else if (aktualnyCzas - zapamietanyCzas02 > 1000UL and click1 == true) {
      Serial.println("Czynność B > ponad 1 sek."); 
    }

Efekt:

Czynność A < ponizej 1 sek.
Czynność A < ponizej 1 sek.
Czynność B > ponad 1 sek.
Czynność B > ponad 1 sek.
Czynność B > ponad 1 sek.
Czynność B > ponad 1 sek.
Czynność B > ponad 1 sek.
Czynność B > ponad 1 sek.
Czynność B > ponad 1 sek.

Czynność A wykonuje się DWA razy, zawsze dwa! O co tu u licha chodzi?

Program startuje ze zmienną globalną licznikA = 0, czyli zwarcie obwodu z automatu ustawia tą wartość na 1 a skoro program wykonuje się linia po linii, to w drugim obiegu zmienna ustawi się na 2 i z automatu drugi raz warunek się nie wykona... a tu proszę, ewidentnie zawsze czynność A pojawia się dwa razy.

________________________________________________________________________________________________________________________________________________________________

Przypadek drugi:

21 godzin temu, ethanak napisał:

A inaczej: niech czynność A wykona się RAZ, ale będzie się składała z sześciu etapów (włącz - wyłącz - włącz - wyłącz- - włącz - wyłącz).

Robiłem latem coś podobnego kumplowi do motocykla, wyglądało to mniej więcej tak (nie mam kodu przed sobą, ale jakoś podobnie):


digitalWrite(PRZEKAZNIK, (millis() - startTime) % CZAS_MIGNIECIA < CZAS_MIGNIECIA / 2);

I oczywiście nie mam żadnych delajów w loop 🙂 - kręci się aż millis() - startTime będzie większa niż 2.5 * CZAS_MIGNIECIA.

Bardzo fajny ten kod, właśnie chcę za wszelka cenę uniknąć używania delayów i pętli w których program mógłby utknąć, implementacja wygląda tak:

  int CZAS_MIGNIECIA = 1000;
  if (aktualnyCzas - zapamietanyCzas02 <= 1000UL and click1 == true) {
    if (licznikA == 1) {
    Serial.println("Czynność A < ponizej 1 sek.");  
    }
  } else if (aktualnyCzas - zapamietanyCzas02 > 1000UL and click1 == true) {
      //Serial.println("Czynność B > ponad 1 sek.");
      long x = 0; // sztuczna zmienna dla mojej wygody przy cwiczeniu programowania
      x = ( ((aktualnyCzas - zapamietanyCzas02) % CZAS_MIGNIECIA) < (CZAS_MIGNIECIA / 2) ); //wyrażenie obliczające x
      licznikA = 0;
      Serial.println(x); // drukujemy x
    }

Efekt jest taki, że wydruk stanu 1 / 0 zmienia się co sekundę ale trwa w nieskończoność, a ja chciałbym żeby wykonał się 3 razy, jak to dobrze zmodyfikować?

Edytowano przez kris2k

Udostępnij ten post


Link to post
Share on other sites
1 godzinę temu, kris2k napisał:

if (aktualnyCzas - zapamietanyCzas02 <= 1000UL and click1 == true)

Czy to aby dobra konstrukcja? Raczej używamy np:

if(aktualnyCzas - zapamietanyCzas02 <= 1000UL && click1 == true).......

Co będzie gdy przycisk będzie na stale wciśnięty? Twoja zmienna licznikA nie zlicza wykonanych czynności lecz się zwiększa pod wpływem stanu LOW na porcie czujnika, a to chyba nie to samo.

Zobacz ten artykuł - może się przyda i coś podpowie - zobacz

Udostępnij ten post


Link to post
Share on other sites

Masz rację, powinienem stosować "&&" zamiast "and".

Owszem, moja zmienna nie liczy wykonanych czynności, to tylko taki mój skrót myślowy, użyłem jej do zagwarantowania wykonania się czynności tylko raz, nie przeszkadza mi to że rośnie wraz z upływam czasu wciśnięcia przycisku.

Wskazany artykuł bardzo przydatny, będę stosował tam gdzie napotkam problemy ze stycznikami, tutaj mój tactile jest tylko i wyłącznie użyty do ćwieczeń, w aucie go rzecz jasna nie będzie.

Podejrzewasz w takim razie że te podwójne wystąpienie to jest właśnie problem drgających styczników czy raczej problem złego zastosowania zmiennej? Siedze przy tym kawałku kodu cały wieczór i dalej nie rozumiem dlaczego wykonuje się dwa razy :/

Udostępnij ten post


Link to post
Share on other sites
(edytowany)

A do czego potrzebny jest w programie zapamietanyCzas01? Czy aby dobrze przemyślałeś wykorzystanie tych zmiennych? Narysuj sobie algorytm tego programu  i przełóż na kod. Przemyślany algorytm bardzo pomaga,  a przy problemach z ogarnięciem millis() może pomóc ten artykuł.

Edytowano przez Belferek

Udostępnij ten post


Link to post
Share on other sites

Obie zmienne wprowadziłem na potrzeby zobrazowania sobie różnicy w upływie czasu pomiędzy kliknięciem w przycisk a nie kliknięciem w przycisk w ogóle.

Jak widzisz, pierwszy wstawiony kod ma tam wrzucone drukowanie się na ekran zawartości z odejmowania obu par z komentarzem co się z nimi dzieje. To jest taki mój sposób na uwidocznienie zmian w programie gdy nie wiem co się dzieje... czyli drukuje printem dane i w ten sposób sprawdzam jak program działa krok po kroku (brak debuggera :/ ).

Coś złego tam dostrzegasz?

Udostępnij ten post


Link to post
Share on other sites

To wklej kod programu w którym wykorzystujesz zapamietanyCzas01. Ja nie znajduję tego wykorzystania. Popracuj nad algorytmem, narysuj go sobie - to pomaga zaoszczędzić duuużo czasu.

Udostępnij ten post


Link to post
Share on other sites

Widzę że edytowałeś poprzednią odpowiedź, chciałeś mi pokazać jakiś artykuł o millis() ale link to ten sam co wcześniej do drgających styczników 😉

Udostępnij ten post


Link to post
Share on other sites
(edytowany)

rzeczywiście - prawidłowy link

Może taki sposób działania programu byłby właściwy?

1. Sprawdź przycisk.
2. Jeśli NIE wciśnięto to skok do 7
3. Zamigaj 3 razy
4. Sprawdź przycisk.
5. Jeśli ZWOLNIONY to skocz do 7
6. Skocz do 4
7  Opóźnienie
8. Skok do 1

Edytowano przez Belferek

Udostępnij ten post


Link to post
Share on other sites
8 godzin temu, Belferek napisał:

rzeczywiście - prawidłowy link

Może taki sposób działania programu byłby właściwy?

1. Sprawdź przycisk.
2. Jeśli NIE wciśnięto to skok do 7
3. Zamigaj 3 razy
4. Sprawdź przycisk.
5. Jeśli ZWOLNIONY to skocz do 7
6. Skocz do 4
7  Opóźnienie
8. Skok do 1

To jest super konstrukcja programu... przypomina mi VisualBasic i funkcje "Go To" "Then"... Przerobiłem oba kursy Arduino na Forbocie już jakiś czas temu, ale nie kojarzę aby było coś takiego omówione. Poszperam w tych materiałach jeszcze raz... (Używanie "and" zamiast "&&" też mi się wzięło z VisualBasica 😉 )

Udostępnij ten post


Link to post
Share on other sites

Funkcji, czy to polecenia goto oczywiście w Arduino IDE nie znajdziemy, ale z powodzeniem można to zastąpić sprawdzaniem warunków if{} else {}switch - case czy też korzystając z wywołania własnych funkcji.

Udostępnij ten post


Link to post
Share on other sites
10 minut temu, Belferek napisał:

Funkcji, czy to polecenia goto oczywiście w Arduino IDE nie znajdziem

A szukałeś, czy zakładasz że nie bo nie?

Oczywiście goto jak najbardziej jest, w końcu to element języka C oraz C++, więc nie tylko jest ale i działa.

Udostępnij ten post


Link to post
Share on other sites

w Arduino reference(tutaj) można przeczytać:

"The use of goto is discouraged in C programming...."

Więc można przyjąć, że nie korzystamy z goto.

Udostępnij ten post


Link to post
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!

Gość
Napisz odpowiedź...

×   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...