Timer0 en PIC18F26J50

0

Tengo un PIC18F26J50 y quiero que el timer0 emita una señal de 1Hz en RA6. Ahora estoy recibiendo ~ 800Hz con mi configuración actual. El reloj es 48MHz / 4 = 12MHz en RA6 (si INTOSCPLLO está habilitado). El compilador es C18.

Aquí está mi código, que obviamente es incorrecto y necesito averiguar cuál es el problema y entender cómo funciona esto.

BYTE Timer0Init( WORD wTimeInterval )
{
UINT16 timerRegValue;
INT8 rc = ERROR_INVALID_COMMAND;

const UINT16 timerPeriodInSeconds = 1;
const UINT32 clockFreq = GetSystemClock();
const UINT16 prescalerValue = (256);
const UINT16 resolution = 65536;   

interruptsDisableAll();

//! configure the timer 0 for 16 bit mode and preescaler of 256
T0CONbits.TMR0ON    = TMR0ON_OFF;           //! turn off
T0CONbits.T08BIT    = T08BIT_LEN_16;        //! select the 16 bit mode
T0CONbits.T0CS      = T0CS_INT;             //! internal clock 
T0CONbits.T0SE      = 0;                    
T0CONbits.PSA       = PSA_PREESC_ASSIGN;    //! use the prescaler    
T0CONbits.T0PS      = T0PS_PREESC_1_256;    //! 1/? prescaler

timerRegValue = ( clockFreq * timerPeriodInSeconds );
timerRegValue = (UINT16)( timerRegValue/(4*prescalerValue) );
timerRegValue = resolution - timerRegValue;

reloadValue_ = timerRegValue;

writeTMR0Register( timerRegValue );

INTCONbits.TMR0IF   = 0;                 //! clear the interrupt flag
INTCONbits.TMR0IE   = 1;    

T0CONbits.TMR0ON = TMR0ON_ON;            //! turn on

interruptsEnableAll();

rc = ERROR_SUCCESS;

return rc;
}

Obtuve estos cálculos de una fórmula que encontré en Internet. Leí y releí la hoja de datos y los cálculos parecen estar bien. Entonces, ¿cuál es el problema de todos modos?

Cualquier ayuda es realmente apreciada!

Gracias.

    
pregunta daniel.franzini

1 respuesta

0

Suponiendo que tmr0 de 16 bits, el desplazamiento se debe establecer de esta manera

Tmr0 = - (fxtal / 4 / prescaler)

Al menos uno de ellos debe ser del tipo 32.

Para 8bit tmr0, tiene que hacerse sobre múltiples llamadas de Isr. El truco es cargar solo el contador una vez.

editar: aquí hay una de las muchas formas de hacer el truco mencionado anteriormente.

//tmr0 isr handle
void my_isr(void) {
    if (tmr0_cnt) {                         //not running out yet
        tmr0_cnt -= 0x100;                  //update tmr0
    } else {
        TMR0 = -TMR_PR;                     //load the TMR0 counter with the initial offset
        tmr0_cnt = TMR_PR &~0xfful;         //initialize the counter - lsb already handled
        IO_FLP(LED_PORT, LED);              //flip the pin
    }
}

la sección anterior se instalará como isr.

para cualquier período de tiempo dado (TMR_PR), escribe al contador timer0 solo una vez, cuando se inicializa al comienzo del período de tiempo del temporizador, independientemente de la duración del período de tiempo, en este caso, TMR_PR es un 32 tipo -bit.

después de eso, tmr0_cnt se actualiza hasta que la duración del tiempo se agote.

el error de sincronización (al cargar TMR0) depende de los chips utilizados / frecuencia en que se ejecuta y del modo compilador. alrededor de 20 - 30 garrapatas sin optimizar.

Aquí está el código en el espacio de usuario:

tmr0_init(TMR0_PS_1x);                  //reset tmr0 to 1x prescaler, 8-bit
//tmr0_cnt = 0;                         //reset tmr0
tmr0_act(my_isr);                       //install user isr
ei();

y aquí está la simulación:

TMR_PR se establece en F_CPU / 10, o 10 vueltas por segundo, como lo confirma la simulación.

El código se puede portar básicamente a cualquier mcu.

    
respondido por el dannyf

Lea otras preguntas en las etiquetas