logo elektroda
logo elektroda
X
logo elektroda
REKLAMA
REKLAMA
Adblock/uBlockOrigin/AdGuard mogą powodować znikanie niektórych postów z powodu nowej reguły.

atmega16, AVR Studio, C - różne czasy wykonania fragmentu kodu

Clay 03 Cze 2011 21:33 2006 13
REKLAMA
  • #1 9574084
    Clay
    Poziom 12  
    Witam,
    Chcę dokonać pomiaru odległości ultradźwiękami. Najpierw program wysterowuje nadajnik ultradźwiękowy falą prostokątną 40kHz (timer0). W tym czasie rusza też timer1 mierzący czas do odebrania sygnału przez odbiornik. Po pewnej chwili (gdy timer1 osiągnie wartość wpisaną do rejestru OCR1AL) wyłączam generację prostokąta (zatrzymuje timer0). I teraz program tylko czeka na odbiór fali przez odbiornik. Problem jest taki że wykonując to cyklicznie co drugi wynik pomiaru różni się o około 20 (czyli np. otrzymuję kolejno 340, 361, 340, 361, 340..)
    Nie mogę znaleźć powodu takiego działania dlatego prosiłbym o pomoc:) Może zajmie to komuś z Was pare minut, a ja siedzę już 3 dni nad tym:/. Dodam że uwzględnianie co drugiej wartości pomiaru nie wchodzi w grę niestety:)

    Poniżej zamieszczona jest pętla główna programu w C oraz część pliku *.lss. Nie znam sie za dobrze na asemblerze AVR bo zetknąłem się tylko dawno temu z asemblerem '51. Może należy zamienić te pare linijek na kod w asm? Albo jakiś inny zapis tego w C?

    Sprawdzałem też wersję w wyłączeniem obsługi przerwań (zakomentowane komendy cli() i niżej sei() ) i nic. Próbowałem też wersję z użyciem rejestru przechwytywania ICR1 i wynik taki sam.

    pętla główna w C:


    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    fragment wygenerowanego pliku *.lss

    
    
    		 	//cli();
    										
    			// SFIOR - reset preskalera
    			SFIOR = (1 << PSR10);		
     7d6:	f0 be       	out	0x30, r15	; 48
    		
    			TCCR1B = 2; // start T1 częstotliowsc taktowania = CLK/8
     7d8:	ee bc       	out	0x2e, r14	; 46
    			TCCR0 = (1 << WGM01)|(1 << COM00)|(1 << CS00); //start T0, tryb CTC
     7da:	d3 be       	out	0x33, r13	; 51
          
    				//oczekiwanie na chwile gdy minie OCR1AL czasu na T1, wtedy zakończ generacje 40kHz
    				while(!(TIFR & 0x10)){};
     7dc:	08 b6       	in	r0, 0x38	; 56
     7de:	04 fe       	sbrs	r0, 4
     7e0:	fd cf       	rjmp	.-6      	; 0x7dc <main+0xb0>
    				 		TCCR0 = 0;		//zatrzymanie generacji paczki impulsów 40kHz
     7e2:	13 be       	out	0x33, r1	; 51
    				 		PORTB |= _BV(3);	//stan wysoki na wyjsciu PB3 (OC0)
     7e4:	c3 9a       	sbi	0x18, 3	; 24
    
    				while  (!(GIFR & 0x40));
     7e6:	0a b6       	in	r0, 0x3a	; 58
     7e8:	06 fe       	sbrs	r0, 6
     7ea:	fd cf       	rjmp	.-6      	; 0x7e6 <main+0xba>
    				
    					TCCR1B = 0; // stop T2
     7ec:	1e bc       	out	0x2e, r1	; 46
    				//sei();
    
    				if(!timeout)			//jeśli czas odebrania nie upłynął to wypisz nową wartosc
     7ee:	80 91 66 00 	lds	r24, 0x0066
     7f2:	88 23       	and	r24, r24
     7f4:	99 f0       	breq	.+38     	; 0x81c <main+0xf0>
    						
    
    						}
    
    
    
    
  • REKLAMA
  • #2 9575893
    janbernat
    Poziom 38  
    Pod koniec programu masz:
    Reset flagi przerwania.
    Opóźnienie 70ms.
    Jesteś pewien że w tym czasie nie pojawi się natępne przerwanie?
    Już nic nie generujesz- ale ile trwa wygaszanie impulsów odbitych?
  • REKLAMA
  • #3 9576098
    Clay
    Poziom 12  
    Przed tym resetem GIFR = (1 << INTF0) jest opóźnienie 2ms i w tym czasie juz cała fala ultradźwiękowa zanika napewno.
    Opźnienie 70ms to tylko opóźnienie między pomiarami... zwiększyłem je zeby widzieć różnice na lcd w kolejnych pomiarach.

    Wlaśnie zauważyłem problem tylko nie wiem do konca jeszcze gdzie jest ten szczegół:
    Mianowicie jak uruchomię już na końcu pętli (za _delay_ms(70); ) na chwilę licznik T0 (ten od generacji prostokąta - 40kHz (okres 25us) to:
    1) jak wyłączę go przed "połową okresu" czyli np. po 2us albo 2us+25us to wynik jest nadal zły
    2) jak wyłączę go po połowie okresu czyli np. po 18us itd. to wynik pomiaru jest dobry

    Nie mięrzę wtedy żadnego czasu licznikiem T1 i nic nie wyświetlam... Tak po prostu włączyłem T0 na chwile żeby zobaczyć czy powodem jest ten albo drugi licznik.
    Widocznie nie ustawiam (resetuję) po dokonanym pomiarze wszystkich parametrów tego licznika. Pewnie licznik T0 działając w trybie CTC zatrzymuje mi sie pomiędzy połową okresu a pełnym okresem tych 25us.
    Szukam dalej:/
  • #4 9576222
    janbernat
    Poziom 38  
    Może str.84
    Timer/Counter0
    and
    Timer/Counter1
    Prescalers

    Albo 72.
    Compare Match
    Blocking by TCNT0
    Write.
    Przyznam się że tak głeboko w Timery nie sięgałem- ale może to być jakiś trop.
  • #5 9576454
    Clay
    Poziom 12  
    dobra.. ominąłem problem i wpisałem do rejestru OCR1AL (tego który definiował jak długo ma być generowany paczka impulsów prostokątnych) taką wartość żeby timer T0 kończył generację w "parzystym" cyklu (jak zaczynałem od stanu niskiego na wyjściu OC0 to na niskim kończę)...
    nie wiem czemu tak jest ale może tak chyba działać:P
    dzięki za pomoc janbernat :)
  • #6 9576568
    janbernat
    Poziom 38  
    No to wklej kod- dla potomności.
    No i ja bym tak nie omijał- działa- to dobrze.
    Ale- dlaczego?
    Poza tym- gdzie zmieniasz timeout?
    Bo tak jak jest to jest stale 0 i w tego if stale wchodzisz.
  • #7 9576653
    Clay
    Poziom 12  
    No dobrze by bylo wiedziec czemu tak jest:P ale torche nie mam czasu narazie szukac bo czas mnie goni a straciłem na tym 4 dni.. Może wyjdzie jeszcze w praniu:P
    Warunek timeout sprawdzam w przerwaniu od porównania licznika T1:

    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    A jeśli chodzi o kod to jest dokładnie taki sam tylko że wpisałem do OCR1 110 przy inicjalizacji zamiast 90. Dzięki temu timer T0 kończy generację tak jak pisałem poprzednio (zaczynamy od stanu niskiego na OC0 i na takim (w trakcie) konczymy)

    Kod: C / C++
    Zaloguj się, aby zobaczyć kod
  • REKLAMA
  • #9 9576691
    Clay
    Poziom 12  
    hahaha:P wiedzialem ze komus wpadnie to w oko:P juz to poprawiłem..
    to było żeby przerwać tą pętlę w końcu jeśli nic nie odbierze odbiornik:

    while (!(GIFR & 0x40)); //oczekiwanie na odbiór w nadajniku (pin INT0)

    Ale jako że przerwania w sumie nie uzywam pozamieniałem to na:

    while (!(PIND & 0x04));

    A zamiast tej mojej "sztucznej generacji zbocza" ustawiam tam ten pin na 1 i później zmieniam znowu na 0 :)[/code]
  • REKLAMA
  • #11 9576757
    Clay
    Poziom 12  
    hmm.. Taka wersja mi została po tym jak szukałem własnie przyczyny tych "różnych czasów wykonania" fragmentów kodu.. Zastanawiałem się czy skok do przerwania i tam jakies sprawdzenie warunków nie trwały różnie... Bo juz naprawde nie wiedziałem gdzie może być błąd. Dlatego też sprawdzałem wersję z wyłączonymi przerwaniami i oczekiwałem w programmie tylko na ten sygnał na odbiorniku..
    Teraz to chyba w sumie obojętnie czy będę to robił w przerwaniu czy w tym miejscu..
  • #13 9576790
    Clay
    Poziom 12  
    No teraz to już żadnych:) Wcześniej w jednej z wersji mi sie pojawiło coś takiego chyba. Bo nawet nie byłem pewny czy mi sie timer1 zatrzymuje w przerwaniu jak chciałem.. Generalnie różne miałem wątpliowści więc skończyłem na takiej wersji.. Teraz jak (prawie) znam przyczynę to mogę kod ładnie popoprawiać:)
REKLAMA