Estoy tratando de simular el modo PMW en múltiples pines en el software controlando un Timer2.
Estoy usando el valor máximo del preescalador 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 completo del temporizador. La interrupción de desbordamiento se usa para encender el LED (PIN13) y la interrupción de comparación se usa para reiniciar el LED y apagarlo.
Cuando lo ejecuto, veo que el LED parpadea pero muy tenuemente y su brillo no se ve afectado por el valor CUT_OFF. Si desactivo el LED apagado en la interrupción de comparación y solo cambio el LED en desbordamiento, veo que parpadea a un ritmo 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 llaman el número correcto de veces.
Aquí está el código que uso:
#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 problema con mi comprensión de cuándo se llaman las interrupciones?
o hay un problema con la configuración del temporizador o el manejo de interrupciones?
Actualización: ¿Podría estar el problema en el uso de digitalWrite() en las interrupciones? Actualización 2: cambiar digitalWrite para dirigir la manipulación de bits de PORTB produce un solo destello probablemente en la interrupción inicial y el LED muy tenue posterior, por lo que no es el único problema.
El LED parpadeante de PS es solo una prueba, por lo que usar PWM integrado no es una opción.
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 preguntaría por qué parece estar borrando el modo asíncrono al entrar y salir del modo pwm, pero no parece afectar nada.
toby jaffey
aliher