Skocz do zawartości
kris2k

Arduino i CanShield - programowe usprawnienia auta

Pomocna odpowiedź

Co nie zmienia faktu, że goto jest i można z niego korzystać. To wbrew pozorom ważna część języka C, chociaż faktycznie w C++ mniej używane.

A to że jakaś dokumentacja tego nie zaleca to już inna sprawa. W każdym razie goto jest i jak ktoś chce i umie, to może z niego korzystać.

Udostępnij ten post


Link to post
Share on other sites
(edytowany)

Przemyślałem działanie mojego programu i ono jest kompletnie bezsensowne w kontekście tego co chcę zrobić, to co napisałem nie będzie działać jak trzeba ;/

Nie mogę decydować o wykonaniu czynności A lub B bazując na czasie przez jaki przycisk jest wciśnięty... dlaczego? Bo Arduino natychmiast z momentem kliknięcia aktywuje czynność A, natomiast po upływie zadanego czasu aktywuje czynność B... a mnie chodzi o program który aktywuje coś dopiero PO upływie tego czasu, a nie od momentu w którym czas zaczynam liczyć.

W praktyce przecież nie mogę zmusić Arduino do czytania w myślach kierowcy auta i wróżąc ze szklanej kuli aktywować potrójne mrugnięcie na etapie samego kliknięcia w przełącznik.

Moja funkcja musi się aktywować PO krótkim przytrzymaniu dźwigienki kierunkowskazu a nie w trakcie jej przytrzymania (nie mniej jednak, czas przez jaki ta dźwigienka będzie przytrzymana ma znaczenie).

Czyli zadanie brzmi tak: Czynność A ma się wykonać tylko gdy przycisk będzie w stanie LOW przez krócej niż 0,5sek. (Jak stan LOW będzie trwał dłużej, to nic się nie ma zadziać.)

No to dorobiłem się takiego kodu:

unsigned long aktualnyCzas = 0;
unsigned long zapamietanyCzas = 0;
boolean click1 = false;
long dlugoscKliku = 0;

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


void loop() {
  aktualnyCzas = millis();
  
  
  if (digitalRead(6) == LOW ) { //Jeśli przycisk wciśnięty
    click1 = true;  //startuje zliczanie czasu klikniecia 
  } else {
    zapamietanyCzas = aktualnyCzas; // zapamietuje kiedy zjawisko ustało, tutaj, przycisk zostal puszczony, ewentualnie nigdy nie klikniety
    click1 = false; //stopuje zliczanie czasu klikniecia
  }
    
  if (click1 == true) {
      dlugoscKliku = aktualnyCzas - zapamietanyCzas; //zapamietuje roznice w czasie trwania stanu LOW, czyli pokazuje czas przez jaki guzik byl wcisniety
  }

  if (dlugoscKliku > 1 && dlugoscKliku < 500 && click1 == false) //dlugoscKliku musi byc mierzona od 1 bo przy 0 po odpaleniu programu warunek jest od razu spelniony
  {
  Serial.println("Czynność do wykonania - 2x mrugnij kierunkiem"); //pierwsze mrugnięcie zrobiło sie samo w trakcie zwarcia przycisku, kolejne dwa dokładam programowo od siebie
  }

}

Pytanie brzmi teraz tak, jak poprawnie zrealizować ostatniego IF'a aby czynność tam wykonała się TYLKO RAZ (sekwencja 1/0/1/0) albo TYLKO DWA RAZY (sekwencja 1/0) ?

 

Edytowano przez kris2k

Udostępnij ten post


Link to post
Share on other sites

czyli:

1 Jeśli przycisk wciśnięty to zapamiętaj.
2. Poczekaj 0,5 s
3. Jeśli przycisk był wciśnięty i jest nadal wciśnięty to CZYNNOŚC A
4. Skocz do 1

Teraz to zakoduj i powinno zadziałać.

 

Udostępnij ten post


Link to post
Share on other sites

Odpisałeś akurat jak wstawiałem kod...

Udostępnij ten post


Link to post
Share on other sites

Może taka funkcja wykonująca nakazane czynności:
1. Wykonaj sekwencję czynności
2. Poczekaj na zwolnienie przyciku
3. Zapamiętaj, że przycisk zwolniony
4. Wróć do programu

Udostępnij ten post


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

Może taka funkcja wykonująca nakazane czynności:
1. Wykonaj sekwencję czynności
2. Poczekaj na zwolnienie przycisku
3. Zapamiętaj, że przycisk zwolniony
4. Wróć do programu

Belferek, dziękuję za wszelkie podpowiedzi, ale to jest dla mnie po prostu zbyt ogólne niestety 😕

Kompletnie nie wiem jak coś takiego zrealizować programowo 😕

 

Udostępnij ten post


Link to post
Share on other sites
(edytowany)

Nie poddawaj się - walcz 🙂 np. :

void sekwencjaCzynnosci()
{
  // czynnosc 1
  // czynnosc 2
  // .....
  // czynnosc N
  
  while(digitalRead(6) == LOW) ; //czekamy na zwolnienie przycisku
  click1=false;
}

 

Edytowano przez Belferek

Udostępnij ten post


Link to post
Share on other sites
(edytowany)

Belferek, w sumie tak jak to napisałeś to zupełnie nie działa 😉 Na ten moment mam szkielet programu który co do zasady działa jak trzeba:


unsigned long aktualnyCzas = 0;
unsigned long zapamietanyCzas = 0;
boolean click1 = false;
long dlugoscKliku = 0;

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

void loop() {
  aktualnyCzas = millis();
  
  if (digitalRead(6) == LOW ) { //Jeśli przycisk wciśnięty
    click1 = true;  //startuje zliczanie czasu klikniecia 
  } else {
    zapamietanyCzas = aktualnyCzas; // zapamietuje kiedy zjawisko ustało, tutaj, przycisk zostal puszczony, ewentualnie nigdy nie klikniety
    click1 = false; //stopuje zliczanie czasu klikniecia
  }
    
  if (click1 == true) {
      dlugoscKliku = aktualnyCzas - zapamietanyCzas; //zapamietuje roznice w czasie trwania stanu LOW, czyli pokazuje czas przez jaki guzik byl wcisniety
  }

  if (dlugoscKliku > 1 && dlugoscKliku < 1000 && click1 == false) //dlugoscKliku musi byc mierzona od 1 bo przy 0 po odpaleniu programu warunek jest od razu spelniony
  {
  sekwencjaCzynnosci();
  } 
}

void sekwencjaCzynnosci()
{
  Serial.println("1 - krok 1");
  delay(250);
  Serial.println("0 - krok 2");
  delay(250);
  Serial.println("1 - krok 3");
  delay(250);
  Serial.println("0 - krok 4");
  delay(250);
  
  Serial.println(dlugoscKliku); // tylko informacyjnie wypluwam czas przez jaki przycisk byl klikniety
  dlugoscKliku = 0; //po wykonanej sekwencji ustawia ta zmienna na 0 i to sprawia że sekwencja już sie kolejny raz nie wykona
}

Sekwencja wykonuje się tylko raz i tylko jeżeli przycisk był w stanie LOW w czasie od 1 do 1000 ms.

POWITANIE
1 - krok 1
0 - krok 2
1 - krok 3
0 - krok 4
196
1 - krok 1
0 - krok 2
1 - krok 3
0 - krok 4
751

Teraz dalsza część zadania, jak poprawnie sprawić żeby sekwencja kroków wykonała się raz co 250ms ale bez użycia tych delay'ow ?

Znowu zapamiętywać czas wystąpienia?

Edytowano przez kris2k

Udostępnij ten post


Link to post
Share on other sites
7 minut temu, kris2k napisał:

w sumie tak jak to napisałeś to zupełnie nie działa

Niczego Ci nie napisałem pokazałem Ci jedynie, że możesz pisać własne funkcje co uczyniłeś i o to chodziło.

9 minut temu, kris2k napisał:

Teraz dalsza część zadania, jak poprawnie sprawić żeby sekwencja kroków wykonała się raz co 250ms ale bez użycia tych delay'ow ?

Znowu zapamiętywać czas wystąpienia? 

Jeśli nie delay() to potrzebujesz innego sposobu odmierzania czasu. Jeśli masz kłopoty z millis() to może skorzystaj z podesłanej Ci wcześniej informacji o Timers.h, która też wykorzystuje millis() ale może być prostsza w użyciu.

Udostępnij ten post


Link to post
Share on other sites

Dziwna ta biblioteka Timers.

Zrobienie takiej sekwencji w ogolę nie daje rezultatu.

Jak wrzucę całość do głównej pętli programu to działa, wewnątrz funkcji już nie :/

void sekwencjaCzynnosci2()
{
  Timer1.begin(250);
  Timer2.begin(500);
  Timer3.begin(750);
  Timer4.begin(1000);

  if (Timer1.available()) {
  Serial.println("1 - krok 1");
  Timer1.time(STOP);
  }

  if (Timer2.available()) {
  Serial.println("0 - krok 2");
  Timer2.time(STOP);
  }

  if (Timer3.available()) {
  Serial.println("1 - krok 3");
  Timer3.time(STOP);
  }

  if (Timer4.available()) {
  Serial.println("0 - krok 4");
  Timer4.time(STOP);
  }

}

 

Udostępnij ten post


Link to post
Share on other sites
Dnia 12.03.2019 o 21:40, 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.

 

 

ethanak, jak to ladnie zpisac aby sekwencja zawsze rozpoczynala sie od x=1 a konczyla sie zawsze na x=0 ?

    x = ( ((aktualnyCzas - zapamietanyCzasACC) % CZAS_MIGNIECIA) < (CZAS_MIGNIECIA / 2) );
    Serial.println(x);

Na ten moment to tak trochę przypadkowo działa 😕

Udostępnij ten post


Link to post
Share on other sites

Ech... nawet mnie zacytowałeś z rozwiązaniem 😉

39 minut temu, kris2k napisał:

kręci się aż millis() - startTime będzie większa niż 2.5 * CZAS_MIGNIECIA

Zaczynać się będzie zawsze od jedynki (zakładam, że na początku pętli aktualnyCzas == zapamietanyCzasACC). Kończy się w chwili, kiedy skończy się ostatnia jedynka (w przypadku jak wyżej będzie to trzecia).

 

  • Lubię! 1

Udostępnij ten post


Link to post
Share on other sites

No właśnie nie mieliśmy jeszcze możliwości przedyskutowania tego przykładu bo wdałem się w rozmowę z Belferkiem.

Niestety ten kod tak nie działa, kawałek praktycznego kodu poniżej:

void loop() {
  aktualnyCzas = millis();
  int CZAS_MIGNIECIA = 1000;

  if (digitalRead(6) == LOW ){
      long x = 0;
      x = ( (( aktualnyCzas - zapamietanyCzas02) % CZAS_MIGNIECIA) < (CZAS_MIGNIECIA / 2) );
      Serial.println(x);
      delay(100);
  } else {
  zapamietanyCzas02 = aktualnyCzas;
  }
  
}

Masz racje, zawsze zaczyna się od 1... ale wydruk w monitorze portu szeregowego trwa w nieskończoność... a raczej tak długo jak trzymam przycisk.

A ja bym chciał żeby zrobił się dwa/trzy/cztery razy i na tym koniec, bez względu na to czy trzymam przycisk dalej, czy nie.

 

Udostępnij ten post


Link to post
Share on other sites

Bo uzależniasz wszystko od tego, czy przycisk jest naciśnięty zamiast czy został naciśnięty.

Podobny przypadek masz tutaj - wprawdzie chodzi tam o zliczanie naciśnięć, ale pokazana jest detekcja wciśnięcia.

Zresztą - poszukaj jakiejś fajnej biblioteki do buttonów obsługującej debouncing i detekcję zdarzeń, może któraś przypasuje. W googlu pod hasłem "arduino button library long press" będziesz miał ich kilka, wybierz sobie najlepszą.

Udostępnij ten post


Link to post
Share on other sites
32 minuty temu, ethanak napisał:

Bo uzależniasz wszystko od tego, czy przycisk jest naciśnięty zamiast czy został naciśnięty.

Good point!

Biorąc pod uwagę fakt, że w aucie nie mam przycisku tylko będę śledził stan napięcia na 2 przewodach to będzie to działać z użyciem w/w techniki sprawdzania zmiany stanu?

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ść
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...