Calcular la frecuencia exacta del temporizador para ATTiny

6

Tratando de envolver mi cabeza alrededor de estos temporizadores de desbordamiento para el ATTinyx5 (45 en este caso particular). Parecía tener un gran control sobre él con el ATMega328 pero no puedo hacerlo funcionar como quiero con los pequeños chips.

Estoy tratando de lograr un pulso de 1 segundo (para propósitos de prueba, LED encendido por 1s luego apagado por 1s). Sé que hay muchas maneras de lograr esto, pero las más simples parecen ser utilizando el ISR de desbordamiento. Esto es lo que tengo hasta ahora:

//Who can ever remember what the prescaler combinations are?
//These are for Timer0
#define PRESCALE0_1 _BV(CS00)
#define PRESCALE0_8 _BV(CS01)
#define PRESCALE0_64 (_BV(CS00) | _BV(CS01))
#define PRESCALE0_256 _BV(CS02)
#define PRESCALE0_1024 (_BV(CS02) | _BV(CS00))

void setup()
{
  DDRB |= _BV(PINB0); // Set Pin 5 (PB0) as output;
  PORTB &= ~_BV(PINB0); //Set it to low, just to be safe

  cli();
  TIMSK |= _BV(TOIE0);
  TCCR0B |= PRESCALE0_64;
  sei();

}

uint8_t _interval = 2;
uint16_t _pulseCount = 0;
uint16_t _pulseMax = 15625; // = 1s / 0.000064s
bool state = false;

ISR(TIM0_OVF_vect) 
{ 
  _pulseCount++;
  if(_pulseCount >= _pulseMax)
  {
    _pulseCount = 0;

    if(!state)
    {
      PORTB |= _BV(PINB0);
      state = true;
    }
    else
    {
      PORTB &= ~_BV(PINB0);
      state = false;
    }
  }
} 

Como puede ver, estoy haciendo poco más que habilitar el ISR de desbordamiento del temporizador y configurar el prescaler a 8. Ahora, estoy ejecutando el chip a 1Mhz al configurar el fusible de reloj / 8.

Dado que 1 / (F_CPU / 64) = 0.000064 o 64 uS, eso significa que 1 / 0.000064 = 15625 desbordamientos por segundo. Por lo tanto, el plan general era contar los desbordamientos en una variable uint16_t util que alcanzó 15625 y luego hacer lo que tenía que hacer en 1 segundo. Una especie de desbordamiento para el desbordamiento.

Pero en lugar de eso, recibo un pulso cada par de minutos! . Para obtener el pulso que necesito, tengo que configurar _pulseMax a más como 128, que debería ser 0.000064s * 128 = ~ 8ms.

Estoy seguro de que lo que sea que esté haciendo es terriblemente estúpido, pero no puedo verlo. ¿Qué estoy haciendo mal aquí?

    
pregunta Adam Haile

2 respuestas

3

No uso los AVR (uso PIC, pero los periféricos básicos son muy parecidos), pero imagino que el registro del temporizador es de 8 bits y la configuración básica es activar una interrupción en un desbordamiento.
Entonces, a menos que me haya perdido algo (muy posible, he estado despierto toda la noche :-)) Creo que estás fuera por un factor de 256, ya que no parece que hayas permitido esto.

Si su reloj es 1MHz y el prescaler es 64, entonces el desbordamiento debería ocurrir cada:

1 / (1e6 / 64/256) = 16.3ms.

Si multiplicas esto por 128, obtienes ~ 2 segundos.

    
respondido por el Oli Glaser
-1

Puedes obtener más flexibilidad usando el modo CTC. Con eso, puedes contar de 0 a un número de 8 bits y luego volver a empezar en 0. Obtienes una interrupción de comparación de coincidencia en lugar de un desbordamiento. Harías algo como esto:

void setup() {
  // blah blah blah
  TCCR0A = _BV(WGM01); // mode 2 - CTC
  TIMSK = _BV(OCIE0A); // OCR0A interrupt only.
  OCR0A = 49; // don't forget to subtract 1 - the counter is 0-49 inclusive.
}

ISR(TIMER0_COMPA_vect) {
  // whatever
}

Esto le dará una interrupción cada 50 relojes con temporizador.

Este mecanismo es muy útil para obtener, digamos, interrupciones de 10 Hz de un reloj del sistema de 1 MHz. Establece el preescalador para dividir por 1024, pero eso significa que para obtener 10 Hz debe contar hasta 97 21/32. Para hacer eso, establece OCR0A en 97 para 21 ciclos, luego 96 para 11 ciclos. Obtendrá una interrupción nominalmente cada 10 Hz, aunque algunos periodos serán 1.024 ms más largos que otros.

    
respondido por el nsayer

Lea otras preguntas en las etiquetas