5 votos

¿Cómo se calcula el período Timer1?

Estoy tratando de configurar el temporizador 1 de un pictograma de 24h a 1ms por cada tic de temporizador, pero no parece que pueda hacer que las matemáticas coincidan con mis resultados.

Tengo un oscilador externo de 20MHz (con una resistencia de 1M en paralelo para la estabilidad) y creo que lo tengo habilitado con los siguientes bits de configuración establecidos en código:

#pragma config FNOSC = PRIPLL           // Oscillator Mode (Primary Oscillator (XT, HS, EC) w/ PLL)
#pragma config IESO = ON                // Internal External Switch Over Mode (Start-up device with FRC, then automatically switch to user-selected oscillator source when ready)

Estoy cambiando un alfiler y mirándolo en la pantalla para comprobar mis matemáticas. Pensé que el cálculo era el siguiente:

//  ms_per_tick = ((F_OSC / 2)/prescaler)^-1 * PR1
//                    = ((20MHz / 2) / 8)^-1 * 4200
//          NO= 1ms

bit un valor de PR1 = 4200 es lo más cercano que puedo llegar a un tick de 1ms.

¿Qué me estoy perdiendo? ¿Cambia el PLL el valor de lo que creo que es F_OSC. ¿Hay alguna manera de validar F_OSC?

El ISR sólo incrementa una variable y borra la bandera de interrupción. Aquí está el código de inicialización:

T1CONbits.TCKPS = 0b01;   // configure the timer prescaler to divide-by-8
T1CONbits.TCS = 0;        // do NOT use the external clock
PR1 = 4200;               // configure the timer period

// configure the Timer1 interrupt
_T1IF = 0;             // begin with the interrupt flag cleared
_T1IE = 1;             // enable the interrupt
T1CONbits.TON = 1;         // turn on timer1

Estoy empezando a aprender más sobre el PLL a través de algunos SFR:

CLKDIV is: 0x3040 (PLLPOST = 1, PLLPRE = 0)
PLLFBD is: 0x0030 (PLLDIV = 48)

También acabo de encontrar esto en la página 16 de la hoja de datos:

"Si el PLL del dispositivo objetivo está habilitado y configurado para el oscilador de arranque del dispositivo, la frecuencia máxima de la fuente del oscilador debe limitarse a ≤8 MHz para la puesta en marcha con el PLL habilitado para cumplir con las condiciones de arranque del dispositivo PLL. Esto significa que si el exterior frecuencia del oscilador está fuera de este rango, la aplicación debe iniciar en el modo FRC primero. Los ajustes PLL por defecto después de un POR con una frecuencia de oscilador fuera de este rango violará la velocidad de funcionamiento del dispositivo. Una vez que el dispositivo se enciende, la aplicación El firmware puede inicializar los PLL SFR, CLKDIV y PLLDBF a un adecuado y luego realizar un cambio de reloj al oscilador + reloj PLL fuente. Tenga en cuenta que la conmutación del reloj debe estar activada en el dispositivo Palabra de configuración".

Ahora, la primera cosa que voy a hacer después de la principal es este código de ejemplo:

void ConfigureOscillator(void) {
  // Disable the Watch Dog Timer
  RCONbits.SWDTEN = 0;

  // When clock switch occurs switch to Prim Osc (HS, XT, EC)with PLL
  __builtin_write_OSCCONH(0x03);  // Set OSCCONH for clock switch
  __builtin_write_OSCCONL(0x01);  // Start clock switching

  // Wait for Clock switch to occur
  while(OSCCONbits.COSC != 0b011);

  // Wait for PLL to lock, if PLL is used
  while (OSCCONbits.LOCK != 1);
}

0 votos

¿Dónde está el código de inicialización del temporizador y el ISR? Además, bastante seguro de que desea FNOSC ajustado a HSPLL, pero vuelva a comprobar que para los PICs de 16 bits.

0 votos

@MattYoung HSPLL no es una opción en el menú desplegable en Ventana >> Vistas de memoria PIC >> Bits de configuración para este PIC.

1voto

Marco W. Puntos 118

Hay que reconocer dos cosas:

  1. el temporizador es un contador ascendente que se interrumpe al desbordarse en el cual punto debe recargar el inicio del contador ascendente.
  2. la frecuencia es la salida del PLL si tiene uno configurado
= (f_osc / 4)^-1 * prescaler * (65535 - TMR1)
= (16MHz / 4)^-1 * 1 * (1000)
= 250us

Donde el temporizador se está utilizando como un temporizador de 16 bits y TMR1 es el valor escrito en TMR1. Me gusta especificar la precarga como un número negativo porque es más intuitivo que ver algo como menos que UINT16_MAX:

#define TIMER1_TIME  (-1000)

void InitTimer1(void) {
  T1CONbits.T1CKPS = 0b00;              // Prescaler is divide-by-1
  T1CONbits.TMR1CS = 0b00;              // Clock source is (f_osc / 4)
  TMR1H = TIMER1_TIME >> 8;             // Load the start of the upcounter
  TMR1L = TIMER1_TIME & 0xFF;
  IPR1bits.TMR1IP = 1;                  // Set to high priority
  PIR1bits.TMR1IF = 0;                  // Clear interrupt flag
  PIE1bits.TMR1IE = 1;                  // Enable interrupt
  T1CONbits.TMR1ON = 1;                 // Turn on the the timer
}

void MyIsr(void) {
  // Reload the start of the upcounter
  TMR1H = TIMER1_TIME >> 8;
  TMR1L = TIMER1_TIME & 0xFF;
}

0voto

NeoRiddle Puntos 106

El temporizador 0 es un temporizador de 16 bits, por lo que tu conjunto para interrumpir cada 1 segundo que necesita establecer:

- Preescalador @ 128

- TMR0 Precarga @ 26474

La ecuación:

\$ T= \left(\left({1 \over Fosc}\right)\times4\right)\times Presc\times\left(Resolution - Preload\right) \$

Dónde:

  • T = Período = 1s
  • Fosc = Frecuencia del oscilador = 20Mhz
  • Presc = Prescaler = 128
  • Resolución = 2^16 = 65535
  • Precarga = 26474

El resultado será: 0.9999872s, será el más cercano de 1s puede alcanzar.

Código de ejemplo:

// Timer1 Registers: Prescaler=1:1; TMR1 Preset=60536; Freq=1.000,00Hz; Period=1,00 ms
T1CON.T1CKPS1 = 0;  // bits 5-4  Prescaler Rate Select bits
T1CON.T1CKPS0 = 0;  // bit 4
T1CON.T1OSCEN = 1;  // bit 3 Timer1 Oscillator Enable Control: bit 1=on
T1CON.T1SYNC  = 1;  // bit 2 Timer1 External Clock Input Synchronization Control bit:1=Do not synchronize external clock input
T1CON.TMR1CS  = 0;  // bit 1 Timer1 Clock Source Select bit:0=Internal clock (FOSC/4) / 1 = External clock from pin T1CKI (on the rising edge)
T1CON.TMR1ON  = 1;  // bit 0 enables timer
TMR1H = $EC;         // preset for timer1 MSB register
TMR1L = $78;         // preset for timer1 LSB register

Uso del compilador CCS en MPALB 8:

// Timer 1 declaration
setup_timer_1(T1_INTERNAL|T1_DIV_BY_128);  
set_timer1(26474);
enable_interrupts(INT_TIMER1);
enable_interrupts(GLOBAL); 

// Timer 1 Method
#INT_TIMER1 
void timer1Method()
{
    //your timer1 code here
}

0 votos

Esa ecuación no coincide con lo que veo en el o-scope. Cuando aumento PR1, aumento el tiempo total hasta que la interrupción se dispara de nuevo. Parece más como (2 / F_osc) * Prescaler * PR1 pero todavía estoy tratando de confirmar la función de transferencia exacta

0 votos

Puede ser una diferencia en lo que micrcontrollers estamos asumiendo. Estoy usando: dsPIC33EPXXXMC20X y ni siquiera tiene una opción de prescaler para 128. También estoy en MPLABX por lo que algunas de las macros asumido que está utilizando no son relevantes para mí. Aprecio su ayuda sin embargo.

i-Ciencias.com

I-Ciencias es una comunidad de estudiantes y amantes de la ciencia en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros usuarios, hacer tus propias preguntas o resolver las de los demás.

Powered by:

X