¿Tiempo preciso con un microcontrolador PIC18?

3

Estoy tratando de escribir una implementación serie de software y tengo problemas con el tiempo. Estoy usando Timer0 en un PIC18F242 y por alguna razón no parece ser muy preciso.

He estado tratando de solucionar el problema activando un pin en el microcontrolador y observando la frecuencia en mi osciloscopio. El osciloscopio muestra que el período es mayor de lo que debería ser, y no sé por qué.

Con mi código completo, el período fue algo así como 10us demasiado largo, si recuerdo bien, pero incluso con un ejemplo muy simple, como el que se muestra a continuación, el tiempo está apagado.

Aquí hay un ejemplo:

#include <p18f242.h>

// fuse configurations
#pragma config OSC = HSPLL
#pragma config OSCS = OFF 
#pragma config PWRT = OFF 
#pragma config BOR = OFF 
#pragma config WDT = OFF
#pragma config LVP = OFF 
#pragma config CP0 = OFF

// CALCULATIONS:
// 8Mhz crystal with PLL enabled
// FOSC = 4*8Mhz = 32MHz
// TOSC = 1/FOSC = 31.25ns
// TCY = 4*TOSC = 125 ns
// timer has 1:8 prescaler, therefore timer increments every 8*TOSC = 1us.

main(void)
{
    // port configuration
    TRISBbits.RB1 = 0; // make RB1 an output

    // configure Timer0
    T0CONbits.TMR0ON = 0; // disable (stop) the timer
    T0CONbits.T08BIT = 0; // 16-bit timer
    T0CONbits.T0CS   = 0; // use internal instruction clock
    T0CONbits.PSA    = 0; // use prescaler (prescaler assigned below)
    T0CONbits.T0PS0  = 0; // 010 = 1:8 prescaler
    T0CONbits.T0PS1  = 1;
    T0CONbits.T0PS2  = 0;
    T0CONbits.TMR0ON = 1; // enable (start) the timer

    while(1) 
    {
        if(TMR0L >= 100)
        {
            PORTBbits.RB1 ^= 1;

            // reset the timer
            TMR0H = 0; // MUST SET TMR0H FIRST
            TMR0L = 0;
        }   
    }
}

Mi osciloscopio dice que el período de esta señal es 204.0us, lo que significa que el pin está alternando cada 102.0us. Si mi osciloscopio es correcto, entonces el pin está alternando dos veces demasiado tarde cada vez.

Es interesante que al cambiar if(TMR0L >= 100) a if(TMR0L >= 102) en el mismo período, pero al ir por debajo de 100 o por encima de 102 , el período disminuye y aumenta, respectivamente.

¿Por qué sucede esto?

También, como mencioné, tener un código adicional en el bucle principal parece exacerbar el problema. ¿Por qué sería eso?

    
pregunta Nate

6 respuestas

2

Si desea una sincronización precisa, utilice interrupciones (es decir, restablezca el valor del temporizador en su rutina de interrupción).
Como lo tiene, solo verifica el valor del temporizador una vez por ciclo, por lo que si agrega código al bucle, los cheques se extienden.
La interrupción cambiará de contexto tan pronto como el temporizador se desborde, por lo que no importa cuánto código haya en su bucle.

    
respondido por el Oli Glaser
3

Lo que ves aquí es el retraso entre el momento en que el temporizador llegó a 100 (lo que significa que tu condición if es verdadera) y cuando lo restableces. En su caso, esto es 2 temporizadores, lo que significa que usted obtiene un período más largo. Como ya se dijo, si quieres tener interrupciones precisas de uso de tiempo. Alternativamente, puede configurar su temporizador para que se desborde exactamente en el momento adecuado. De esa manera, solo necesita verificar que ocurra un desbordamiento y no es necesario restablecerlo.

    
respondido por el hli
2

Esta no es la forma más efectiva de usar un temporizador. Si desea una sincronización precisa, establezca una interrupción para cuando el temporizador gire. La rutina de interrupción debe establecer un indicador de temporizador y hacer lo que sea más rápido que deba tratarse de manera crítica, y restablecer el conteo del temporizador (leyendo el valor actual del temporizador para que pueda tener en cuenta cualquier retraso asociado con el servicio de interrupción). Todo lo que no es rápido, se pone en un bucle if que comprueba el indicador del temporizador. Lo primero que haces en ese bucle es restablecer el indicador del temporizador y luego hacer todo lo que no es crítico con el tiempo asociado a tu bucle.

    
respondido por el Scott Seidman
1

El retraso adicional se debe al tiempo que lleva ejecutar el tiempo, si se comparan, se alternan y se restablecen las instrucciones, porque cuando se pone a cero el temporizador se pierden todos esos conteos, dependiendo de cuándo exactamente llegó a 100 en el temporizador. ese ciclo particular Tcy es de 125 ns, por lo que solo se necesitan 16 instrucciones de ensamblaje para dar cuenta del retraso adicional. Eche un vistazo a la lista de ensamblajes y se dará cuenta de la sobrecarga que está agregando.

Como han dicho otros, use una interrupción para la menor incertidumbre y la inestabilidad. En lugar de restablecer el temporizador, deje que se desborde y siga contando, de esa manera no se ponen a cero las cuentas, que se agregan al período total.

Si no desea utilizar interrupciones (pero debería), también configure el período para que se desborde y verifique el indicador de desbordamiento. Esto le permitirá no poner a cero el temporizador y conservará el período calculado, pero tendrá fluctuaciones.

    
respondido por el apalopohapa
0

Si usa un preaclarial con el temporizador 0, no es posible generar interrupciones con precisión a velocidades que no sean múltiplos de potencia de dos de 256. Si desea generar una velocidad que no sea una potencia de dos múltiplo de 256, su mejor apuesta es probablemente usar el Temporizador 2, que se puede configurar para cualquier número del formulario (A * B * C) donde A es cualquier número 1-256, B es cualquier número 1-16 y C es una potencia permitida de dos (me olvido de cuales son permitidas). De lo contrario, si desea usar el temporizador 0 de manera eficiente en el modo de 8 bits sin pre-escalar, diga que TMR0L += N avanzará el temporizador por N-3 ciclos. Por lo tanto, si quisiera que el temporizador 0 se ajustara cada 200 ciclos, podría, después de cada envoltura, agregarle (259-200) ciclos (ya que avanzar el temporizador en 56 ciclos después de la envoltura dejaría 256-56 ciclos, es decir, 200). Tenga en cuenta que al utilizar esta técnica, no importa precisamente cuándo se realiza el "agregado", siempre que ocurra lo suficientemente pronto como para que no empuje el temporizador "por encima del límite".

    
respondido por el supercat
-1

Puede ser una molestia si no conoce el ensamblaje, pero la inserción de rutinas de ensamblaje en el código C puede ayudarlo a lograr una sincronización precisa. Si recuerdo correctamente insertar el ensamblaje en el PIC C, usas

_asm

escriba su código de ensamblaje

_endasm

    
respondido por el Brandon Bailey

Lea otras preguntas en las etiquetas