C18 Timer0 Timing-Berechnung mit MCC18

Ich programmiere einen PIC18F4520 und habe ihn so eingestellt, dass er eine interne 32-MHz-Uhr verwendet.

Ich brauche einen Zähler, der jede Sekunde tickt, also verwende ich ihn TMR0für diesen Zweck.

Zur Verwendung TMR0habe ich folgendes eingestellt:

  • Vorteiler 1:256
  • 16-Bit-Modus
  • High-Level-Interrupt bei TMR0Überlauf.

Um den Timer so einzustellen, dass er alle 1 Sekunde zählt, habe ich ihn wie folgt berechnet:

TMR0 = (Required time)/(4 * Timer clock * prescale value)
     = 1 / (4  * (1/32000000) * 256)
     = 31250

Also, TMR0 = 0xFFFF - 31250.

Ist das richtig? Wenn nicht, was übersehe ich? Der Code lautet wie folgt:

#pragma code
void main(void)
{
    //Set clock frequency
    OSCCON |= 0x70;             //8 Mhz clock, primary clock
    OSCTUNEbits.PLLEN = 1;          //4x Multiplier, thus we have 32 Mhz clock
    while (!OSCCONbits.IOFS);       //Wait until INTOSC is stable.

    //Enable TRISA as analog input (For ADC)
    TRISA = 0x2F;

    //PIN Outputs
    TRISB = 0;              //Make PORTD as output
    //Reset PORTB
    PORTB = 0;

    //Set ADC
    OpenADC(ADC_FOSC_32 &           //Fosc/32
         ADC_RIGHT_JUST &
         ADC_4_TAD,             //4xTAD
         ADC_CH0 &
         ADC_REF_VDD_VSS &
         ADC_INT_OFF, ADC_5ANA);        //ADC CH0-CH4 Initialized

    //Set Timer0
    OpenTimer0( TIMER_INT_ON &
                T0_16BIT &
                T0_SOURCE_INT &
                T0_PS_1_256);

    //Write Timer
    WriteTimer0(CLOCK_TICK);

    INTCON2bits.TMR0IP = 1;         //TMR0 has high overflow interrupt priority
    RCONbits.IPEN = 1;                  //enable priority levels
    INTCONbits.GIEH = 1;            //enable high interrupts

    //Begin
    while (TRUE)
    {

    }

    CloseADC();             //Closing ADC
    CloseTimer0();
}

Auf meinem Interrupt-Vektor auf hoher Ebene habe ich Folgendes getan:

#pragma code 
#pragma interrupt high_priority_interrupt 
void high_priority_interrupt()
{
    if (INTCONbits.TMR0IF)                  //TIMER0 overflowed
    {
        //Stuff
        second += 1;
        if (second == 60)
        {
            minute += 1;
            second = 0;
        }

        if (minute == 60)
        {
            measure_and_switch();
            WriteTimer0(CLOCK_TICK);
            minute = 0;
        }

        INTCONbits.TMR0IF = 0;              //Clear TIMER0 overflow bit.
    }
}

Im Grunde möchte ich also, dass die Methode alle 2 Minuten measure_and_switch()ausgeführt wird. Soll ich ihm folgen WriteTimer0()?

Übrigens: CLOCK_TICKist TMR0(Rechnung von oben).

Danke

Können Sie uns sagen, was jetzt passiert? Das kann ich aus der Frage selbst nicht entnehmen.
Mein Timer war vom Kurs abgekommen (Uhr tickt war nicht "synchronisiert"). Ich habe es gelöst. Danke. :-)
Vergiss nicht, die Lösung als Antwort zu posten und akzeptiere sie nach zwei Tagen!
Süß, geht.

Antworten (1)

Die Antwort ist einfach. Wenn das Überlaufbit auftritt und der Interrupt ausgelöst wird, müssen wir zuerst den Zähler schreiben TMR0und das TMR0IFFlag zurücksetzen.

Diese Lösung funktioniert:

#pragma code 
#pragma interrupt high_priority_interrupt 
void high_priority_interrupt()
{
    if (INTCONbits.TMR0IF)              //TIMER0 overflowed
    {
        //Stuff
        second += 1;
        if (second == 60)
        {
            minute += 1;
            second = 0;
        }

        if (minute == 60)
        {
            measure_and_switch();
            minute = 0;
        }

        WriteTimer0(CLOCK_TICK);        //Write the count to TMR0.
        INTCONbits.TMR0IF = 0;          //Clear TIMER0 overflow bit.
    }
}

Ich hoffe, das hilft jemandem. :-)

Sie sollten auch nach TMR0IE suchen, bevor Sie die Funktion aufrufen, da sie möglicherweise gesetzt ist, selbst wenn Sie das TMR0IE-Bit gelöscht haben.