Ich bin neu bei PIC-Mikrocontrollern (ich habe etwas Erfahrung mit Arduino, wollte aber etwas "echte" Erfahrung = P). Ich habe mir einen PIC16F88 besorgt und beabsichtige, einen einfachen Roboter mit zwei 2 Gleichstrommotoren zu bauen. Jeder Motor wird unabhängig über PWM gesteuert.
Ich möchte die PWM-Signale in Software implementieren (ja, ich weiß, eine ziemlich gute Lernerfahrung!). Dieser Mikrocontroller hat nur ein PWM-Modul, aber ich würde es in Software machen wollen, auch wenn er mehr hätte.
Ohne weiteres:
Was passiert, wenn zwei Timer-Überlauf-Interrupts gleichzeitig auftreten? Ignoriert der Controller einen? Rufen beide nacheinander den Interrupt-Vektor auf?
Angenommen, Sie haben die Interrupts TMR0 und TMR1 aktiviert, indem Sie TMR0IE und TMR1IE gesetzt haben. Wenn eines der Interrupt-Ereignisse eintritt, werden ihre Interrupt-Flags (TMR0IF oder TMR1IF) gesetzt. Dies bewirkt nicht, dass der Code tatsächlich zur Interrupt-Routine vektorisiert, es sei denn, das GIE-Bit (Global Interrupt Enable) ist ebenfalls gesetzt.
Angenommen, GIE wurde festgelegt, und Sie erhalten einen TMR0-Überlauf. Dies setzt TMR0IF, Vektoren zur Unterbrechungsstelle und löscht das GIE-Bit . Jetzt, da GIE gelöscht ist, verursachen zukünftige Interrupt-Trigger kein Code-Vectoring. Die Interrupt-Flags werden jedoch weiterhin gesetzt.
Angenommen, Sie befinden sich in Ihrer Interrupt-Routine. Der TMR1-Interrupt wird ausgelöst. Dies setzt das TMR1IF-Bit, tut aber sonst nichts. Das Bit bleibt einfach gesetzt.
Wenn Ihre Interrupt-Routine beendet ist, verwenden Sie eine RETFIE
Anweisung (in Assembler) oder eine return();
(in c). Dies vektorisiert zurück zu Ihrem Mainline-Code und setzt das GIE-Bit .
Da nun sowohl das GIE- als auch das TMR1IF-Bit gesetzt sind, bewirkt dies einen sofortigen Vektor zurück in Ihren Interrupt-Code.
Sie verlieren also keine Interrupt-Daten; es verzögert sich nur.
Eine übliche Art, einen ISR zu strukturieren, sieht folgendermaßen aus:
if (TMR0IF && TMR0IE)
{
(do something)
TMR0IF = 0; // Clear the flag!
return();
}
else if (TMR1IF && TMR1IE)
{
(do something else)
TMR1IF = 0;
return();
}
Wenn Sie jedoch gleichzeitige Interrupts erwarten, möchten Sie möglicherweise zulassen, dass beide in nur einem Durchgang durch die ISR verarbeitet werden:
if (TMR0IF && TMR0IE)
{
(do something)
TMR0IF = 0;
}
if (TMR1IF && TMR1IE) // Notice this isn't an "else if"
{
(do something else)
TMR1IF = 0;
}
return();
Es gibt noch ein letztes Problem, dessen Sie sich bewusst sein sollten. Angenommen, beide Interrupt-Flags werden gleichzeitig (oder sehr nahe an der gleichen Zeit) gesetzt. Zum Zeitpunkt der Codevektoren an die Interrupt-Routine sind beide Flags bereits gesetzt. Die ISR weiß nicht, welche zuerst gesetzt wurde ; es läuft einfach durch Ihren Code. In meinen früheren Beispielen wird also zuerst der TMR0-Interrupt bedient, auch wenn das TMR1-Flag etwas früher war.
Ich hoffe das hilft :)
trosley
Etienne
Markt
Etienne