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

Obliczanie przerwania w uC PIC

28 Sie 2006 01:35 1351 7
  • Poziom 23  
    Witam

    Od niedawna programuję w asm dla PIC w środowisku MPLAB. Opanowałem już jak się wywołuje przerwania za pomocą przepełnienia licznika, lecz mam mały problem z rejestrem TMR0. Proszę, aby ktoś wytłumaczył mi jak się go używa i jak obliczyć częstotliwość, z którą wywoływane jest przerwanie.

    Może lepiej zilustruje mój problem to:
    Przyjmując, że osc = 4Mhz a PSA = 1 czyli częstotliwość, z jaka jest zliczany TMR0 to 1MHz.
    Nie zmieniając nic w rejestrze TMR0 zlicza on od 0 do 256 czyli jego szerokość to 256

    1000000 / 256 = 3906,25 Hz i to się zgadza w praktyce.
    Ja natomiast chce np. aby ta częstotliwość wynosiła 50kHz.
    1000000 / 20 = 50000 Hz czyli do rejestru wpisuje 256 – 20 = 236
    W praktyce otrzymuje częstotliwość 16,25kHz

    Gdzie robię błąd?
  • Multimetr FlukeMultimetr Fluke
  • Poziom 22  
    Napisz jaki to jest dokładnie procesor (co prawda dużej różnicy to tu nie robi, ale będzie jaśniej).
    Rzeczywiście, wydaje się, że wszystko powinno się zgadzać tak jak napisałes.
    A jak mierzysz tą częstotliwość z tak dużą dokładnością, że jesteś pewien, że wynosi akurat tyle?
  • Multimetr FlukeMultimetr Fluke
  • Poziom 23  
    Procesor to PIC16F870. Częstotliwość mierzę w następujący sposób. W czasie trwania głównego programu na pinie RC0 ustawiam 0 a gdy zostanie wywołane przerwanie na jego początku na tym samym pinie ustawiam 1. Częstotliwość mierzę moim multimetrem cyfrowym. Pomiar jest poprawny tylko i wyłączcie, gdy nie dotykam rejestru TMR0 stad ten post.
  • Poziom 22  
    Ja też mam funkcję mierzenia częstotliwości w moim multimetrze, ale tylko do 20kHz. Upewnij się, że multimetr "daje rade" z taką częstotliwością.
  • Poziom 23  
    Multimetr ma zakres od 1Hz do 10MHz, przy czym jest bardzo dokładny.
  • Pomocny post
    Poziom 12  
    hmm, przerwania co 20 instrukcji procesora ;-)

    Wydaje mi się, że nie uwzględniasz czasu pomiędzy wywołaniem przerwania a ustawieniem timera.

    Dla przykładu
    Code:

    ; INTERRUPT
          ORG   0x004      ; interrupt vector location
          btfsc   INTCON,T0IF   ; TMR0 overflow
          goto   serv_t0
          retfie         ; return from interrupt
    serv_t0
          bsf   PORTC,0

          movlw   .256 - (.20 - X)
          movwf   TMR0

          bcf   INTCON,T0IF   ; clear int flag
          retfie         ; return from interrupt

    main
          bcf   PORTC,0
          goto   $-1


    gdzie X =
    3 instrukcje (interrupt latency)
    +6 instrukcji (test przerwania + ustawienie portu + ustawienie timera)

    ponieważ nie używasz prescalera, (1 instrukcja = 1 inkrementacja timera)
    to X = 9
    czyli powinieneś wpisywać nie .256 - .20 tylko .256 - .11
    (i masz 11 instrukcji żeby wyjść z przerwania)

    Jesli masz program troszkę bardziej rozbudowany np:
    Code:

    ; INTERRUPT
          ORG   0x004      ; interrupt vector location
          movwf   irq_w      ; save W reg
          movf   STATUS,w   ; save STATUS
          clrf   STATUS      ; set bank0; IRP,RP1,RP0 = 0
          movwf   irq_status
          movf   PCLATH,w   ; save PCLATH
          movwf   irq_pclath
          clrf   PCLATH      ; set page 0
          movf   temp,W
          movwf   irq_temp

          btfsc   INTCON,INTF   ; RB0/INT (wake)
          goto   serv_int

          btfsc   PIR1,TMR1IF   ; TMR1 overflow
          goto   serv_t1

          btfsc   INTCON,T0IF   ; TMR0 overflow
          goto   serv_t0

          btfsc   INTCON,RBIF   ; RB port change (wake)
          goto   serv_rb

          btfsc   PIR1,TMR2IF   ; TMR2 overflow
          goto   serv_t2

    i_ret
          movf   irq_temp,W
          movwf   temp
          movf   irq_pclath,w   ; restore PCLATH
          movwf   PCLATH
          movf   irq_status,w   ; restore STATUS
          movwf   STATUS
          swapf   irq_w,f      ; restore W
          swapf   irq_w,w
          retfie         ; return from interrupt

    serv_t0
          bsf   PORTC,0

          movlw   .256 - (.20 - X)
          movwf   TMR0

          bcf   INTCON,T0IF   ; clear int flag
          goto   i_ret

    to masz problem ;-)

    bo X =
    3 instrukcje (interrupt latency)
    +9 ins (push)
    +7 ins (spr. przerwan - wejscie do obsługi tmr0)
    +3 ins (ustawienie portu i timera)

    = 22
    co jest większe od 20, (nie licząc 13 instrukcji potrzebnych do wyjścia z przerwania) czyli nie wyrobimy się z obsługą - trzeba zastosować prescaler

    Mam nadzieję, że nie nakłamałem za bardzo,

    pozdrawiam
  • Poziom 23  
    Dziękuje za odpowiedzi. Zastosowałem się do porady kolegi _paput_ i pomogło :)
    Pozdrawiam.