Skocz do zawartości
Komentator

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

Pomocna odpowiedź

12 godzin temu, Slowik napisał:

Gdyby wywołać funkcję bezpośrednio w instrukcji warunkowej w pętli,

@Slowik nie jest to dobry pomysł z 2 powodów:

  1. wywołasz tę funkcję 7 razy zamiast 1,
  2. za każdym razem możesz uzyskać inny pomiar, raczej chcesz zwizualizować tylko jeden.

Mogę Ci jeszcze doradzić co zrobić żeby poprawić kod 🙂

  1. wyrzuć tzw. magiczne liczby i zastąp je dyrektywami preprocesora #define na górze kodu
  2. osobiście nie podobają mi się jednolinikowe warunki ale tu się nie upieram
  3. dla poprawy czytelności możesz wydzielić funkcjonalność czyli pomiar i wyświetlanie do osobnej funkcji.

W programowaniu bardziej istotna jest czytelność kodu, a nie jego upakowanie. Często dzięki ładnym nazwom zmiennych i funkcji możesz zrezygnować z komentarzy - patrz funkcja zmierz_odleglosc(). Niedawno pojawił się na forum artykuł o pisaniu czystego kodu, możesz na niego zerknąć 🙂 

  • Pomogłeś! 1

Udostępnij ten post


Link to post
Share on other sites
(edytowany)

 Powiem inaczej: skracanie kodu nie polega na usuwaniu spacji (bo to tak, jakbyś z książki chciał usunąć myślniki i znaki nowej linii, co byłoby pewnie szczególnie przydatne przy dialogach), ale na zastępowaniu jakichś długaśnych konstrukcji prostszymi, krótszymi i bardziej czytelnymi. Oto przykład:

13 godzin temu, Slowik napisał:

if (odleglosc < (i * mnoznik)) digitalWrite(i, HIGH); // to wyjasnione ponizej poniewaz komentarz bylby zbyt dlugi :D
else digitalWrite(i, LOW);

 

Bez usuwania znaków nowej linii i wiodących spacji byłoby to:

if (odleglosc < (i * mnoznik))
  digitalWrite(i, HIGH); // to wyjasnione ponizej poniewaz komentarz bylby zbyt dlugi :D 
else
  digitalWrite(i, LOW);

Trochę czytelniejsze, prawda? Zapoznaj się z programami typu indent czy clang-format, one potrafią skrócić zapis nie tracąc czytelności.

Ale rozumiem, że chcesz to koniecznie i bezwarunkowo skrócić. Proszę bardzo:

digitalWrite(i, odległość < i * mnożnik);

Wypadł jeden if, z dwóch instrukcji zrobiła się jedna, a czytelność nawet większa[1]. To jest skracanie kodu. To, co pokazałeś, to nie jest skracanie kodu (bo kod przecież się nie zmienia, zmienia się tylko jego zapis z czytelnego na nieczytelny).

Aha, sensowności takiego czegoś nie komentuję. Nie ma o czym mówić.

---

[1] pod warunkiem że wie się o C/C++ trochę więcej niż po przeczytaniu pierwszego rozdziału podręcznika

Edytowano przez ethanak
  • Lubię! 2

Udostępnij ten post


Link to post
Share on other sites

@Gieneq @ethanak Dziękuję za uwagi i rady 🙂 

Jeśli chodzi o "skracanie kodu" to nie miałem na myśli usuwania jakichkolwiek spacji (chociaż w mojej opinii zapis jednolinijkowy jest bardziej czytelny niż ze wcięciami, jak się scrolluje bardzo długi kod, to można więcej objąć wzrokiem). Raczej o coś jak zrezygnowanie z kilkudziesięciolinijkowej instrukcji switch lub if/else w której każda dioda jest opisana osobno. Albo możliwość regulacji czułości układu za pomocą jednej zmiennej, czy też możliwość dodawania/odejmowania diod, również w jednej zmiennej. Nie wiem skąd pojawił się szalony pomysł, że chodzi o usuwanie spacji, ale mimo wszystko dzięki za podsunięcie pomysłu na tą linijkę: 

digitalWrite(i, odległość < i * mnożnik);

To upraszcza kod jeszcze bardziej 🙂 

Dodam, że przejrzałem cały temat i nie znalazłem rozwiązania podobnego do tego które zaproponowałem, dlatego też opublikowałem wcześniejszy post. Zaznaczyłem również, że zdaję sobie sprawę, że nadmierne 'skracanie' kodu może powodować utrudnienia w czytelności. Żeby nikt niepotrzebnie się nie denerwował, następnym razem zanim wrzucę jakiś kod to postaram przeczytać chociaż 2 rozdziały z podręcznika o C/C++😎

 

Cytat
11 godzin temu, Gieneq napisał:

wyrzuć tzw. magiczne liczby i zastąp je dyrektywami preprocesora #define na górze kodu

 

Co mam rozumieć poprzez magiczne liczby? Chodzi o to, żeby zastąpić numery pinów dla echo i trigger dyrektywami preprocesora? 

PS Komentarze dodawałem tylko i wyłącznie dlatego, że na tym forum spotykałem się z opinią, że kod należy komentować nawet kiedy piszemy na własne potrzeby (o ile pamiętam w którejś lekcji z kursu jest taka uwaga). Mnie uczono, że kod ma być samokomentujący się a komentarze tylko w przypadku jakichś egde-case.

Udostępnij ten post


Link to post
Share on other sites
36 minut temu, Slowik napisał:

w mojej opinii zapis jednolinijkowy jest bardziej czytelny niż ze wcięciami

if (a) fun1(); else if (b) {if (c) fun2(); else fun3()} else fun4();

Co o tym sądzisz?

38 minut temu, Slowik napisał:

jak się scrolluje bardzo długi kod, to można więcej objąć wzrokiem

Jak się skroluje kod który ma np. 1000 linii to i tak całego wzrokiem nie obejmiesz, a zaręczam że 1000 linii to wcale nie jest tak dużo.

Przerabiałem kiedyś kod (w sumie kilka tysięcy linii) pisany przez niewidomego, który co prawda wszystko pięknie umieszczał w oddzielnych linijkach, ale nie wpadł na to żeby robić wcięcia (choć to trochę dziwne, zarówno brajlowski monitor jak i gadacz czytają poziom wcięć). Niestety - bez użycia indenta się nie obeszło...

A co do komentarzy - nie chodzi tu o jakieś komentowanie każdej linii, ale raczej o napisanie czegoś w stylu "a to jest po to". Rozumiem, że bez problemu za pięć lat będziesz wiedział, co robi linia 4276 w Twoim pisanym dzisiaj kodzie nawet i bez komentarza... ale zastanów się, czy na 100% będziesz pamiętał po kiego grzyba ją tam wsadziłeś i co, do ciężkiej cholewy, robi ta funkcja... 🙂

 

Udostępnij ten post


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

Co o tym sądzisz?

To już popadanie w skrajność 🙂 Prawie klasyfikuje się do udziału w IOCCC 😁 

Udostępnij ten post


Link to post
Share on other sites

Cześć, moje wykonanie zadania 9.3:


#define buzzPin 10 // sygnal do buzzera
#define trigPin 11 // wyslanie sygnalu do czujnika
#define echoPin 12 // odczyt z czujnika
#define safeLed A5

void setup() { // wstepne ustawienia
  pinMode(echoPin, INPUT);
  pinMode(trigPin, OUTPUT);
  pinMode(A0, OUTPUT); // wyjscie A0 jako output - dioda nr 1
  pinMode(A1, OUTPUT); // wyjscie A1 jako output - dioda nr 2
  pinMode(safeLed, OUTPUT); // wyjscie A5 jako output - dioda wskazujaca bazpieczna odleglosc > 100 cm

  for (int i = 2; i <= 11; i++) { // wyjscia od 2 do 11
    pinMode(i , OUTPUT); // ustawione jako output
    digitalWrite(i, LOW);  // wstepnie sygnal niski na wszystkie wyjscia
  }

  digitalWrite(A0, LOW);
  digitalWrite(A1, LOW);
  digitalWrite(A5, LOW);
}

void loop() {
  int odleglosc = zmierzOdleglosc();
  pokazOdleglosc(odleglosc);
}

int zmierzOdleglosc()
{
  long czas, dystans;

  // proces pomiaru
  digitalWrite(trigPin, LOW);
  delayMicroseconds(2);
  digitalWrite(trigPin, HIGH);
  delayMicroseconds(10);

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

  return dystans;
}

void pokazOdleglosc(int odleglosc) // zapala odpowiednie diody jesli przeszkoda znajdzie sie nie dalej niz 100 cm
{                                 //
  // wygaszamy wszystkie diody i wylaczamy buzzer
  digitalWrite(A0, LOW);
  digitalWrite(A1, LOW);
  digitalWrite(A5, LOW);
  for (int i = 2; i <= 10; i++) {
    digitalWrite(i, LOW);
  }

  // przeksztalcenie zmierzonej odleglosci, aby mozna bylo uzyc jej w switch
  // jako wartosci calkowitej
  odleglosc /= 10; // dzielenie przez 10 i obciecie czesci ulamkowej
  odleglosc += 1; // dla poprawnosci dodajemy 1

  switch (odleglosc)
  {
    case 10: digitalWrite(A0, HIGH); break; // zaczynam od 10 bo diody maja sie zapalc ponizej 1 metra
    case 9: digitalWrite(A1, HIGH); break; // 90 cm
    case 8: digitalWrite(2, HIGH); break; // 80 cm itd..
    case 7: digitalWrite(3, HIGH); break;
    case 6: digitalWrite(4, HIGH); break;
    case 5: digitalWrite(5, HIGH); break;
    case 4: digitalWrite(6, HIGH); break;
    case 3: digitalWrite(7, HIGH);
      analogWrite(buzzPin, 10); // 30 cm - dodajemy sygnal dzwiekowy
      break;
    case 2: digitalWrite(8, HIGH);
      analogWrite(buzzPin, 50); // 20 cm - sygnal wyzszy
      break;
    case 1: digitalWrite(9, HIGH);
      analogWrite(buzzPin, 150); // 10 cm - sygnal wysoki
      break;
     default: digitalWrite(A5, HIGH); // preszkoda powyzej 1 metra - zapala sie odpowiednia dioda, reszta zgaszona
  }
}

I taki byle jaki wyświetlacz: 

Czujnik_odl.thumb.jpg.b12415ddbea2c835b94b931c9c1e1576.jpg

Testy, trochę czasem niebieska mruga, ale wydaje mi się, że za mała powierzchnia "przeszkody" przy większych odległościach od czujnika.

 

 

Jak zwykle proszę o wytykanie błedów.

  • Lubię! 1

Udostępnij ten post


Link to post
Share on other sites

@badbit działa i wygląda bardzo fajnie - dobra robota 🙂 Na pewno dałoby się jakoś trochę to zoptymalizować, aby usunąć tego switcha, ale na tym etapie nie musisz się raczej tym przejmować. Jedynie czego "dla zasady" się uczepię to konsekwencja co do korzystania z define. Jedna dioda, buzzer i czujnik mają piny zadeklarowane przez #define, a np. diody na A0 i A1 są wpisane "z palca" podczas samej konfiguracji.  Rozumiem dlaczego tak zrobiłeś, ale jak się patrzy na ten kod to wydaje się to pewnym brakiem konsekwencji.

BTW pamiętaj też, że do pinów A0-A5 można się też odwoływać "normalnie" za pomocą numerków od 14 do 19.

  • Lubię! 1

Udostępnij ten post


Link to post
Share on other sites

Pytanie dotyczy podtematu "Funkcje zwracające wynik" - stworzyliśmy tam funkcję liczącą pole kwadratu a więc potęgującą daną cyfrę/liczbę do potęgi drugiej. Eksperymentując sprawdziłem, że ostatni prawidłowy wynik wskazywany przez funkcję to 1812 , a kolejne tj. 1822, 1832, (...) są już błędne. Z czego to wynika, jeśli zakres zmiennej int jest dużo większy niż wyniki kwadratów?

Udostępnij ten post


Link to post
Share on other sites
8 minut temu, Stark napisał:

zakres zmiennej int jest dużo większy niż wyniki kwadratów?

A więc twierdzisz, że 182² (czyli 33124) mieści się w zakresie -32768..32767?

 

  • Lubię! 1

Udostępnij ten post


Link to post
Share on other sites

@Stark wróć do wcześniejszych lekcji - w tym miejscu znajdziesz zakresy dla zmiennych: https://forbot.pl/blog/kurs-arduino-uart-komunikacja-z-komputerem-pc-zmienne-id3836

W przypadku potęg Twój wynik zawsze będzie dodatni, więc zamiast int możesz wykorzystać np. zmienną typu unsigned int, czyli właśnie bez znaku. W takim przypadku zmienna ta będzie mogła przechowywać wartości od 0 do 65,535.

  • Lubię! 1

Udostępnij ten post


Link to post
Share on other sites

Niedopatrzenie z mojej strony.

Dnia 16.11.2020 o 12:40, ethanak napisał:

A więc twierdzisz, że 182² (czyli 33124) mieści się w zakresie -32768..32767?

Chodziło mi o przedział −2 147 483 648 — +2 147 483 647.

@Treker dziękuję bardzo za pomoc.

Udostępnij ten post


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

Chodziło mi o przedział −2 147 483 648 — +2 147 483 647.

Widzisz - to nie jest takie proste.

W języku C/C++ musi być spełniona zależność:

sizeof(char) <= sizeof(short int) <= sizeof(int) <= sizeof(long int)

Nie ma natomiast nic o rzeczywistych szerokościach tych typów. 16-bitowe inty są bardzo często spotykane w dialektach C na 8-bitowce, w czasach pierwszych pecetów wszelkie Turbo C i podobne kompilatory posługiwały się również 16-bitowym intem (też się kiedyś na to nabrałem kiedy musiałem się przymusowo przesiąść na jakiś czas z Amigi na jakiegoś 386), i zawsze należy albo sprawdzić jakiej szerokości jest tak naprawdę int, albo posługiwać się typami z stdint (np. int32_t będzie zawsze 32-bitowy niezależnie od architektury).

Rozumiem, że zacząłeś od kursu STM, czyli 32-bitowego kompilatora, gdzie sizeof(int) to 4 bajty?

  • Lubię! 2

Udostępnij ten post


Link to post
Share on other sites

Dziękuję! Bardzo doceniam takie tłumaczenia bo dzięki nim mogę zrozumieć więcej.

13 godzin temu, ethanak napisał:

Rozumiem, że zacząłeś od kursu STM, czyli 32-bitowego kompilatora, gdzie sizeof(int) to 4 bajty?

To prawda, że zacząłem od kursu STM, aczkolwiek moje przyzwyczajenie co do przedziału wartości zmiennej int wywodzi się z nauki programowania/informatyki, gdzie za pewnik przyjąłem ten przedział, nie do końca albo i w ogóle rozumiejąc ten temat.

  • Lubię! 1

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!

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