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.

PIC16F873 i timer - problem z czasami

dudi_elektr 25 Sie 2009 16:31 1097 5
  • #1 25 Sie 2009 16:31
    dudi_elektr
    Poziom 13  

    Cześć

    Taki problem napotkałem. Obliczenia czasu generowanego przez timer są trywialnie proste. Z wyliczeń jednak wychodzi mi jednak wartość zupełnie inna niż z pomiarów po zaprogramowaniu.

    Program wygląda tak

    Code:

    #include <16F873A.h>
    #include <definicje.h>
    #fuses HS,NOWDT,NOPROTECT,NOBROWNOUT,NOLVP
    #use delay(clock=20000000)

    #define LED4 4

    int w = 0;

    void main()
    {
       PORTA = 0;
       PORTB = 0;
       PORTC = 0;

       TRISA = 0xff;
       TRISB = 0;
       TRISC = 0;

       //konfiguracja timer1
       INTCON = 0xc0;         //1100 0000
       PIR1 |= (1 << TMR1IF);
       PIE1 |= (1 << TMR1IE);
       TMR1L = 0;
       TMR1H = 0;
       T1CON = 0x30;         //0011 0000
       
       T1CON |= (1 << TMR1ON);
       for(;;)
       {
          
       }
    }

    #INT_TIMER1
    void isr_timer1()
    {
       TMR1L = 0;
       TMR1H = 0;
       ++w;
       
       if(w > 4)
       {
          w = 0;
          PORTC ^= (1 << LED4);
       }

       INTCON = (1 << GIE)|(1 << PEIE);
    }


    Po 4 przerwaniach dioda ma zmienić swój stan na przeciwny (tzn. zgasnąć jeżeli świeciła lub na odwrót).

    Przy TMR1L = 0, TMR1H = 0, PRESCALER 1:8 i oczekiwaniu na 4 przerwania dostaję ok. 0,56 sekundy. Z obliczeń wynika że powinno być oczekiwanie na 9,6 przerwania czyli 10 żeby była sekunda. Gdzie robię błąd?

    0 5
  • #2 25 Sie 2009 18:45
    mkaczor
    Poziom 15  

    Code:
    #INT_TIMER1
    
    void isr_timer1()
    {
       TMR1L = 0;
       TMR1H = 0;
       ++w;
       
       if(w > 4)
       {
          w = 0;
          PORTC ^= (1 << LED4);
       }

       INTCON = (1 << GIE)|(1 << PEIE);
    }


    Wywolanie kodu wewnatrz if(w > 4) odbywa sie co piate wejscie w przerwanie.
    Wywolanie przerwania nastepuje wtedy gdy TMR1L == 0 i TMR1H == 0, a wewnatrz przerwania licznik TMR1L juz ma wartosc wieksza od 0. Zerowanie licznika jest wiec zbedne i jedynie nieznacznie opoznia kolejne wyzwolenie przerwania.

    0
  • #3 25 Sie 2009 20:24
    dudi_elektr
    Poziom 13  

    no ok, masz rację, co 5, ale nie zmienia to faktu że 5 < 9,6. Co do wartości TMR1L, nie ma się co martwić, bo jego wartość nieco większa od 0 nie zmieni w znaczący sposób długości trwania całego impulsu.

    0
  • #4 26 Sie 2009 14:47
    damiano713
    Poziom 14  

    Cytat:
    #use delay(clock=20000000)

    Jeżeli masz kwarc 20MHz to wewnętrzny sygnał zegarowy jest 20/4 czyli 5MHz.

    Pozdrawiam

    0
  • #5 26 Sie 2009 18:28
    CDMaster
    Poziom 14  

    Kilka uwag:
    1. Nie widzę tutaj czyszczenia flagi TMR1F. Wręcz nie wiem czemu ją na początku ustawiasz:

    Code:
    PIR1 |= (1 << TMR1IF); 

    2. 5MHz / 2^16 jest jak nic 76, czyli ten licznik zostanie przekręcony 76 razy wciągu sekundy...
    3. Po co ustawiasz
    Code:
    TMR1L = 0;
    
    TMR1H = 0;

    skoro po wystąpieniu przerwania posiadają takie właśnie wartości??:D
    Pozdrawiam

    0
  • #6 26 Sie 2009 21:19
    dudi_elektr
    Poziom 13  

    Tak, wiem, że przy zegarze 20MHz to wewnętrzny sygnał jest 5MHz ale nie to stanowi istotę problemu. Mimo wszystko dziękuję za głos.

    CDMaster
    ad. 1. Rzeczywiście nie mam czyszczenia flagi, ale o dziwo to działa. I przyznaję, mój błąd, ustawianie nie ma sensu. :-] (wstyd)

    ad. 2. Jest jeszcze prescaler 1:8


    Problem rozwiązałem. Kolega w pracy podpowiedział. Wymieniłem zegar na 4MHz i obliczenia się zgadzają z rzeczywistością. Widać było coś nie tak z tamtym draniem. Mimo, że na obudowie było napisane 20MHz to zachowywał się jakby było dużo mniej.

    0