Skocz do zawartości

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

Link do komentarza
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
Link do komentarza
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ć.

 

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

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 😕

 

Link do komentarza
Share on other sites

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
Link do komentarza
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
Link do komentarza
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.

Link do komentarza
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);
  }

}

 

Link do komentarza
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 😕

Link do komentarza
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
Link do komentarza
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.

 

Link do komentarza
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ą.

Link do komentarza
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?

Link do komentarza
Share on other sites

Bądź aktywny - zaloguj się lub utwórz konto!

Tylko zarejestrowani użytkownicy mogą komentować zawartość tej strony

Utwórz konto w ~20 sekund!

Zarejestruj nowe konto, to proste!

Zarejestruj się »

Zaloguj się

Posiadasz własne konto? Użyj go!

Zaloguj się »
×
×
  • 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.