Manejo del desbordamiento del temporizador y comparación de interrupciones en ATMega328 (Arduino)

6

Estoy intentando simular el modo PMW en varios pines en el software controlando un Timer2.

Estoy usando el valor máximo de preescalado para obtener aproximadamente 60 pulsos por segundo cuando el temporizador cuenta hasta su valor máximo. El valor de OCR2A se utiliza para activar el momento real dentro del ciclo de temporizador completo. La interrupción por desbordamiento se usa para activar el LED (PIN13) y la interrupción de comparación se usa para reiniciar el LED.

Cuando lo ejecuto, veo que el LED parpadea pero muy débilmente y su brillo no se ve afectado por el valor CUT_OFF. Si desactivo el LED en la comparación de interrupciones y simplemente cambio el LED en el desbordamiento, veo que parpadea a una velocidad razonable que coincide con el informe final impreso en el puerto serie (número de interrupciones en 5 segundos). El informe final también muestra que ambas interrupciones se están llamando el número correcto de veces.

Aquí está el código que utilizo:

#include <avr/io.h>
#include <avr/interrupt.h>

#define LED_PORT (13)

#define CUT_OFF (100)

volatile unsigned long time1 = 0;
volatile unsigned long time2 = 0;

ISR(TIMER2_OVF_vect) {
  PORTB |= 0x20;
  time1++;
}

ISR(TIMER2_COMPA_vect) {
  PORTB &= ~0x20;
  time2+=2;
}

void startTimer() {
  cli();
  // enable timer interrupt overflow + reg a
  TIMSK2 = _BV(OCIE2A) | _BV(TOIE2);
  // counter
  TCNT2  = 0x00;
  // cut off value
  OCR2A  = CUT_OFF;
  // mode - normal + prescaler 1024
  TCCR2A = 0x00;
  TCCR2B = _BV(CS22) | _BV(CS21) | _BV(CS20);
  // async mode off
  ASSR  &= ~(_BV(AS2) | _BV(EXCLK));
  sei();
}

void stopTimer() {
  cli();
  // disable interrupts
  TIMSK2 = 0x00;
  // mode (disconnect clock source)
  TCCR2A = 0x00;
  TCCR2B = 0x00;
  // async mode off
  ASSR  &= ~((1<<AS2) | (1<<EXCLK));
  sei();
}

void blinkLed(uint8_t times) {
  for(uint8_t i=0;i<times;i++) {
    digitalWrite(LED_PORT, HIGH);
    delay(500);
    digitalWrite(LED_PORT, LOW);
    delay(500);
  }
}

void setup() {
  pinMode(LED_PORT, OUTPUT); 
  Serial.begin(9600);
}

unsigned long iterations = 0;

#define MAX_ITERATIONS (1000000)

void loop() {
  blinkLed(3);
  startTimer();
  delay(5000);
  stopTimer();
  blinkLed(2);

  Serial.println("Iterations finished!");
  Serial.print("Timer1=");
  Serial.println(time1);
  Serial.print("Timer2=");
  Serial.println(time2);

  while(1);  
}

¿Hay algún error en mi comprensión de cuándo se llaman las interrupciones?

  • COM2A: cuando alcanzamos el valor CUT_OFF
  • OVF cuando el contador llega a 255 y cambia a 0

¿O hay algún problema con la configuración del temporizador o el manejo de las interrupciones?

Actualización: ¿Podría el problema estar en el uso de digitalWrite () en interrupciones? Actualización 2: el cambio de digitalWrite para dirigir la manipulación de bits PORTB produce un solo flash probablemente en la interrupción inicial y el subsiguiente LED muy tenue, por lo que no es el único problema.

P.S. El LED parpadeante es solo una prueba, por lo que el uso de PWM integrado no es una opción.

    
pregunta aliher

1 respuesta

2

No estoy completamente seguro de por qué , pero el uso del modo pwm rápido en lugar del modo normal parece solucionar este problema.

Use el mismo código, pero reemplazando

TCCR2A = 0x00;

con

TCCR2A = _BV(WGM20)|_BV(WGM21);

También me preguntaría por qué pareces estar desactivando el modo asíncrono al entrar y salir del modo pwm, pero no parece afectar nada.

    
respondido por el Brog

Lea otras preguntas en las etiquetas