Hallo Zusammen,
Ich habe ein ein kleines Betriebbssystem geschreiben. Frpher alles über
Timer.
Jetzt habe ich die wichtisten Teile auf die High und Low Interrupt
Routinen aufgeteilt.
- Das Programm startet. Der Timer 0 aktualisiert die Uhrzeit und
Temperatur.
- Ich kann Daten senden. Diese werden verabeitet.
Das Problem:
Das Programm springt mit aus diesen Programmteil, nicht zurück.
Sämtliche Tests waren erfolglos.
Es muss etwas ganz einfaches bedingt durch die beiden Einsprungsadressen
sein.
Was mache ich falsch?
Ist zwar schon ne Weile her bei mir mit PIC aber du musst die Interrupt
Flag bei Peripherie manuell zurück setzen soweit ich mich erinnere (im
Interrupt)
Heißt, INTCON.TMR0IF = 0. Sonst bleibt die Flag permanent gesetzt.
Ja stimmt, das wäre mal ein Ansatz. Der Befehl ist in der Timer Routine
drin. Aber was passiert, wenn der Interrupt unterbricht, und das Flag
noch gesetzt ist. Ich werde das mal testen..
1
C-Code
2
voidTMR0_ISR(void)
3
{
4
// clear the TMR0 interrupt flag
5
INTCONbits.TMR0IF=0;
6
7
// reload TMR0
8
// Write to the Timer0 register
9
TMR0H=timer0ReloadVal>>8;
10
TMR0L=(uint8_t)timer0ReloadVal;
11
12
// ticker function call;
13
// ticker is 1 -> Callback function gets called every time this ISR executes
Die PIC bilden eine Ausnahme gegenüber den üblichen Mikrocontrollern,
sie haben keine nach Quelle unterschiedlichen Interruptvektoren.
Daher müssen in den beiden Interrupthandlern erstmal alle freigegebenen
Quellen abgeklappert werden, ob das Pending-Flag gesetzt ist und dann
muß es gelöscht werden.
Ingo S. schrieb:> Aber was passiert, wenn der Interrupt unterbricht, und das Flag> noch gesetzt ist.
Ein Interrupt kann nur durch einen Interrupt höherer Priorität
unterbrochen werden und wird nach dessen Ende weiter ausgeführt. Das
Flag ist dabei egal.
Peter D. schrieb:> Die PIC bilden eine Ausnahme gegenüber den üblichen Mikrocontrollern,> sie haben keine nach Quelle unterschiedlichen Interruptvektoren.
Das gilt nur für <= PIC18
Stimmt, dass kann ich nach meinen Tests bestätigen. Unabhängig von den
Flags bleibt der Interrupt über die serielle Schnittstelle aktiv, und
der TMR0 startet nicht mehr. Jetzt kommt aber das was ich nicht für
möglich gehalten habe.
- Mit der aktuellsten Version des XC8 2.32 startet der Timer nicht mehr.
- Aus Spielerei habe ich gestern dann noch die Vorgänger Version
getestet.X8 2.31. Das kuriose in dieser Version startet der Timer
wieder.
Wer kann mir nun sagen, welcher Compiler richtig oder falsch arbeitet.
Ingo S. schrieb:> Wer kann mir nun sagen, welcher Compiler richtig oder falsch arbeitet.
Wer anderen diese Frage stellt, kann sich ziemlich sein, dass es nicht
der Compiler ist.
Ist zwar schon länger her, aber, falls doch noch jemand darüber
stolpert, hier einige Gedanken: ganz wichtig - Interruptservice-Routinen
sollten so kurz wie möglich gehalten werden und keine extensiven
Funktionsaufrufe beinhalten (besonders solche, deren Quellcode man nicht
kennt).
Ino S. hat in seiner TMR0_ISR() viele sprintf, strcopy, LCDprintf sowie
MCP794XX...-Aufrufe. Das ist mit ziemlicher Sicherheit vom
Zeitmanagement her problematisch.
Die Abarbeitung all dieser Dinge hat außerhalb und nach Beendigung der
Interruptservice-Routine zu erfolgen (jeweiliges Interrupt-Flag wieder
rücksetzen!), zB in einer Schleife, welche auf ein von der
Interruptservice-Routine gesetztes Flag prüft, dieses löscht und zur
Abarbeitungsfunktion (= TMR0_ISR) für den MCPxxx und dem Display
verzweigt. Oder man implementiert eine einfache state-machine.
Was nicht aus den Codeabschnitten hervorgeht, ist, wie oft die TMR0-ISR
pro Sekunde angesprungen wird. Kennt man das, dann vergleiche man,
wieviel Zeit all die sprintf, strcopy, etc Funktionen benötigen - es
wird sich bis zum nächsten TMR0_ISR-Aufruf uU nicht ausgehen und das
TMR0-Intervall wäre daher entsprechend zu vergrößern. Werden zudem ev
auch Interrupts in den aufgerufenen Funktionen deaktiviert (dann sieht
es düster aus)?
Die Interruptservice-Routine für das Abfangen der seriellen Daten
unterbricht die TMR0-Interruptservice-Routine, falls etwas daherkommt,
da sie die höhere Priorität hat. Auch hier sollte die eigentliche
Abarbeitung/Verarbeitung der empfangenen Daten außerhalb der
Interruptservice-Routine erfolgen. Zudem würde ich die
TMR0-Interruptservice-Routine als high_priority setzen, um ev
Unterbrechungen durch andere Interruptservice-Routinen hintanzuhalten.