Skocz do zawartości

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


Komentator

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
Link do komentarza
Share on other sites

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

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

 

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

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

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

Link do komentarza
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
Link do komentarza
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
Link do komentarza
Share on other sites

Skończyłem Kurs dla Początkujących cz. I Dlaczego wszystko co dobre, tak szybko się kończy?..🥺 Poziom endorfin spadł niebezpiecznie i pojawiło się pytanie: CO DALEJ?

Na II część Kursu nie miałem odwagi. W głowie mętlik. Niby wiem, a nie wiem. Niby rozumiem a nie rozumiem...

Aby jakoś ratować dobre samopoczucie, postanowiłem poddać torturom sam "podmiot liryczny" kursu (czyli płytkę Arduino) i jakiś element zewnętrzny. Najlepiej mało potężny i pozornie, stosunkowo niegroźny... Na pewno więc nie servo, albo wyświetlacz. Wybór padł na buzzer, zwłaszcza, że Autor tego wybitnego kursu potraktował go dość pobieżnie, a nawet po macoszemu (przynajmniej w części I podkreślam, innych nie czytałem). Ot, hałaśliwy, pikacz.😉

Już na poziomie zapoznawania się z kursem doszedłem do wniosku, że buzzer przecież nie może wyłącznie wydawać wkurzającego dźwięku. Znalazłem w sieci kod na dźwięk R2D2 (https://www.instructables.com/R2D2-Sound-Generator/) trochę powycinałem, trochę podolepiałem... (zaniepokoiła mnie co prawda funkcja tone(), ale nie zaprzątałem nią sobie - JESZCZE - głowy) i buzzerek przemówił milej dla ucha. Niestety cały czas tak głośno, że rodzina się zlatywała (nalepkę usunąłem zanim zamontowałem element). Jak zmusić buzzer, żeby gadał ciszej, pojawiło się pytanie. JAKOŚ przecież musi się dać...🤨

Pierwsza myśl jaka mi przyszła do głowy, to żeby zmniejszyć buzzerowi napięcie. OK, ale jak? Coś tam mi świtało mgliście o mierzeniu napięcia na pinach analogowych, więc niewiele myśląc podłączyłem plus buzera do pinu A3. Nie było to chyba roztropne, zważywszy napisane jak wół na boku użytego łącza ANALOG IN. No, ale stało się, albo wybuchnie, albo zdechnie. Napisałem kod deklarując analogWrite na ten PIN i wartość 100 (dla bezpieczeństwa he, he🙄) ...  Kod się ładnie skompilował, po czym.... nic się nie stało. Buzzer milczał... Zmieniłem na 255, buzzer wydał znajomy, nieznośny dźwięk.🤔 Zmieniłem na 120. Cisza. Zmieniłem na 1000. Dźwięk. 127. Cisza. 128. Dźwięk. Hmm.. Wnioski: Płyta podaje podaje napięcie na pin A3, a może nawet je moduluje. Pin ten może być czytany przez elementy zewnętrzne. Co więcej może być wykorzystywany (w nieco pokrętny sposób, przyznaję) jako ten, tego... " pin zapasowy" do podawania sygnału jak zabraknie pinów cyfrowych. 

Pytanie do eksperta 1: Czy powyższe wnioski są słuszne?

Pytanie do eksperta 2: Co sprawia, że na tym pinie pojawia się sygnał?

Dobra, pomyślałem. Analogowe piny tu nie pomogą. Przerzutka plusa buzera na pin 3. Do głowy przychodzi mi nowy głupi pomysł: "A może to nie napięcie, tylko wypełnienie decyduje o głośności buzzera?". Instrukcja for i jazda po całym zakresie. Hmm... Od wartości 0 do 255, pisk. Jakby trochę inny, ale ten sam. Znajomy. Rodzina już wkurzona. Groźba konfiskaty sprzętu. Odłączam płytkę. Chyba muszę się wiele douczyć.😔 Poziom endorfin sięgnął 0. Wtedy przypomniałem sobie o tone(). Co to jest? Na stronie Arduino dowiedziałem się, że to: "fala kwadratowa określonej częstotliwości, przy 50% wypełnieniu". Dobra tam.. kwadratowa, nie kwadratowa, ale wypełnienie stałe... Czyli jednak nie wypełnienie.

Pytanie do eksperta: Co "łopatologicznie" robi funkcja tone()?

Pytanie do eksperta: Jak samemu robić falę kwadratową na pinie 3 z ominięciem funkcji tone()? 

Wtedy sięgnąłem dna i już miałem pomyśleć: "Nie da się...", gdy przypomniał mi się opornik. "Gdyby tak wsadzić ileś tam oporników między buzzer a pin, to napięcie by spadło". Ale jakich i ile? Te kreski, liczenie... Na pewno by zadziałało, gdyby poślęczeć nad tym, ale jaki uzyskałbym efekt? Buzzer byłby prawdopodobnie cichszy, o jakąś wartość, ale raz by się go uciszyło i koniec... Wtedy już poszło z górki, ale nie od razu... Przyszło mi do głowy, żeby wsadzić gdzieś potencjometr (przepraszam, trochę dziwnie to zabrzmiało). Zmóżdżałem się nad tym stojąc pod piekarnią. GDZIE GO UMIEŚCIĆ I JAK OBSŁUŻYĆ? I wtedy przyszło OLŚNIENIE.😮 W całym kursie (część I) potencjometr był wykorzystywany jako sterownik PROGRAMU, czyli wpływał pośrednio na poszczególne elementy, ale przecież nie bezpośrednio! Tutaj potencjometr musiał być zastosowany bezpośrednio jako regulator napięcia na buzerze. Dla programu miał być PRZEŹROCZYSTY. Wtedy już wiedziałem, że to będzie działać!

Po powrocie do domu rzuciłem bułki w kąt i wmontowałem potencjometr w ten sposób, że jego plus poszedł do pinu 3, sygnał do plusa buzera, a minus wiadomo gdzie. 

Pytanie do eksperta: Czy takie podłączenie potencjometru ma sens? 

Pytanie do eksperta: Czy można uciszyć buzzer "lepiej", patrz programowo?

Kilka minut pisania kodu i... uciszam buzzer wydający miłe dźwięki. 😀😀😀

(Te wszystkie kable pochodzą z rozebranego Monstera, do którego pewnie jeszcze wrócę)

 

Ogólnie poziom endorfin wrócił do lvl azjata. 🙂 🙂 🙂 

Pozdrowienia dla Forumowiczów! 

A no i kod:

#define buzzer 3

void setup() {
  
pinMode(buzzer,OUTPUT);

}

void loop() {


for(int i=0;i<50;i++) {
sound();
delay(10);
}

}

void sound() {
    
  int freq = random(0,2000);
  for (int i = 0; i <= random(100,500); i++){      
  tone(buzzer, freq);          
  delay(random(.9,2));             
} 
  for (int i = 0; i <= random(100,1000); i++){
  tone(buzzer, freq + (-i * 10));          
  delay(random(.9,2));      
} 
noTone(buzzer);
 }

 

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

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.