PIC16F628A: 500 ms de retardo (con temporizador 1) no como se esperaba

1

TL; DR: Vea las últimas líneas (y la cita) en la parte inferior.

Solo una palabra sobre mi experiencia: aprendí los microcontroladores el último semestre con el 8051 y he estado aprendiendo los microcontroladores PIC durante el verano. He pasado la mayor parte de mi verano trabajando con el PIC12F683, y apenas estoy empezando a aprender el PIC16F628A. Todo esto es para decir que no soy totalmente nuevo para los microcontroladores o PIC.

Como acabo de comenzar en el 16F628A, decidí comenzar por parpadear un LED. (Estoy usando un PICkit 3 y MPLAB X IDE v3.00 en Linux Mint 17.) Para hacerlo, quería usar el temporizador 1 para crear un retraso de 500 ms. El retraso está sustancialmente fuera de 500 ms, y quiero entender por qué.

Dado que no hay una función de recarga automática (como en el 8051), mi idea fue usar un precalculador 1: 8. Luego, cada vez que el temporizador 1 se desborda, inicialícelo en 0x0BDB. Ese valor crea un intervalo de 0xFFFF - 0x0BDB = 0xF424 antes del desbordamiento (o 62,500, en decimal).

Ya que estoy usando el reloj interno (4 MHz) y el Temporizador se incrementa como FOSC / 4, y estoy usando un preescalador de 1: 8, el período de demora debería ser:

1 / (4 MHz / 4 / 8 / 62,500) = 0.5 sec

Mi LED está parpadeando, pero el retraso no es de 0.5 segundos. Usé mi multímetro para medir la frecuencia, y el resultado se resuelve en un período de aproximadamente 0.417 seg. Además, esto funciona aproximadamente a 144bpm, y cuando configuro un metrónomo a 144bpm, coincide con el LED parpadeante.

Las únicas cosas conectadas a mi placa son Vss (pin 5), Vdd (pin 14), un LED (con una resistencia limitadora de corriente de 10 kΩ) en el pin 6 (RB0) y una resistencia de 47 kΩ entre MCLR y Vdd ( pines 4 y 14). (... y mi PICkit.)

Aquí está mi código:

#include <xc.h>

#pragma config FOSC = INTOSCIO  //oscillator selection; use internal oscillator
#pragma config WDTE = OFF       //disable watchdog Timer
#pragma config PWRTE = OFF      //power-up timer disabled
#pragma config MCLRE = OFF      //use MCLR pin (internally tied to Vdd) as a digital input
#pragma config BOREN = OFF      //disable Brown-Out Reset
#pragma config LVP = OFF        //disable Low-Voltage Programming
#pragma config CPD = OFF        //data code protection disabled
#pragma config CP = OFF         //code protection disabled

bit LEDstatus;

void main(void)
{
    LEDstatus=1;            //initialize LED off (active-low)
    TRISB0=0;               //use RB0 as digital output

    T1CON=0b00110000;       //Timer 1 off; 1:8 prescaler; use internal clock

    TMR1H=0x0B;             //initialize Timer 1 to get a 500ms delay
    TMR1L=0xDB;

    INTCONbits.PEIE=1;      //enable peripheral interrupts (i.e., Timer 1)
    PIR1bits.TMR1IF=0;      //clear Timer 1 interrupt flag
    PIE1bits.TMR1IE=1;      //enable Timer 1 interrupts
    INTCONbits.GIE=1;       //enable all interrupts

    T1CONbits.TMR1ON=1;     //turn on Timer 1

    while(1);               //wait for interrupts

    return;
}

void interrupt ISR()
{
    if (PIR1bits.TMR1IF==1)
    {
        PIR1bits.TMR1IF=0;          //clear interrupt flag

        T1CONbits.TMR1ON=0;         //turn off Timer 1
        TMR1H=0x0B;                 //initialize Timer 1 for 500ms delay
        TMR1L=0xDB;
        T1CONbits.TMR1ON=1;         //turn on Timer 1

        LEDstatus=~LEDstatus;       //toggle LED
        RB0=LEDstatus;
    }
}

TL; DR: Sé que detener un temporizador, volver a cargarlo y reiniciarlo (en general) causará algún retraso, pero ¿por qué el PIC acortando mi ¿Intervalo de 500 ms por más de 80 ms?

Creo que he encontrado una pista de por qué esto no funciona, pero no entiendo muy bien los detalles. A partir de la p.53 de la hoja de datos:

  

7.7 Timer1 Prescaler

     

El contador del prescaler se borra al escribir en el
  Registros TMR1H o TMR1L.

¿Qué significa esto exactamente? ¿El prescaler se convierte en un valor distinto de 1: 8 durante un período de tiempo cuando escribo en TMR1H y TMR1L?

EDIT: También he intentado usar la función Comparar del módulo CCP, y el retraso sigue siendo el mismo valor inexacto. ¿Podría tener un chip malo? ¿Podría el oscilador interno realmente estar tan lejos?

    
pregunta Daniel Charles

1 respuesta

3

No parece haber ningún problema con su código. Aquí está el retraso con un reloj de 4.000MHz usando MPSIM:

Intente colocar un capacitor de derivación de baja impedancia y un capacitor más grande en paralelo (p. ej., cerámica de 100 nF y electrolítico de 100 uF) directamente a través de la alimentación (Vss-Vdd) al microcontrolador.

La sección que cita hace referencia al presaler contador , no a la selección del prescaler, por lo que no hay un gran efecto.

    
respondido por el Spehro Pefhany

Lea otras preguntas en las etiquetas