Skocz do zawartości
Komentator

Kurs Arduino - #9 - Czujnik odległości HC-SR04, funkcje

Pomocna odpowiedź

@Gieneq

Dnia 18.06.2020 o 07:29, Gieneq napisał:

To o czym pisał @Treker to dobry sposób na "debugowanie" programów, bo jest szybki i niezawodny. 🙂 

Wszystko fajnie, tylko w jaki sposób się tego używa🤔

A tym czasem może ktoś żuci okiem na moje nie działające bazgroły i naprowadzi na drogą właściwą . Przeglądałem rozwiązania kolegów (niektóre kody kopiowałem i próbowałem uruchomić, ale niektóre nawet się nie kompilują...) 🙁

#define trigPin 12
#define echoPin 11

 int wynik;// Zmienna liczbowa globalna

void setup() {
  Serial.begin (9600);//Komunikacja z monitorem szeregowym 
  pinMode(trigPin, OUTPUT);
  pinMode(echoPin, INPUT);
  pinMode(2, OUTPUT);//Ustawianie pinow jako wyjscia na diody
  pinMode(3, OUTPUT);
  pinMode(4, OUTPUT);
  pinMode(5, OUTPUT);
  pinMode(6, OUTPUT);
  pinMode(7, OUTPUT);

  digitalWrite(2, LOW);//Diody poczatkowo zgaszone
  digitalWrite(3, LOW);
  digitalWrite(4, LOW);
  digitalWrite(5, LOW);
  digitalWrite(6, LOW);
  digitalWrite(7, LOW);
}

  void loop(){
    zmierzOdleglosc();//Wywolanie funkcji
     delay (500);//Opoznienie
  }
int zmierzOdleglosc() {//Deklaracja funkcji zwracajacej wynik laczbowy
  long czas, dystans;//Zmienna liczbowa do obliczania

  digitalWrite(trigPin, LOW);//Pomiar odleglosci
  delayMicroseconds(2);
  digitalWrite(trigPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigPin, LOW);

  czas = pulseIn(echoPin, HIGH);
  dystans = czas / 58;

  return dystans;
  
  wynik = map(zmierzOdleglosc, 3, 30, 1, 6);//Podzial odleglosci na 6  odcinkow(warunkow) i zapisujemy do nowej zmiennej
  Serial.println(wynik);//Drukuj wynik pomiaru w monitorze szeregowym 
 
  switch (wynik) {//Sprawdzamy warunki i zapalamy odpowiednie diody 
    case 1:
      digitalWrite(2, HIGH);
      break;
      case 2:
       digitalWrite(2, HIGH);
       digitalWrite(3, HIGH);
      break;
      case 3:
       digitalWrite(2, HIGH);
       digitalWrite(3, HIGH);
      digitalWrite(4, HIGH);
      break;
      case 4:
       digitalWrite(2, HIGH);
       digitalWrite(3, HIGH);
      digitalWrite(4, HIGH);
      digitalWrite(5,HIGH);
      break;
      case 5:
        digitalWrite(2, HIGH);
       digitalWrite(3, HIGH);
      digitalWrite(4, HIGH);
      digitalWrite(5,HIGH);
      digitalWrite(6,HIGH);
      break;
      case 6:
        digitalWrite(2, HIGH);
       digitalWrite(3, HIGH);
      digitalWrite(4, HIGH);
      digitalWrite(5,HIGH);
      digitalWrite(6,HIGH);
      digitalWrite(7,HIGH);
      break;
  }
}

Z góry dziękuje za poświęcony czas

Udostępnij ten post


Link to post
Share on other sites

Tak na szybko: Po wykonaniu "return" w danej funkcji nie wykona się nic więcej. Czyli gdy masz funkcję zmierzOdleglosc to kod, który masz w tej funkcji, ale poniżej linijki "return dystans;" nigdy się nie wykona. Więc nalezało by przenieść return na koniec tej funkcji.

Druga kwestia jest to, że nie masz nigdzie gaszenia diod (dotyczy kodu za return). Więc nawet jak return przeniesiesz to raz zapalona dioda nie zgaśnie.

Jeżeli chodzi o debugowanie diodą to w pewnym sensie zadziałało ono u ciebie 😉 bo jak zapewne zauwazyleś diody nigdy się nie zapalały  wiec powinieneś się domyśleć, że z jakiegoś powodu kod tutaj nie dociera. Choć ja wolę debugować za pomocą serial bo wtedy mam możliwość sprawdzenia jeszcze wartości wybranych zmiennych. Ale warto zapamiętać. Jeżeli coś nie chce się wydarzyć to problemem jest coś wcześniej niż instrukcja, która się nie wywołuje.

  • Lubię! 1
  • Pomogłeś! 1

Udostępnij ten post


Link to post
Share on other sites
21 godzin temu, Vova napisał:

Wszystko fajnie, tylko w jaki sposób się tego używa🤔

Polega to na tym, że gdy pojawi się jakiś stan, który chcesz wykryć to ustawiasz/przełączasz pin z podłączonym LEDem. Szczególnie w blokach warunkowych jest to informacja, że program wszedł w dany blok warunkowy tj. warunek został spełniony. Często ta informacja, to już dużo krok na przód przy poszukiwaniu błędu 🙂 

  • Pomogłeś! 1

Udostępnij ten post


Link to post
Share on other sites

Dziękuje za nakierowanie. Oto końcowa wersja kodu. Działa jak należy😄 


  digitalWrite(trigPin, LOW);//Pomiar odleglosci
  delayMicroseconds(2);
  digitalWrite(trigPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigPin, LOW);

  czas = pulseIn(echoPin, HIGH);
  dystans = czas / 58;

  wynik = map(dystans, 1, 30, 1, 6);//Podzial odleglosci na 6  odcinkow(warunkow) i zapisujemy do nowej zmiennej
  Serial.println(dystans);//Drukuj wynik pomiaru w monitorze szeregowym

  switch (wynik) {//Sprawdzamy warunki i zapalamy / gasimy  odpowiednie diody
    case 6:
      digitalWrite(ledPin2, HIGH);
      digitalWrite(ledPin3, LOW);
      digitalWrite(ledPin4, LOW);
      digitalWrite(ledPin5, LOW);
      digitalWrite(ledPin6, LOW);
      digitalWrite(ledPin7, LOW);
      break;

    case 5:
      digitalWrite(ledPin2, HIGH);
      digitalWrite(ledPin3, HIGH);
      digitalWrite(ledPin4, LOW);
      digitalWrite(ledPin5, LOW);
      digitalWrite(ledPin6, LOW);
      digitalWrite(ledPin7, LOW);
      break;

    case 4:
      digitalWrite(ledPin2, HIGH);
      digitalWrite(ledPin3, HIGH);
      digitalWrite(ledPin4, HIGH);
      digitalWrite(ledPin5, LOW);
      digitalWrite(ledPin6, LOW);
      digitalWrite(ledPin7, LOW);
      break;

    case 3:
      digitalWrite(ledPin2, HIGH);
      digitalWrite(ledPin3, HIGH);
      digitalWrite(ledPin4, HIGH);
      digitalWrite(ledPin5, HIGH);
      digitalWrite(ledPin6, LOW);
      digitalWrite(ledPin7, LOW);
      break;

    case 2:
      digitalWrite(ledPin2, HIGH);
      digitalWrite(ledPin3, HIGH);
      digitalWrite(ledPin4, HIGH);
      digitalWrite(ledPin5, HIGH);
      digitalWrite(ledPin6, HIGH);
      digitalWrite(ledPin7, LOW);
      break;

    case 1:
      digitalWrite(ledPin2, HIGH);
      digitalWrite(ledPin3, HIGH);
      digitalWrite(ledPin4, HIGH);
      digitalWrite(ledPin5, HIGH);
      digitalWrite(ledPin6, HIGH);
      digitalWrite(ledPin7, HIGH);
      break;
      
    default:
      digitalWrite(ledPin2, LOW);//Ddiody zgaszone, gdy żaden z warunków nie spełniony
      digitalWrite(ledPin3, LOW);
      digitalWrite(ledPin4, LOW);
      digitalWrite(ledPin5, LOW);
      digitalWrite(ledPin6, LOW);
      digitalWrite(ledPin7, LOW);
      
      return dystans;
  }
}

 

  • Lubię! 1

Udostępnij ten post


Link to post
Share on other sites

@Vova Super! To teraz zadanie dodatkowe 😄 Wiesz jak wyrzucić cały switch-case? Tu podpowiem: możesz użyć tablic, zapisać do ich wyprowadzenia i wartości i poprzez odwołanie się do tego co jest w case odwołasz się do np. wiersza w tablicy, gdzie jest to zapisane. Np,:

int pins[6] = {ledPin2, ledPin3, ..., ledPin7}; // ta tablica służy do odwoływania się do tych samych pinów w tej samej kolejności

//teraz definiujesz tablice które służą wyświetlaniu poziomów odległości:

int dists[7][6] = {

{LOW, LOW, LOW, LOW, LOW, LOW}, //indeks 0 zamiast default - możesz zrobić warunek, że jak przekroczy zakres od 1 do 6 to jest 0

{}, ... //wartości dla indeksa 1 itd
{}
}

Spróbuj zrobić w ten sposób 🙂 

  • Lubię! 1

Udostępnij ten post


Link to post
Share on other sites

@Gieneq 

Dnia 25.06.2020 o 07:23, Gieneq napisał:

Tu podpowiem: możesz użyć tablic

Chętnie się zmierzę z postawionym zadaniem, tylko nie wiem czy "tablice"  już były omawiane wcześniej i coś mi umknęło🤔. Może podrzucisz jakiegoś linka, gdzie można zaczerpnąć trochę informacji o wykorzystaniu "tablic". . .     

  • Lubię! 1

Udostępnij ten post


Link to post
Share on other sites

@Vova przepraszam za późne odpisywanie, w weekendy raczej unikam komputerów 🙂 

Faktycznie temat ten mógł się nie pojawić w tych częściach kursu Tu masz przykładowy poradnik dot. tablic. Tablice pojawią się też w 2 części kursu Arduino np. w tej dot. klawiatury. Nie jest to trudny temat i możesz to uznać za ponumerowane kontenerki na zmienne, gdzie do danego kontenerka odwołujesz się poprzez jego indeks: 0, 1, itd. Zarówno zapis jak i odczyt odbywają się w ten sposób.

Udostępnij ten post


Link to post
Share on other sites

@Gieneq Przeczytałem część #5 Kursu II od deski do deski i jest tam tylko wspomniane że, cytuje: "W kursie Arduino, do tablic jeszcze wrócimy - więc, jeśli ktoś ich nie zna,
to nie musi się teraz niczego obawiać", 
ale tak i nie zostało to wyjaśnione tylko jest ponownie wykorzystane w dalszej części kursu😔. Czyli pozostaje  ten poradnik z GOOGLE...

Udostępnij ten post


Link to post
Share on other sites

@Vova fakt, w kursie jest przykład użycia, ale z samego przykładu da się czegoś dowiedzieć. Jak uda Ci się liznąć trochę teorii to pomyślimy co dalej 🙂 

Udostępnij ten post


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

Czyli pozostaje  ten poradnik z GOOGLE...

Niekoniecznie ten. Ja np. polecałbym podręczniki na Wikibooks - podręcznik C i podręcznik C++ (czytane w tej kolejności). Pamiętaj, że podręcznik i kurs to dwie absolutnie różne rzeczy: kurs jest po to, aby szybko i w miarę bezboleśnie opanować pewne podstawy - i jak w naszym przypadku móc zacząć (uwaga na podkreślenie) zabawę z Arduino. Absolutnie nie może omawiać wszystkich możliwości danego języka (C/C++ w naszym przypadku) bo po pierwsze jest tego za dużo jak na początek, a po drugie przestałby to być kurs Arduino z elementami języka programowania, a kurs (czy może już podręcznik) programowania w C/C++ z niektórymi przykładami zrealizowanymi na Arduino...

To tak jak z kursem na prawo jazdy. Owszem, przygotuje Cię do podjechania samochodem z fasonem po panienkę - ale nie zastąpi przeczytania Kodeksu Drogowego ani nie przygotuje do Rajdu Dakar...

 

  • Lubię! 1

Udostępnij ten post


Link to post
Share on other sites
9 godzin temu, Vova napisał:

ale tak i nie zostało to wyjaśnione tylko jest ponownie wykorzystane w dalszej części kursu😔

@Vova tak, niestety masz tutaj racje - to moje niedopatrzenie, bo ostatecznie tablice nie zostały omówione. W nowej odsłonie kursu temat ten będzie już omówiony 🙂 O wszystkich aktualizacjach będziemy informować na blogu (teraz działamy nad odświeżeniem kursu elektroniki II, później TC i RPi oraz Arduino).

  • Lubię! 1

Udostępnij ten post


Link to post
Share on other sites
(edytowany)
#define trigPin 12
#define echoPin 11
#define ledPin2 2
#define ledPin3 3
#define ledPin4 4
#define ledPin5 5
#define ledPin6 6
#define ledPin7 7

int wynik;// Zmienna liczbowa globalna

void setup() {
  Serial.begin (9600);//Komunikacja z monitorem szeregowym
  pinMode(trigPin, OUTPUT);
  pinMode(echoPin, INPUT);
  pinMode(ledPin2, OUTPUT);//Ustawianie pinow jako wyjscia na diody
  pinMode(ledPin3, OUTPUT);
  pinMode(ledPin4, OUTPUT);
  pinMode(ledPin5, OUTPUT);
  pinMode(ledPin6, OUTPUT);
  pinMode(ledPin7, OUTPUT);

  digitalWrite(ledPin2, LOW);//Diody poczatkowo zgaszone
  digitalWrite(ledPin3, LOW);
  digitalWrite(ledPin4, LOW);
  digitalWrite(ledPin5, LOW);
  digitalWrite(ledPin6, LOW);
  digitalWrite(ledPin7, LOW);
}

void loop() {
  zmierzOdleglosc();//Wywolanie funkcji
  delay (100);//Opoznienie
}
int zmierzOdleglosc() {//Deklaracja funkcji zwracajacej wynik laczbowy
  long czas, dystans;//Zmienna liczbowa do obliczania

  digitalWrite(trigPin, LOW);//Pomiar odleglosci
  delayMicroseconds(2);
  digitalWrite(trigPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigPin, LOW);

  czas = pulseIn(echoPin, HIGH);
  dystans = czas / 58;

  wynik = map(dystans, 1, 30, 1, 6);//Podzial odleglosci na 6  odcinkow(warunkow) i zapisujemy do nowej zmiennej
  Serial.println(dystans);//Drukuj wynik pomiaru w monitorze szeregowym

  int piny[6] = {ledPin2, ledPin3, ledPin4, ledPin5, ledPin6, ledPin7};
  int odleglosc[7][6] = {
    {LOW, LOW, LOW, LOW, LOW, LOW},
    {HIGH, LOW, LOW, LOW, LOW, LOW},
    {HIGH, HIGH, LOW, LOW, LOW, LOW},
     {HIGH, HIGH, HIGH, LOW, LOW, LOW},
       {HIGH, HIGH, HIGH, HIGH, LOW, LOW},
        {HIGH, HIGH, HIGH, HIGH, HIGH, LOW},
          {HIGH, HIGH, HIGH, HIGH, HIGH, HIGH}   
  };
  if (wynik == 6){
    digitalWrite ????? Jak odwołać się do wiersza z tablicy???
  }
      return dystans;
  }

Utknąłem w tym miejscu, Jak odwołać się do wiersza z tablicy? W podanych przykładach z poradnika jest jest tylko jak przechowywać dane zapisane w tablicy ( w sensie nie wiem w jaki sposób zapisać zapalanie diod ? Tak rozumiem że za pomocą digitalWrite ... a co w miejscu kropek? odleglosc [1]  ? jak ma się tam znaleźć np. pierwszy wiersz z tablicy wielowymiarowej? ) , w części z klawiaturą też nie znalazłem odpowiedzi...

 Pomożecie? Z góry przepraszam za głupie pytania...

Edytowano przez Vova

Udostępnij ten post


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

jak ma się tam znaleźć np. pierwszy wiersz z tablicy wielowymiarowej?

A w jaki sposób chcesz cały wiersz wrzucić do digitalWrite? Nie zmieści się...

Odwołanie do elementu tablicy to faktycznie tablica[n]. Tablice wielowymiarowe możesz traktować jako tablice tablic, czyli np. odwołanie do wiersza n i pozycji m w tym wierszu to tablica[n][m].

Coś się rozjaśniło?

Aha, jeszcze jedna ważna rzecz: elementy w tablicy numeruje się od zera a nie od jedynki. Pierwszy element tablicy to tablica[0] a nie tablica[1], a zakres indeksów tablicy 6-elementowej to 0 do 5 a nie 1 do 6. Mógłbyś jednak czytać to co ci polecają? I to uważnie? Bo nikt tu nie ma zamiaru przepisywać zdań z podręczników ani tłumaczyć czegoś, co w podręczniku zostało wytłumaczone.

Edytowano przez ethanak

Udostępnij ten post


Link to post
Share on other sites
(edytowany)

Co do numeracji w tablicach od zera to wiem (czytałem to co było polecane).  U mnie wiersz 0 to wszystkie diody zgaszone ( czyli miał być wykorzystany zamiast default) . A pierwszy warunek- jedna doda zapalona ( czyli wiersz numer 1 z tablicy)...

Zdania z podręcznika raczej też mi nie pomogą, przeczytałem je w podręczniku kilkanaście razy.

Raczej liczyłem na to, że ktoś w wolnej chwili i z dobrej woli napisze ze dwie linijki kodu, których mi brakuje do pełni szczęścia. Wtedy mógłbym je wykorzystać do wykonania zadania i przeanalizować na swój sposób i czegoś się nauczyć, bo chyba po to był stworzony dany kurs...

 Przecież za wykonanie zadań nikt żadnych nagród nie daje, to też i praktyczne przykłady rozwiązań nie są jakąś tajemnicą...

Czytać podręcznik fajna sprawa, ale dla kogoś, kto z programowaniem spotyka się po raz pierwszy nie wszystko, tam opisane,  jest takie przejrzyste oczywiste i zrozumiałe . . .

Dzięki za poświęcony czas. Pozdrawiam 

Edytowano przez Vova
  • Lubię! 1

Udostępnij ten post


Link to post
Share on other sites

Jestem fanem maksymalnego skracania kodu, chociaż wiem, że nie zawsze oznacza to UPROSZCZENIE kodu a potrafi nieco utrudnić czytelność. Jednak chciałbym zaprezentować swoje rozwiązania zadania 9.3 

byte ilosc_diod = 7; // Tu mozna zmienic ilosc diod, wazne jednak aby wpinac je po kolei, pomijajac pin 0
byte mnoznik = 5; // Parametr wyplywajacy na czulosc na odleglosc

void setup() {
  pinMode(12, OUTPUT); // trig
  pinMode(11, INPUT);  // echo
  for (int i = 1; i <= ilosc_diod; i++) pinMode(i, OUTPUT); // Petla for dodajaca kolejne diody jako OUTPUT
}

void loop() {  
  int odleglosc = zmierz_odleglosc(); // wywolanie funkcji mierzacej odleglosc i przypisanie wartosci do zmiennej 'odleglosc'
  for (int i = 1; i <= ilosc_diod; i++) {
    if (odleglosc < (i * mnoznik)) digitalWrite(i, HIGH); // to wyjasnione ponizej poniewaz komentarz bylby zbyt dlugi :D
    else digitalWrite(i, LOW);
  }
  delay(30); // male opoznienie dodajace plynnosc do ukladu
}

int zmierz_odleglosc() { // funkcja obslugujaca pomiar odleglosci, zwraca wynik w centymetrach
  digitalWrite(12, LOW);
  delayMicroseconds(2);
  digitalWrite(12, HIGH);
  delayMicroseconds(10);
  digitalWrite(12, LOW);
  return pulseIn(11, HIGH) / 58; // przelicza pomiar na cm
}

Całość sprawuje się wyjątkowo dobrze jak na tak skrócony kod, jestem zadowolony z efektu 😄 można trochę kombinować z długością opóźnienia w głównej pętli żeby jeszcze bardziej poprawić płynność.

Zastosowałem numery pinów w pętli for i parametr dodany na samej górze ('mnoznik') jako wartości graniczne dla zapalania kolejnych diod (a konkretniej ich iloczyn). W praktyce - jeśli mnożnik ustawimy na 5 to mamy po kolei wartości dla diod 5cm, 10cm, 15cm itd. Instrukcja warunkowa sprawdza czy konkretne wartości zostały przekroczone i odpowiednio steruje stanem wysokim/niskim. Zmieniając tylko jeden parametr (mnożnik), zmieniamy czułość na odległość dla całego układu. Wadą tego rozwiązania jest, że raczej należy pomijać pin 0, bo przy mnożeniu przez 0 trochę rozjedzie się skala, ostatnia dioda zaświeci tylko gdy fizycznie zatkamy czujnik. W ostateczności można by we wnętrzu pętli zamiast 'i * mnoznik' wpisać '(i + 1) * mnoznik😁

Pojawiło mi się jedno pytanie. Chciałem kod skrócić jeszcze bardziej i zrezygnować w głównej pętli ze zmiennej 'odleglosc'. Po prostu w warunku zamieścić wywołanie funkcji 'zmierz_odleglosc" zamiast przypisywać najpierw do zmiennej. Jednak po chwili zastanowienia doszedłem do wniosku, że w obecnej wersji program może być bardziej optymalny, bo przy każdej iteracji przez główną pętlę, funkcja 'zmierz_odleglosc' jest wywoływana jeden raz. Gdyby wywołać funkcję bezpośrednio w instrukcji warunkowej w pętli, to uruchamiałaby się przy przejściu przez każdy pin, czyli wiele razy więcej. Pierwszy raz spotkałem się z tego typu nieskończoną pętlą właśnie w Arduino, więc moje pytanie brzmi, czy to dobry sposób rozumowania? 

Edytowano przez Slowik

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