Elektroda.pl
Elektroda.pl
X
Proszę, dodaj wyjątek www.elektroda.pl do Adblock.
Dzięki temu, że oglądasz reklamy, wspierasz portal i użytkowników.

[ATtiny12] [Asembler] Timer/Licznik

krystii 21 Cze 2009 18:08 2088 10
  • #1 21 Cze 2009 18:08
    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:

    Code:

    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

    0 10
  • #2 22 Cze 2009 19:58
    krystii
    Poziom 16  

    Nikt nie jest w stanie mi pomóc? Bądź dać jakichś namiarów jak mam to wykonać?

    0
  • #3 22 Cze 2009 20:31
    ZbeeGin
    Poziom 38  

    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.

    0
  • #4 22 Cze 2009 21:00
    krystii
    Poziom 16  

    Do TCNT0 ładuje 0. Na początku programu mam:

    Code:

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

    0
  • #5 22 Cze 2009 21:07
    ZbeeGin
    Poziom 38  

    Sprawdza czy upłynęła podana liczba mikrosekund.

    0
  • #6 22 Cze 2009 23:10
    krystii
    Poziom 16  

    Co robie źle? Przykład na diodzie migającej podłączonej do PB3

    Code:

    ;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

    0
  • #7 22 Cze 2009 23:24
    ZbeeGin
    Poziom 38  

    Pierwsze z brzegu: Gdzie masz stos?

    0
  • #8 23 Cze 2009 19:59
    krystii
    Poziom 16  

    Chyba sobie w tym temacie nie poradzę. A co ze stosem nie tak?

    0
  • #9 23 Cze 2009 20:13
    ZbeeGin
    Poziom 38  

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

    0
  • #10 23 Cze 2009 20:38
    krystii
    Poziom 16  

    To co w takim razie robie źle z tym timer'em?

    0
  • #11 24 Cze 2009 17:44
    krystii
    Poziom 16  

    Poradziłem sobie już w inny sposób. Dodałem pętle w odpowiednim miejscu:

    Code:

    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

    0