Skocz do zawartości

Funkcja Input Capture w Arduino


Pomocna odpowiedź

8 minut temu, _LM_ napisał:

Tak na szybko odpowiadam w przerwaniu mususz aktualizowac tcnt2

O ile dobrze rozumiem to musze ten rejestr aktualizowac ,ale tylko wtedy kiedy wartosc ma byc mniejsza niz pojemnosc tego rejestru...w moim przypadku nie istotne bo zawsze zliczam od 0-256 zakresu 8-bitow...po przepelnieniu, osiagnieciu tej wartosci wywolane jest przerwanie i "TCNT" jest automatycznie kasowane do wartosci 0...cykl sie powtarza..

 

14 minut temu, _LM_ napisał:

albo skorzystać z rejestru porownania ocr2 chyba.

No tak, ale to juz w trybie porownania z opcja "CTC"..a ja korzystam ze zwyklego trybu licznika bez "OCR" czy "CTC"..i tez ma dzialac bez zadnych wygibasow..poprostu wykonuje sie to u mnie 2 razy szybciej i tyle. To zaden problem pomnozyc razy 2 przed uwzglednieniem wartosci zmiennych itp. no ale, jednak wolalbym wiedziec czemu tak sie dzieje...obliczenia chyba dobre mam..stad moje zdziwienie...dzieki za pomaganie/poswiecony czas😉

Link to post
Share on other sites
(edytowany)

Ok odrobiłem się troszkę więc tak: Dobrze kombinujesz z tym liczeniem jednak wg noty powinieneś ustawić bity CS20,21,22 wtedy preskaler wyniesie 1024. Liczy się to tak fCpu/1024 = 15625kHz co daje 1/15625 64µS na wejściu timera. Więc przy maks pojemności timera przerwanie będzie generowane co  16.32 mS trzeba 61 przerwań dla jednej sekundy. Co do programu nie wiem jak to jest w Arduino ale kompilatory C wymagają aby zmienna która ma być przeliczana w przerwaniu musi być volatile, jak jest w arduino nie wiem.. Przykładowy program mógłby wyglądać tak:

volatile uint8_t sek = 0;

void setup() {
pinMode(13, OUTPUT);
                                
  TCCR2B|=(1<<CS22)|(1<<CS21)|(1<<CS20);  //preskaler na 1024
  TIMSK2|=(1<<TOIE2);    //wlaczenie przerwania od przepelnienia
  //TCNT2=0;               //przypisanie wartosci startowej do licznika --> niepotrzebnie gdyż licznik i tak ma wartość 0
  sei();                 // przerwania globalne wlacz
}


void loop() {
//delay(77777);
/*
if (x == 61)  {
  digitalWrite(13, HIGH);
}
if (x == 122)  {
  digitalWrite(13, LOW);
  x = 0;
*/
digitalWrite(13, sek % 2);
}



ISR(TIMER2_OVF_vect)
{
  static uint8_t ovfCount = 61;
  if(!--ovfCount){
  sek++;
    ovfCount = 61;
  }
 }

 

Edytowano przez _LM_
  • Lubię! 1
Link to post
Share on other sites

Teraz mam sytuacje dokladnie przeciwna...czyli czestotliwosc zmiany jest dwa razy wolniejsza niz powinna..czyli 2s-on /2s-off itd.😉hehe

A czym sie roznia te vectory(?)?

TIMER1_CAPT_vect
TIMER1_OVF_vect

z tego co widze to kazdy z trzech timerow posiada te "funkcje" dobrze rozumiem ze

TIMER1_OVF_vect

Moge uzywac tylko w trybie normalnym/licznik a ten drugi czyli

TIMER1_CAPT_vect

W trybie porownania(?) z CTC..?

No i jeszcze takie pytanie mi sie nasuwa ze dzieki jednemu czy drugiemu trybowi moge odczytac lub wczytac stan logiczny na dowolny pin powiedzmy co 10us...wiec jaka przewage maja te piny? 

OC0
OC1
OC2

 

Link to post
Share on other sites
17 minut temu, farmaceuta napisał:

Teraz mam sytuacje dokladnie przeciwna...czyli czestotliwosc zmiany jest dwa razy wolniejsza niz powinna..czyli 2s-on /2s-off itd.😉hehe

A no tak... zliczenie od 61 do zera trwa 1s xD  ovfCount = 30 i po bólu.

17 minut temu, farmaceuta napisał:

A czym sie roznia te vectory(?)?

A ja już chyba to tłumaczyłem wcześniej hmm? OVF od przepełnienia, CAPT od przechwytu. I niema problemu oba mogą być aktywne co z resztą widać w kodzie który wcześniej wkleiłem. Patrz: mamy aktywne przerwanie od przechwytu i przepełnienia. I teraz gdy nadejdzie sygnał przechwytywania, w rejestrze ICR1 znajduje się wartość timera która została skopiowania w momencie tegoż sygnału(przechwytu). Jeśli nie zatrzymamy timera lub go nie wyzerujemy on liczy dalej jeśli doliczy do swojego max zgłosi przerwanie przepełnienia. Można je obsłużyć lub nie, ale timer nadal liczy. Inaczej jest w trybie CTC  - Clear Timer on Compare Match. Czyli zeruj timer po porównaniu i to działa tak że w rejestrze np OCR1 przetrzymujesz jakąś wartość np 123; i wtedy gdy wartość zliczona timera zrówna się z tą 123 timer zostanie automatycznie wyzerowany i zgłosi przerwanie. 

 

27 minut temu, farmaceuta napisał:

No i jeszcze takie pytanie mi sie nasuwa ze dzieki jednemu czy drugiemu trybowi moge odczytac lub wczytac stan logiczny na dowolny pin powiedzmy co 10us...wiec jaka przewage maja te piny?

Kurcze no ciężko żebym tłumaczył Ci tutaj całą notkę. Wyjścia OC są właśnie od sprzętowego generowania PWM lub Częstotliwości. Jest fajna książka która opisuje po Polsku co w AVR piszczy. Mikrokontrolery AVR AtMega w praktyce Rafała Baranowskiego. 

  • Pomogłeś! 1
Link to post
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

36 minut temu, farmaceuta napisał:

A czym sie roznia te vectory(?)?


TIMER1_CAPT_vect
TIMER1_OVF_vect

z tego co widze to kazdy z trzech timerow posiada te "funkcje" dobrze rozumiem ze

Bzdura w Atmedze328, tylko Timer1 ma funkcje przechwytywania.

Link to post
Share on other sites
(edytowany)
55 minut temu, farmaceuta napisał:

wiec jaka przewage maja te piny? 

Taką że sygnał na nich może być generowany automatycznie bez udziału programu

Spójrz też na to zwłaszcza na rozdział o Timerach

http://w-tarnawski.pl/wp-content/uploads/2014/08/Atmega16-polska-dokumentacja.pdf

Edytowano przez _LM_
  • Pomogłeś! 1
Link to post
Share on other sites
48 minut temu, _LM_ napisał:

A no tak... zliczenie od 61 do zera trwa 1s xD  ovfCount = 30 i po bólu

No wlasnie 1s...wiec stan diody powinien sie zmieniac co...1s. mam 61 przerwan na sekunde i gdy zmienna osiagnie ta wartosc to ma zmienic stan led...

 

54 minuty temu, _LM_ napisał:

 Inaczej jest w trybie CTC  - Clear Timer on Compare Match. Czyli zeruj timer po porównaniu i to działa tak że w rejestrze np OCR1 przetrzymujesz jakąś wartość np 123; i wtedy gdy wartość zliczona timera zrówna się z tą 123 timer zostanie automatycznie wyzerowany i zgłosi przerwanie. 

I to jest juz dla mnie zrozumiale😉 

 

1 godzinę temu, _LM_ napisał:

Bzdura w Atmedze328, tylko Timer1 ma funkcje przechwytywania.

Blad wynikajacy z tego ze jeszcze slabo zapamietalem te wszystkie nazwy i mi sie mieszaja..chodzilo o 

TIMER_COMP_vect

 

1 godzinę temu, _LM_ napisał:

Kurcze no ciężko żebym tłumaczył Ci tutaj całą notkę. 

Nie no jasne, ja rozumiem ze ciezko tak w kilku zdaniach odpowiedziec na wiele kwestii..😉

Dzieki wielkie za sporo wyjasnien..jak cos mi sie jeszcze uroi to bede pytal...😅

Link to post
Share on other sites

Trochę odkopię temat, bo od jakiegoś czasu właśnie próbowałem obsłużyć HC-SR04 w C, ale nie mogłem zrozumieć, jak zmierzyć czas impulsu, jak to zaimplementować w kodzie. Teraz też jeszcze nie wszystko do końca rozumiem, ale częściowo skopiowałem twój kod @_LM_ i w sumie zadziałało. Tylko usunąłem procedure obsługi od przepełnienia, bo gdy wywalało błąd, czujnik już nie mierzył odległości, musialem resetować uC. Ale bez tego też działa ok, pamiętam, że na arduino jak uruchamiałem go to przy maksymalnym zbliżeniu do ściany też walił jakieś błędy, trzeba było min. 1cm utrzymać. Teraz wkleje kilka linijek, które nie rozumiem, gdyby ktoś wytłumaczył po co to 😛

ISR (TIMER1_CAPT_vect){
	if (TCCR1B & (1 << ICES1)) {
			TCNT1 = 0;
			TCCR1B &= ~(1 << ICES1); // nastepne przerwanie na zbocze opadajace
			TIMSK1 |= (1 << TOIE1);    // odblokowanie przerwania od przepelnienia
		} else {
			TIMSK1 &= ~(1 << TOIE1); // blokuj przerwania przepelnienia
			TIMSK1 &= ~(1 << ICIE1); // blokuj przerwanie icp
			TCCR1B |= (1 << ICES1); // nast przerwanie na zbocze narastajace
			wynik = ICR1;
			start_pomiar = 2;
		}
}

Generalnie nie do końca rozumiem procedure obslugi przerwania. Wiem że sa komentarze, ale:

if (TCCR1B & (1 << ICES1))

Co ten warunek sprawdzam bo nie do konca kumam dlaczego maskujemy bit ICES1

TIMSK1 &= ~(1 << TOIE1); // blokuj przerwania przepelnienia
TIMSK1 &= ~(1 << ICIE1); // blokuj przerwanie icp
TCCR1B |= (1 << ICES1); // nast przerwanie na zbocze narastajace

Tu po else tez nie bardzo wiem. Chyba mam problem ze zrozumieniem jak sie ten impuls mierzy.

TIFR1 &= ~(1 << ICF1); // kasowanie flagi przerwania na wypadek gdyby sie "uchowalo"
TIMSK1 |= (1 << ICIE1); // przerwania od przechwytu
TCNT1 = 0;          // zerowanie timera
TCCR1B |= (1 << ICES1);   // przerwanie na zboczu narastajacym

Tu też nie wiem hmm czemu włączamy znowu przerwania od przechwytu jak były włączone w na poczatku w main.. Sorry za glupie pytania, ale oprócz tego, że mi działa to chciałbym zrozumiec dlaczego 😄

Link to post
Share on other sites
Dnia 20.04.2021 o 11:58, _LM_ napisał:

Po wyświetleniu wyniku warto nieco odczekać zrobiłem to delay-em nie jest to rozwiązanie eleganckie no ale niech będzie. Opóźnienie jest konieczne gdyż HC... ma ograniczoną ilość pomiarów w sekundzie różne źródła różnie mówią czytałem gdzieś o max 20 pomiarów/sek.

Ostatni warunek w loop



		if (start_pomiar == 3) {
			uart_puts(0, "POZA ZAKRESEM!"); // gdy przerwanie od przepelnienia
			start_pomiar = 0;
		}

   Może się zdarzyć że licznik się "przekręci" czyli doliczy do swojego MAX(65535) i zacznie liczyć od zera. Czasami zdarza się że hc potrafi się zawiesić przy większych odległościach wtedy można to pośrednio wykryć dzięki temu przerwaniu.

Wisienka na torcie: przerwania



ISR(TIMER1_CAPT_vect) { // przechwyt

	if (TCCR1B & (1 << ICES1)) { // sprawdzam na jakie zbocze zareagoalo przerwanie
		TCNT1 = 0;
		TCCR1B &= ~(1 << ICES1); // nastepne przerwanie na zbocze opadajace 
		TIMSK |= (1 << TOIE1);    // odblokowanie przerwania od przepelnienia
	} else {
		TIMSK &= ~(1 << TOIE1); // blokuj przerwania przepelnienia
		TIMSK &= ~(1 << TICIE1); // blokuj przerwanie icp
		TCCR1B |= (1 << ICES1); // nast przerwanie na zbocze narastajace
		wynik = ICR1;
		start_pomiar = 2;
	}
}

TCCR1B wg notykatalogowej  Timer/Counter1 Control Register B czyli rejestr kontrolny "B" timera1



if (TCCR1B & (1 << ICES1)) { // sprawdzam na jakie zbocze zareagoalo przerwanie

Jeśli w rejestrze ICES1 (Input Capture Edge Select)była jedynka to znaczy że zbocze było narastające i czas rozpocząć pomiar. 

Zeruję timer (Timer/Counter1)



TCNT1 = 0;

i liczymy czas....... a gdy



	} else {
		TIMSK &= ~(1 << TOIE1); // blokuj przerwania przepelnienia
		TIMSK &= ~(1 << TICIE1); // blokuj przerwanie icp
		TCCR1B |= (1 << ICES1); // nast przerwanie na zbocze narastajace
		wynik = ICR1;
		start_pomiar = 2;

wcześniejszy warunek dał w odpowiedzi 0 wykonuje się ten fragment. 

Przerwanie od przepełnienia



ISR(TIMER1_OVF_vect) { // przepelnienie
	PORTC ^= (1 << PC1); // sygnalizacja przepelnienia
	start_pomiar = 3;
	TIMSK &= ~(1 << TOIE1); // blokowanie tego przerwania
}

jeśli do niego doszło to dioda zmieni swój stan na przeciwny, blokuję też to przerwanie przez wyzerowanie bitu TOIE1 po to aby przy zablokowanym HC program nie skakał do tej funkcji.

Proszę usunąć ten wpis gdyż @Krawi92 szybko odpisał i teraz niema on sensu 

Edytowano przez _LM_
  • Lubię! 1
Link to post
Share on other sites
Przed chwilą, Krawi92 napisał:

I nie do konca kumam zasade jak się zlicza ten czas impulsu. 

No to musisz zobaczyć jak działa ten HC:

uploads2ftmp2f0e8762c9-13ef-48e3-8ee9-838c7f24ca8d2f2_ultrasonic_module_timing_diagram_IoXUGXtipu.thumb.jpg.aab5dd8aa2c35ddf7633492e10878573.jpg

a więc po impulsie "trig", kiedy na pinie echo jest zbocze narastające(wtedy już ICP powinno być skonfigurowane na to zbocze), natychmiast ustawiamy wejście ICP aby reagowało na zbocze opadające i zaczynamy liczyć czas. Kiedy to zbocze(opadające) nadejdzie - znaczy że jest w liczniku jakaś wartość i można obsłużyć wynik, po tej obsłudze znów ustawiasz ICP na zbocze narastające itd.. w koło Macieju 😉. Przerwanie od przepełnienia licznika było po to aby -kiedy nie nadejdzie impuls powrotny - móc jakoś na to zareagować.

Link to post
Share on other sites
31 minut temu, Krawi92 napisał:

pamiętam, że na arduino jak uruchamiałem go to przy maksymalnym zbliżeniu do ściany też walił jakieś błędy, trzeba było min. 1cm utrzymać. Teraz wkleje kilka linijek, które nie rozumiem, gdyby ktoś wytłumaczył po co to 😛

Cóż.... taki urok arduinowych "libsów". Ale faktem jest że niektóre z tych czujników potrafią się zawiesić jeśli sygnał echa nie powraca.

Link to post
Share on other sites
10 minut temu, _LM_ napisał:

Cóż.... taki urok arduinowych "libsów". 

Ja bym tu bardziej byl sklonny zwalic winne na czujniki...wkoncu czego sie spodziewac po module za piatke?😉 jak na te ceny to i tak moze byc...wkoncu to taniocha do prostych zadan hobbystycznych i raczej bym nie liczyl na dokladnosci do cm (+ powtarzalnosc tego pomiaru)

Link to post
Share on other sites

jesli chodzi o dokladnosc to nie ma tragedii... miarką mierzyłem do 50cm i się zgadza. Na razie próbuje się wczytać w sam tryb input capture i skumać jak to działa, żeby samemu z głowy napisać obsługe.

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

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.