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

[ATtiny12] [Asembler] Timer/Licznik

krystii 21 Cze 2009 18:08 2406 10
REKLAMA
  • #1 6684931
    krystii
    Poziom 16  
    Witam.

    Chcę aby program sprawdzał PORTB pin2 dwa razy w odstępie ok.1s. Mianowicie gdy na PB2 pojawi się stan niski uruchomić ma się timer i przez ok. sekunde będzie sprawdzał PB2 i jeżeli w tym czasie pojawi się stan niski program wraca do LOOP. Jeżeli po odmierzeniu owej sekundy nie pojawi się stan niski na PB2 to program ma odmierzyć czas ok. 1s. i w tym czasie ma czekać na pojawienie się stanu niskiego na PB2 i jeżeli się pojawi program ma skoczyć to podprogramu PODPROGRAM, a jeżeli się nie pojawi w tym czasie stan niski na PB2 to program wraca do LOOP. Myślę, że się jasno wyraziłem. Dopiero zaczynam programować w Asemblerze, i jak narazie nie wiem jak obchodzić się timer'ami. uC jest taktowany wewnętrznym zegarem 1,2MHz (1200000MHz).

    Oryginalny opis działania funkcji: ""Jeśli powodem wybudzenia procesora z trybu idle było przepełnienie licznika timera, to nastepuje sprawdzenie stanu klawisza. Jeśli jest on nacisnięty, to program po chwili sprawdza go ponownie, aby wyeliminować ewentualne zakłócenia mogące spowodowac fałszywą zmianę stanu układu. Po upewnieniu się, że klawisz jest dalej nacisnięty wykonywany jest PODPROGRAM" i według tego opisu działa poniższy kod.

    Oto oryginał kodu:
    
    KEYTEST:sbic	PINB,PB2		; test for keypress
    	rjmp	SDOWN			; not pressed
    	out	TCNT0,r1
    	ldi	r16,2			; start timer, CK/8
    	out	TCCR0,r16		; for key debouncing
    	sleep				; wait for interrupt
    	nop
    	sbic	PINB,PB2		; second key test
    	rjmp	LOOP			; not pressed
    	rjmp	PODPROGRAM
    
  • REKLAMA
  • #2 6689754
    krystii
    Poziom 16  
    Nikt nie jest w stanie mi pomóc? Bądź dać jakichś namiarów jak mam to wykonać?
  • #3 6689952
    ZbeeGin
    Poziom 39  
    Rozpatrz opis działania polecenia SLEEP:
    Cytat:
    "Rozkaz ten wprowadza procesor w jeden z trybów obniżonego poboru energii, określony przez nastawę specjalnego rejestru. Układ może wyjść ze stanu uśpienia tylko w skutek wystąpnienia przerwania lub zdarzenia zerowania. Jeśli do wybudzenia procesora wykorzystane mają być przerwania, należy pamiętać by wcześniej je uaktywnić (ustawić flagę I w rejestrze SREG)"

    Nie pokazujesz jaką wartość ładujesz do TCNT0. Nawet jak wpisałbyś tam zero i licznik sie przekręcił to uzyskasz czas tylko(!) 1,7ms. Z preskalerem CK/1024 też nie uzyskasz potrzebnych 1s, a tylko marne 0,218s. Dlatego nie tędy droga.

    Trzeba by tak wyliczyć i ustawić TIMER0 by zwiększał się co 0,1s (Przepis: 139 do licznika, CK/1024) i w przerwaniu dodać licznik programowy (zmienną), która doliczając do 10 (lub odliczając od 10 do zera) spowoduje ustawienie flagi (np. T w SREG), na którą to grzecznie program poczeka aż zostanie ustawiona. Po tym można flagę skasować, licznik zatrzymać i przejść do następnych zadań.
    Problem polega na tym, że 1,2MHz nie jest zbyt elastyczne i nie będzie to dokładnie 1s.
  • REKLAMA
  • #4 6690111
    krystii
    Poziom 16  
    Do TCNT0 ładuje 0. Na początku programu mam:
    
    .MACRO TTEST
    in	 r22,TCNT0			; get timer value			
    cpi	 r22,(CLK/64 * @0 / 1000000)	; test timer value depend on CLK and 
    					; parameter value in microseconds
    .ENDMACRO

    Co owe makro robi?
  • REKLAMA
  • #6 6690887
    krystii
    Poziom 16  
    Co robie źle? Przykład na diodzie migającej podłączonej do PB3
    
    ;DEVICE ATtiny12 @ Internal 1.2MHz RC oscillator
    
    ;FUSES:		(Internal RC oscillator)
    ;BODLEVEL	0 (set)
    ;BODEN		0
    ;SPIEN		0
    ;RSTDISBL	1 (clear)
    ;CKSEL3		0
    ;CKSEL2		0
    ;CKSEL1		1
    ;CKSEL0		1
    
    .Nolist
    .Include "tn12def.inc"
    .List
    
    .equ	CLK	= 1200000		; 1,2MHz clock
    .def	zero_reg = r1
    .def	tmp	 = r16			; temp register
    .def	timer	 = r25			; Counter for power-down timer input
    .def	icnt	 = r24			; Flag for time check
    
    ;==============================================================================
    
    ;RESET AND INTERRUPT VECTORS
    .org 0
    ;wyłączenie przerwań
    
    cli
    
    	sbi DDRB, PB3
    	sbi	ACSR,ACD		; disable analog comparator
    	ldi	tmp,(1<<ISC00 | 1<<SE)	; external interrupt reaction
    	out	MCUCR,tmp		; for any logic change
    	ldi	tmp,(1<<INT0)		; enable external interrupt
    	out	GIMSK,tmp
    	ser	timer
    	ldi tmp,0
    	out	TCNT0,tmp		; Main loop
    	clr	zero_reg
    
     
    petla:
    
    	sbi PORTB, 3	;włącz diode
    		ldi timer,0
    	rcall Czekaj1s	;odczekaj 1sek
    
    	cbi PORTB, 3;	;wylacz diode
    		ldi timer,0
    	rcall Czekaj1s	;odczekaj 1sek
    	rjmp petla
    
    Czekaj1s:
    	wdr				; watchdog reset
    	out	TCNT0,zero_reg		;ładuj do licznika 0
    	ldi	tmp,(1<<TOIE0)
    	out	TIMSK,tmp		; enable timer interrupt
    	ldi	tmp,5
    	out	TCCR0,tmp		; start timer, CK/1024
    	sleep				; enter IDLE mode
    	nop
    	wdr
    	inc timer
    	cpi	timer,10			; Is timer interrupt ?
    	brsh	Czekaj1s			; No - Exit
    	set			; Mark interrupt flag
    	ret
    
  • #8 6694101
    krystii
    Poziom 16  
    Chyba sobie w tym temacie nie poradzę. A co ze stosem nie tak?
  • #9 6694169
    ZbeeGin
    Poziom 39  
    Jakoś mi się cyferki poprzestawiały i przeczytałem, że używasz Tiny13, a przecież używasz Tiny12 :( Tam jest stos sprzętowy. Nie było pytania...
  • REKLAMA
  • #10 6694304
    krystii
    Poziom 16  
    To co w takim razie robie źle z tym timer'em?
  • #11 6697854
    krystii
    Poziom 16  
    Poradziłem sobie już w inny sposób. Dodałem pętle w odpowiednim miejscu:

    
    Czekaj1s:
     ldi R27, 0
    Czekaj250ms:
     ldi R28, 0
     czekaj250ms_0:
      ldi R26, 0
      czekaj250ms_1:
       inc R26
       cpi R26, 250
       brlo czekaj250ms_1
      inc R28
      cpi R28, 249
      brlo czekaj250ms_0
      inc R27
      cpi R27, 4
      brlo Czekaj250ms
     ret
    
REKLAMA