Ich versuche, den PMW-Modus an mehreren Pins in der Software zu simulieren, indem ich einen Timer2 steuere.
Ich verwende den maximalen Prescaler-Wert, um ungefähr 60 Impulse pro Sekunde zu erhalten, wenn der Timer auf seinen Maximalwert zählt. Der Wert von OCR2A wird verwendet, um den tatsächlichen Moment innerhalb des vollen Zeitgeberzyklus auszulösen. Der Überlauf-Interrupt wird verwendet, um die LED (PIN13) einzuschalten, und der Vergleichs-Interrupt wird verwendet, um die LED zurückzusetzen.
Wenn ich es ausführe, sehe ich, dass die LED blinkt, aber sehr schwach ist und ihre Helligkeit nicht vom CUT_OFF-Wert beeinflusst wird. Wenn ich die LED im Vergleichsinterrupt ausschalte und die LED im Überlauf einfach umschalte, sehe ich, dass sie mit einer angemessenen Geschwindigkeit blinkt, die dem an der seriellen Schnittstelle gedruckten Endbericht entspricht (Anzahl der Interrupts in 5 Sekunden). Der Abschlussbericht zeigt auch, dass beide Interrupts korrekt oft aufgerufen werden.
Hier ist der Code, den ich verwende:
#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);
}
Stimmt etwas mit meinem Verständnis nicht, wenn Interrupts aufgerufen werden:
oder gibt es ein Problem mit dem Einrichten des Timers/oder dem Umgang mit Interrupts?
Update: Könnte das Problem in der Verwendung von digitalWrite() in Interrupts liegen? Update2: Die Umstellung von digitalWrite auf direkte PORTB-Bit-Manipulation erzeugt wahrscheinlich beim ersten Interrupt ein einzelnes Blinken und anschließend eine sehr schwache LED, sodass dies nicht das einzige Problem ist.
Die blinkende PS-LED ist nur ein Test, daher ist die Verwendung des integrierten PWM keine Option.
Ich bin mir nicht ganz sicher, warum , aber die Verwendung des schnellen PWM-Modus anstelle des normalen Modus scheint dieses Problem zu beheben.
Verwenden Sie denselben Code, aber ersetzen Sie ihn
TCCR2A = 0x00;
mit
TCCR2A = _BV(WGM20)|_BV(WGM21);
Ich würde auch fragen, warum Sie den asynchronen Modus sowohl beim Betreten als auch beim Verlassen des PWM-Modus zu löschen scheinen, aber es scheint nichts zu beeinflussen.
Toby Jaffey
aliher