Skocz do zawartości

[C][Atmega8] Kilka pytań dotyczących HC-SR04


Dagon

Pomocna odpowiedź

Witam wszystkich,
otóż męczę się od wczoraj z poprawnym zaprogramowaniem czujnika ultradźwiękowego HC-SR04. Przeczytałem już multum różnych poradników na ten temat, ale wciąż nie jestem pewien jak sobie z tym poradzić. Dlatego też mam parę pytań (jeśli jakieś pytanie jest głupie to mi wybaczcie, jestem amebą intelektualną robotyki):

1. Jaki timer powinienem podłączyć do czujnika i dlaczego? (w Atmega8)

2. Jak powinny być na początku ustawione piny w Echo i Trig? (w sensie DDRx i PORTx na zero czy na jeden)

3. Jeśli dobrze zrozumiałem poradniki i dokumentacje to mam na 10us zmienić napięcie Trig na wysokie, a potem z powrotem na niskie. Kiedy fala się odbija to wraca do Echo i on zmienia swoje napięcie na wysokie na czas od zmiany Trig na napięcie niskie do wyłapania fali. Kiedy pin Echo równa się 1 to włączyć timer i wyłączyć go, gdy Echo wróci do stanu 0. Czas, który przed chwilą zliczył timer podzielić przez 58, żeby dystans wyszedł w cm. Czy dobrze to rozumiem? Jeśli nie to proszę o wskazanie błędu w moim myśleniu. (mam nadzieję, że da się zrozumieć co napisałem)

Z góry dzięki za odpowiedzi.

PS: Mam nadzieję, że temat nie łamie regulaminu, ale jeśli tak to proszę o zmianę na adekwatny do zasad forum.

Link do komentarza
Share on other sites

Nie chcę zakładać nowego tematu więc napiszę tutaj (właściwie to jest na temat).

Napisałem sobie kod, który powinien zaświecić diodą, kiedy Echo odbiera sygnał z Trig (żeby przetestować czy w ogóle działa mi ten czujnik). Wydaje mi się, że do tego nie potrzeba timerów, więc napisałem coś takiego:

#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>

#define Echo PB0
#define Trig PD0

volatile int dlugosc = 0;
int main(void)
{
DDRD |= (1<<Trig);
DDRB &= ~(1<<Echo);
PORTB &= ~(1<<Echo);


   while(1)
   {
  if(dlugosc == 0)
  {
	  DDRB &= ~((1<<PB7) | (1<<Echo));
	  PORTB &= ~((1<<PB7) | (1<<Echo));
  }
  else
  {
	  DDRB = 0b10000000;
	  PORTB = 0b10000000;
  }

  _delay_ms(1000);
  PORTD |= (1<<Trig);
  _delay_us(10);
  PORTD &= ~(1<<Trig);

  if(!(PINB & (1<<Echo)))
  {
	  if(dlugosc == 0)
	  {
		  dlugosc = 1;
	  }
	  else
	  {
		  dlugosc = 0;
	  }
  }

}
}

Mógły mi ktoś powiedzieć co źle robię? Już od trzech dni próbuję ogarnąć ten czujnik i zero postępu...

ps: led jest podłączony do PB7.

Link do komentarza
Share on other sites

Po pierwsze:

      PORTD |= (1<<Trig);
     _delay_us(10);
     PORTD &= ~(1<<Trig); 

10 us to minimalny czas przez jaki musi być '1' na 'Trig'. Więc jeśli twoja Atmega ma niedokładny zegar (np. wewnętrzny RC) to ten czas może okazać się np. 9.5 us i czujnik nie zadziała. A jeśli masz źle ustawioną częstotliwość w projekcie np. 1 MHz, a w rzeczywistości procek pracuje na 8 MHz to będziesz miał ustawiany pin 'Trig' na tylko 1.25 us. Polecam więc w ten delay wstawić 100 us:

      PORTD |= (1<<Trig);
     _delay_us(100);
     PORTD &= ~(1<<Trig); 

Po drugie:

      if(dlugosc == 0)
     {
         DDRB &= ~((1<<PB7) | (1<<Echo));
         PORTB &= ~((1<<PB7) | (1<<Echo));
     }
     else
     {
         DDRB = 0b10000000;
         PORTB = 0b10000000;
     }

Pin jako wejście lub wyjście definiuje się tylko raz, przed pętlą główną. Pin leda ustawiasz tu jako wejście, a przecież powinno to być wyjście.

Po trzecie:

      PORTD |= (1<<Trig);
     _delay_us(10);
     PORTD &= ~(1<<Trig);

     if(!(PINB & (1<<Echo)))

Oczekujesz tu, że stan pinu 'Echo' zmieni się od razu po wystawieniu jedynki na 'Trig', tak się nie stanie. Lepiej czekać na zmianę stanu pinu 'Echo' przy użyciu instrukcji while:

      while(!(PINB & (1<<Echo)))
  • Lubię! 1
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

Wracam ponownie,
Otóż już zacząłem pisanie tego czujnika tak, żeby mierzył odległość. Powiem nawet, że jestem już w połowie sukcesu. LCD wyświetla dobre wartości dla odległości od 10 - 29 cm. Teraz wypiszę jakie są problemy:

1. Gdy odległość jest mniejsza od 10 to źle wskazuje wynik np. dla 9 cm pokazuje 90 cm, dla 8 cm pokazuje 80 cm itd.

2. Gdy odległość jest większa od 29 cm, licznik zaczyna wariować.

3. Czasem zdarza się, że licznik zatrzymuje się na jakiejś liczbie i po prostu przestaje działać (trzeba wyłączyć i włączyć).

A tutaj kod:

#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>

#define Echo PB0
#define Trig PD0

volatile int dlugosc = 0;
char konwersja[3];
int main(void)
{
DDRD |= (1<<Trig);
DDRB &= ~(1<<Echo);
TCCR1B |= (1 << CS10);
LCD_Initalize();
LCD_Clear();
   while(1)
   {
	 PORTD |= (1<<Trig);
	 _delay_us(500);
	 PORTD &= ~(1<<Trig);

	 while(!(PINB & (1<<Echo)))
	 {
		 TCNT1 = 0;
	 }
	 while(PINB & (1<<Echo))
	 {
		 if(TCNT1 != 0)
		 {
			 dlugosc = TCNT1 * 34 / 1000 / 2;
		 }
	 }
	 sprintf(konwersja, "%i", dlugosc);
	 LCD_GoTo(0, 0);
	 LCD_WriteText(konwersja);
	 LCD_GoTo(5, 0);
	 LCD_WriteText("cm");
}
}

Z góry dzięki za pomocne odpowiedzi.

Link do komentarza
Share on other sites

1. Gdy odległość jest mniejsza od 10 to źle wskazuje wynik np. dla 9 cm pokazuje 90 cm, dla 8 cm pokazuje 80 cm itd.

Mam wrażenie że problem leży tu:

       LCD_GoTo(0, 0);
       LCD_WriteText(konwersja);
       LCD_GoTo(5, 0);
       LCD_WriteText("cm");

Zero zostaje z poprzedniego odczytu, nie czyścisz go w żaden sposób.

  • Lubię! 1
Link do komentarza
Share on other sites

1. Gdy odległość jest mniejsza od 10 to źle wskazuje wynik np. dla 9 cm pokazuje 90 cm, dla 8 cm pokazuje 80 cm itd.

Mam wrażenie że problem leży tu:

       LCD_GoTo(0, 0);
       LCD_WriteText(konwersja);
       LCD_GoTo(5, 0);
       LCD_WriteText("cm");

Zero zostaje z poprzedniego odczytu, nie czyścisz go w żaden sposób.

Tak, to było problemem! Dzięki wielkie.

PS: Przy okazji zauważyłem, że nie wyświetla się w ogóle 7 cm. (Edit: oprócz tego jeszcze 14 i chyba 21, ale domyślam się, że to przez ten wzór na dystans).

PS2: Gdy odległość jest większa od 34 to zaczyna mi naliczać jakby od nowa odległość tzn. zamiast 35cm pokazuje mi 1, zamiast 36cm pokazuje mi 2 itd.

Link do komentarza
Share on other sites

PS: Przy okazji zauważyłem, że nie wyświetla się w ogóle 7 cm. (Edit: oprócz tego jeszcze 14 i chyba 21, ale domyślam się, że to przez ten wzór na dystans).

PS2: Gdy odległość jest większa od 34 to zaczyna mi naliczać jakby od nowa odległość tzn. zamiast 35cm pokazuje mi 1, zamiast 36cm pokazuje mi 2 itd.

Tak, to przez ten wzór.

dlugosc = TCNT1 * 34 / 1000 / 2;

TCNT1 jest typu 'uint16_t', czyli "TCNT1 * 34" też musi się mieścić w tym typie (maksimum 65535), co daje maksymalną dlugosc: 65535 / 2000 = 32.7675. Aby tego uniknąć należy rzutować na typ o większym zakresie. Na przykład tak:

dlugosc = TCNT1 * 34UL / 2000UL;
Link do komentarza
Share on other sites

PS: Przy okazji zauważyłem, że nie wyświetla się w ogóle 7 cm. (Edit: oprócz tego jeszcze 14 i chyba 21, ale domyślam się, że to przez ten wzór na dystans).

PS2: Gdy odległość jest większa od 34 to zaczyna mi naliczać jakby od nowa odległość tzn. zamiast 35cm pokazuje mi 1, zamiast 36cm pokazuje mi 2 itd.

Tak, to przez ten wzór.

dlugosc = TCNT1 * 34 / 1000 / 2;

TCNT1 jest typu 'uint16_t', czyli "TCNT1 * 34" też musi się mieścić w tym typie (maksimum 65535), co daje maksymalną dlugosc: 65535 / 2000 = 32.7675. Aby tego uniknąć należy rzutować na typ o większym zakresie. Na przykład tak:

dlugosc = TCNT1 * 34UL / 2000UL;

Niestety to nie pomogło.

Link do komentarza
Share on other sites

Juz spiesze z pomoca, w moim przypadku czujnik zaczynal wariowac a procek sie zawieszac kiedy zasilanie i GND HC-SR04 bylo podlaczone blisko zasilania i GND procka.

Zaczalem wiec odsuwac czujnik od mikroprocka i bylo coraz lepiej ale dopiero zawieszenia procka ustaly gdy zaczalem zasilac czujnik napieciem sprzed stabilizatora a gnd bylo tuz obok gnd od baterii.

Druga smocza zasada jest to ze wszystkie delaye w przypadku pomiarow tak krotkich sygnalow bez udzialu przetwornika ADC poprostu zabijaja cala konstrukcje, musisz je ograniczyc do minimum, a w szczegolnosci ten wyzwalajacy pomiar to juz MAKSYMALNIE 15us, sproboj tez taktowac procesor jak najwieksza czestotliwoscia zeby zadne stany ci nie umknely, u mnie jest to 8 MHZ.

A no i oczywiscie najlepiej to by bylo generowac przerwania od stanu wysokiego/niskiego na pinie ECHO.

W zalaczniku dorzucam ci moj kod uzbrojony w pomiar medianowy czyli skladajacy sie z kilku pomiarow i sredniej z nich wyciagnietej.

Oczywiscie kod moznaby usprawnic dodaniem jeszcze jednego timera ktory by odliczal superokladnie czas sygnalu ECHO, ale w sumie to co jest daje wystarczajace rezultaty.

W zalaczniku masz kompletny kod (bez biblioteki HD44780)

W algorytmie znajduje sie rowniez prototyp funkcji ktora w przypadku wystapienia w krotkiej chwili 1 do 2 bardzo rozniacych sie pomiarow odrzuca je i kaze wykonac te pomiary od nowa az do skutku, jednak jest niedopracowana i w sumie pomiar medianowy dal juz wystarczajace wyniki.

Pozostaje rowniez kwestia tego ze ten czujnik nie jest idealny, przy malych przedmiotach i rownoczesnej odleglosci >50 cm wystarczy niewielki kat odchylenia przedmiotu (tak ze fala ultradzwiekowa nie odbija sie od prostopadlej przeszkody) i masz po pomiarze i tego sie juz nie da raczej naprawic.

Ew rozwiazaniem byloby zastosowanie 2 takich czujnikow w kooperacji i dzialalyby one jak uklad stereofoniczny, jednak to juz wyzsza szkola jazdy a moj projekt mial slozyc jedynie do nauki i nic wiecej.

addons.h

addons.c

serwo+odleglosc.c

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.