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

[ATMEGA128] Timer1 w trybie CTC

Lysoleq 05 Lip 2008 16:24 4121 23
REKLAMA
  • #1 5314381
    Lysoleq
    Poziom 17  
    Witam.
    Chciałem wykorzystać w Atmedze 128 Timer1 do wykonania zegara zliczającego sekundy. W tym celu ustawiłem go w trybie CTC i po zliczeniu do 62500 (taką wartość wpisuje do OCR1A] powinno nastąpić przerwanie. Nie wiem czemu tak się nie dzieje.

    Atmega taktowana jest kwarcem 16MHz. W układzie cały czas aktywne jest globalne zezwolenie na przerwania [znacznik I w SREG].


    
    .CSEG
    .ORG	$000	RJMP	RESET
    .ORG	$018	RJMP	DATA
    
    ...
    
    KONFIGURACJA_TIMER1:
    push	r16
    in	r16,SREG
    push	r16
    
    ldi	r16,high(62500)
    out	OCR1AH,r16
    ldi	r16,low(62500)	;ustaw przerwanie po czasie 1s
    out	OCR1AL,r16	;dla częstotliwości 16MHz
    
    in	r16,TIMSK
    ldi	r16,(1<<OCIE1A)
    out	TIMSK,r16	;ustaw przerwanie porownania OCIE1A
    
    in	r16,TCCR1B
    ldi	r16,(1<<CS12)|(0<<CS11)|(0<<CS10)|(1<<WGM12)	
    out	TCCR1B,r16	;ustaw tryb pracy licznika na CTC
    			;ustaw prescaler licznika na 256
    			;uruchom licznik
    
    pop			r16
    out			SREG,r16
    pop			r16
    reti
    
    DATA:
    
    w tej procedurze Atmega128 ma zgasić diodę. Ogólnie później zmienię jej przeznaczenie, natomiast narazie widzę dzięki temu czy układ działa poprawnie.
    
    reti
    


    Moje pytanie brzmi: Dlaczego to nie działa?
  • REKLAMA
  • Pomocny post
    #2 5314827
    ZbeeGin
    Poziom 39  
    Działa. Pewnie o czymś zapomniałeś na wstępie. Mój działający kod:
    .include "m128def.inc"
    
    	.cseg 
    
    	.org	0x0000
    	rjmp	reset				;skok po resecie systemu
    	
    	.org	0x0018
    	rjmp	data				;skok po wykryciu zgodności
    
    reset:
    	ldi		r16, high(RAMEND)
    	out		SPH, r16
    	ldi		r16, low(RAMEND)
    	out		SPL, r16
    	
    	rcall	KONFIGURACJA_TIMER1
    	sei
    
    loop:
    	nop
    	rjmp	loop
    
    ;...
    
    KONFIGURACJA_TIMER1:
    	push	r16
    	in		r16, SREG 
    	push	r16
    
    	ldi		r16, high(62500) 
    	out		OCR1AH, r16 
    	ldi		r16, low(62500)		;ustaw przerwanie po czasie 1s 
    	out		OCR1AL, r16			;dla częstotliwości 16MHz 
    
    	in		r16, TIMSK 
    	ldi		r16, (1<<OCIE1A) 
    	out		TIMSK, r16   		;ustaw przerwanie przełenienia licznika 
    
    	in		r16, TCCR1B 
    	ldi		r16, (1<<CS12)|(0<<CS11)|(0<<CS10)|(1<<WGM12)    
    	out		TCCR1B, r16			;ustaw tryb pracy licznika na CTC 
    								;ustaw prescaler licznika na 256 
    								;uruchom licznik 
    	pop		r16 
    	out		SREG,r16 
    	pop		r16 
    	ret
    
    DATA: 
    ; w tej procedurze Atmega128 ma zgasić diodę. Ogólnie później zmienię jej 
    ; przeznaczenie, natomiast narazie widzę dzięki temu czy układ działa 
    ; poprawnie. 
    	reti


    Dodano po 11 [minuty]:

    Oczywiście prościej i dokładniej byłoby skorzystać z licznika TIMER0 pracującego z taktowaniem asynchronicznym za pomocą kwaru "zegarkowego"...
  • #3 5314874
    Lysoleq
    Poziom 17  
    Faktycznie, było by prościej, niestety nie posiadam w układzie wolnych wyprowadzeń i muszę sobie poradzić w inny sposób.

    Wypróbowałem kod który przedstawiłeś i nie widać absolutnie żadnej różnicy w działaniu :/.
  • #4 5314908
    ZbeeGin
    Poziom 39  
    Wrzuć ten:
    .include "m128def.inc"
    
    	.cseg 
    
    	.org	0x0000
    	rjmp	reset				;skok po resecie systemu
    	
    	.org	0x0018
    	rjmp	data				;skok po wykryciu zgodności
    
    reset:
    	ldi		r16, high(RAMEND)
    	out		SPH, r16
    	ldi		r16, low(RAMEND)
    	out		SPL, r16
    	
    	rcall	KONFIGURACJA_TIMER1
    	sei
    
    loop:
    	nop
    	rjmp	loop
    
    ;...
    
    KONFIGURACJA_TIMER1:
    	push	r16
    	in		r16, SREG 
    	push	r16
    
    	ldi		r16, high(62500) 
    	out		OCR1AH, r16 
    	ldi		r16, low(62500)		;ustaw przerwanie po czasie 1s 
    	out		OCR1AL, r16			;dla częstotliwości 16MHz 
    
    
    	ldi		r16, (1<<OCIE1A) 
    	out		TIMSK, r16   		;ustaw przerwanie przełenienia licznika 
    
    	sbi		DDRB, PORTB5
    	ldi		r16, (1<<COM1A0)	;migaj diodą na OC1A.
    	out		TCCR1A, r16
    
    	ldi		r16, (1<<CS12)|(0<<CS11)|(0<<CS10)|(1<<WGM12)    
    	out		TCCR1B, r16			;ustaw tryb pracy licznika na CTC 
    								;ustaw prescaler licznika na 256 
    								;uruchom licznik 
    	pop		r16 
    	out		SREG,r16 
    	pop		r16 
    	ret
    
    DATA: 
    ; w tej procedurze Atmega128 ma zgasić diodę. Ogólnie później zmienię jej 
    ; przeznaczenie, natomiast narazie widzę dzięki temu czy układ działa 
    ; poprawnie. 
    	reti

    i podłącz diodę do PB5. Katodą do portu, anodą do Vcc przez rezystor 330R.
  • REKLAMA
  • #5 5314972
    Lysoleq
    Poziom 17  
    Diody nie podłącze bo układ mam już gotowy i nie chce przy nim majstrować. W części DATA wpisałem funkcje mającą zapalić diodę gdy wystąpi przerwanie licznika. Nie wiem czemu nigdy nie następuje to przerwanie.
  • #6 5314987
    ZbeeGin
    Poziom 39  
    Skąd wiesz, że ono nie następuje? Przecież sterowanie diodą też odbywa się progamowo. Mogłeś popełnić byka w tym sterowaniu i nawet o tym nie wiesz...
    Dlatego podesłałem kod, który wszystko robi sprzętowo. Skoro nie chcesz go wgrać i zrobić tego testu to możesz spędzić 2 lata na szukaniu błędu... Być może nie tam gdzie trzeba.
  • #7 5315089
    Lysoleq
    Poziom 17  
    Faktycznie, licznik działa. Wsadziłem układ na oscyloskop i wszystko PB5 zmieniał stan z wysokiego <> niski. Ale dlaczego nie wywołuje przerwania umieszczonego pod 0x0018?
  • #9 5315189
    Lysoleq
    Poziom 17  
    Balu czemu nie nastąpi przerwanie związane z porównaniem?
  • #11 5315244
    Lysoleq
    Poziom 17  
    W takim razie jak zrobić żeby nastąpiło przerwanie gdy TCNT1 jest zgodne z OCR1A? W doumentacji takie wektor przerwania jest pod adresem 0x0018, ale jak spowodowac jego wywolanie?
  • REKLAMA
  • #12 5315272
    ZbeeGin
    Poziom 39  
    Balu napisał:
    ZbeeGin, ale przepełnienie nie nastąpi, podobnie jak Compare nie (chyba, ze będzie wcześniej niż ctc)...

    Wystąpi, wystąpi. Gdyby rejestr porównania nie działał w tym trybie to licznik by się sam nie skasował w trybie CTC, bo niby skąd miałby wiedzieć kiedy ma to zrobić... :)
    Cytat:
    An interrupt can be generated at each time the counter value reaches the TOP value by either using the OCFnA or ICFn flag according to the register used to define the TOP value.

    Powiem więcej. Jeśli licznik zrówna się z liczbą z OCR1A to jeszcze nic się nie stanie. Dopiero na początku w cyklu w któym TCNT1 zrówna się z OCR1A+1 licznik się przepełni i skasuje. Przy tak wysoko ustawionym preskalerze może to mieć znaczenie przy dokładnym odmierzaniu czasu. W sumie symulacja pokazuje, że jeden cykl trwa 1000,2ms.

    Jedynie co nie nastąpi to przepełnienie TOVF1, gdyż licznik w CTC liczy od BOTTOM do TOP, a nie od BOTTOM to MAX.
    Gdzie: BOTTOM - wartość zero, TOP - wartość skracająca cykl licznika, MAX - wartość jaką może maksymalnie osiągnąć licznik.

    Lysoleq napisał:
    Faktycznie, licznik działa. Wsadziłem układ na oscyloskop i wszystko PB5 zmieniał stan z wysokiego <> niski

    Zatem jak przypuszczałem błędu trzeba szukać gdzie indziej. Może kolega pokaże większy kawałek kodu.
  • #13 5315301
    Lysoleq
    Poziom 17  
    
    .CSEG
    .ORG	0x000	
    		RJMP	RESET
    .ORG	0x018	
    		RJMP	TEST
    
    RESET:
    ldi		r16,HIGH(RAMEND)		
    out		SPH,r16
    ldi 		r16,LOW(RAMEND)
    out		SPL,r16
    
    rcall		KONFIGURACJA_PINOW	;Konfiguracja wyprowadzen mikrokontrtolera
    rcall		KONFIGURACJA_TIMER1	;Konfiguracja ustawien zegara
    rcall                  MAIN
    Main:
    sei
    rjmp	Main
    
    KONFIGURACJA_PINOW:
    Tu jest nic nie wnoszące ustawianie pinow, typu:
    cbi		O_LED,LED_RED_P ;zapal czerwona 		
    cbi		O_LED,LED_GRN_P ;zaapal zielona
    zadnych dodatkowych instrukcji.
    ret
    
    KONFIGURACJA_TIMER1:
    push	r16
    in		r16,SREG
    push	r16
    
    ldi     r16, high(62500) 
    out     OCR1AH, r16 
    ldi     r16, low(62500)     ;ustaw przerwanie po czasie 1s 
    out     OCR1AL, r16         ;dla częstotliwości 16MHz 
    
    clr		r16
    
    ldi     r16, (1<<CS12)|(0<<CS11)|(0<<CS10)|(1<<WGM12)    
    out     TCCR1B, r16        ;ustaw tryb pracy licznika na CTC 
                            	;ustaw prescaler licznika na 256 
                            	;uruchom licznik
    
    clr		r16
    ldi     r16, (1<<OCIE1A)
    out     TIMSK, r16         ;ustaw przerwanie porownania licznika 
    
    pop		r16
    out		SREG,r16
    pop		r16
    ret
    
    
    TEST:
    sbi		O_LED,LED_RED_P		
    sbi		O_LED,LED_GRN_P
    reti
    


    Funkcja TEST nigdy nie jest wywolywana i nie mam pojecia czemu:/ Na chwilę obecną to całość kodu.
  • #14 5315306
    ZbeeGin
    Poziom 39  
    A teraz powiedz, gdzie ustawiasz tryb pracy końcówek do których zostały podłączone diody? Skąd procesor wie czy to wejścia czy wyjścia...?

    Dodano po 6 [minuty]:

    No teraz to już namieszłeś w tym kodzie niezemsko. Po co te rcall Main i clr r16.
  • #15 5315331
    Lysoleq
    Poziom 17  
    W części KONFIGURACJA_PINOW, której tu nie wkleiłem. Jeżeli to bardzo istotne to mogę ją podać. Nie zrobiłem tego tylko dlatego aby oszczędzić czytającym 100 kilka linii definicji stałych, a następnie konfiguracji czy dane wyprowadzenie to wejście/wyjście i jeżeli wyjście to w jakim stanie.

    RCALL MAIN dodaje to gdyż kiedyś jedna instrukcja RET wróciła mi aż do RESETu. W ten sposób mam na stosie odłożony adres funkcji MAIN i do niej zawsze wrócę. Gdyby tego nie było i nastąpiło przerwanie 0x0018 skoczyłbym do funkcji test poleceniem RJMP TEST. Zakończona jest poleceniem RET które gdyby nie RCALL MAIN wróciło by do RESETU.
  • REKLAMA
  • #16 5315369
    ZbeeGin
    Poziom 39  
    Lysoleq napisał:
    RCALL MAIN dodaje to gdyż kiedyś jedna instrukcja RET wróciła mi aż do RESETu.

    Jak się nie dba o poprawne odkładanie i zdejmowanie ze stosu to tak właśnie bywa.
  • #17 5315383
    Lysoleq
    Poziom 17  
    Zgadza się, dlatego teraz przykładam więcej uwagi do stosu. W każym razie nie sądze aby Rcall Main miało jakiś wpływ na to czy przerwanie występuje czy nie. Są lepsze rozwiązania od rcall Main?
  • #19 5315425
    ZbeeGin
    Poziom 39  
    Lysoleq, wklej ten cały kod jako załącznik. Bo w ten sposób to nigdy tego problemu się nie rozwiąże, jak będziesz za każdym razem pokazywał jakieś tam fragmenty.
  • Pomocny post
    #21 5315530
    ZbeeGin
    Poziom 39  
    Nie widzę problemów przy symulacji w AVR Studio (4.14) Twojego programu. Sprzętowo nie mam jak sprawdzić gdyż nie posiadam obecnie żadnego ATMega128/64.
  • #22 5315676
    Lysoleq
    Poziom 17  
    W AVR studio u mnie też to ladnie działa. A w układzie rzeczywistym jest zupełnie inaczej :/. Z tego co zaobserwowałem wygląda na to że moja ATMEGA nie powraca z części KONFIGURACJA_PINOW, ale nie wiem czemu.
  • #24 5316113
    Lysoleq
    Poziom 17  
    Dalej nic. Po skoku do konfiguracji pinów układ gdzieś grzęźnie i nie wiem co jest tego przyczyną. Próbowałem już rjmp, jmp w wektorach przerwań i rcall i call w funkcji reset. Wszystko idzie jak po maśle do napotkania instrukcji RET. Gdy ją usuwam na końcu konfiguracji pinów układ przechodzi do następnej instrukcji i wykonuje ją, do momentu napotkania koleinej instrukcji RET i się gubi.

    Problem funkcji RET rozwiązany. Nie przestawiłem FuseByte odpowiedzialnego za zgodność ATmegi128 z Atmega103. Wszystko działa! :) Dziękuje wszystkim udzielającym się w temacie za pomoc.
REKLAMA