C18 Расчет времени Timer0 с использованием MCC18

Я программирую PIC18F4520 и настроил его на использование внутренних часов 32 МГц.

Мне нужен счетчик, чтобы тикать каждую секунду, поэтому я использую TMR0для этой цели.

Для использования TMR0я установил следующее:

  • Предделитель 1:256
  • 16-битный режим
  • Прерывание высокого уровня при TMR0переполнении.

Чтобы настроить таймер на отсчет каждую секунду, я рассчитал его следующим образом:

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

Итак, TMR0 = 0xFFFF - 31250.

Это верно? Если нет, то что мне не хватает? Код выглядит следующим образом:

#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();
}

В моем векторе прерывания высокого уровня я сделал это:

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

Итак, в основном, каждые 2 минуты я хочу, чтобы метод measure_and_switch()выполнялся. Должен ли я следовать за ним WriteTimer0()?

Кстати: CLOCK_TICKесть TMR0(расчет сверху).

Спасибо

Можете ли вы рассказать нам, что происходит сейчас? Я не вижу этого из самого вопроса.
Мой таймер сбился с курса (такты часов не были «синхронизированы»). Я решил это. Спасибо. :-)
Не забудьте опубликовать решение как ответ и принять его через два дня!
Сладкий, пойдет.

Ответы (1)

Ответ прост. Когда происходит бит переполнения и возникает прерывание, нам нужно сначала записать счетчик TMR0и сбросить TMR0IFфлаг.

Это решение работает:

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

Надеюсь, это кому-нибудь поможет. :-)

Вы также должны проверить TMR0IE перед входом в функцию, поскольку она может быть установлена, даже если вы сбросили бит TMR0IE.