Hallo,
ich weiß, das ist nach Lehrbuch sehr böse. Aber vielleicht ist es
manchmal doch ganz sinnvoll:
Angenommen, ich benutze einen ATMEGA mit 4 USARTs. 4 gleichartige
Sensoren mit je einer seriellen Schnittstelle liefern die Daten an, alle
nach dem gleichen Protokoll.
Ich brauche also vier USART-Empfangsroutinen, die sich auf die Präambel
des Protokolls synchronisieren, die Daten einsammeln, die Checksumme
"mitrechnen" und zum Schluss, wenn alle Daten eingetroffen sind, diese
in einen Puffer umkopieren und ein Flag setzen.
Im Hauptprogramm in der Endlosschleife wird dann nur auf die Flags
gewartet und dann der Parser aufgerufen, der für die eigentliche
Verarbeitung der eingetroffenen Daten zuständig ist.
Was spricht eigentlich dagegen, die ISR nicht viermal zu kopieren,
sondern von dort aus ein Unterprogramm aufzurufen, das als einzigen
Parameter neben dem emfangenen Zeichen einen Index bekommt, welche der
jeweils vier Puffer- und Statusvariablen zu benutzen ist?
Wäre über eure Meinungen dankbar! Ich denke, der Code entspricht dann
zwar nicht ganz der Lehrmeinung, ist dafür aber besser zu warten.
Zinkchromat schrieb:> Was spricht eigentlich dagegen, die ISR nicht viermal zu kopieren,> sondern von dort aus ein Unterprogramm aufzurufen, das als einzigen> Parameter neben dem emfangenen Zeichen einen Index bekommt, welche der> jeweils vier Puffer- und Statusvariablen zu benutzen ist?
Nichts.
Wenn ein Lehrbuch behauptet, das sei böse, dann verbrennen.
Es geht ja nicht drum, ob sich der Code unterscheidet. Die Uarts
unterscheiden sich nur durch die Daten. Also fuer jedes UART einen
eignenen Datensatz und gut ist.
Zinkchromat schrieb:> Ich denke, der Code entspricht dann> zwar nicht ganz der Lehrmeinung, ist dafür aber besser zu warten.
Programmiertips sind kein Gesetz, sondern nur Empfehlungen. Wenn es
einen triftigen Grund gibt, kann man natürlich davon abweichen.
Die AVRs haben einen Nachteil, daß sie keine Interruptprioritäten haben.
Daher bestimmt der langsamste Interrupt die Latenz aller anderen
Interrupts. Und deshalb die Empfehlung, sämtliche Interrupts schnell zu
halten.
Andere MCs mit Interruptprioritäten können z.B. eine Software-PWM mit
hoher Priorität ausführen und dann kann ein UART-Interrupt sich soviel
Zeit nehmen, wie er lustig ist. Für die hohe Priorität sind alle anderen
Interrupts quasi nicht vorhanden, sie laufen sozusagen auf Main-Level.
Falls Du noch schnelle andere Interrupts brauchst, kannst Du die
Funktion als Inline definieren. Sie muß dann im h-File stehen, damit
jeder Aufruf sie expandieren kann.
Peter
Zinkchromat schrieb:> Was spricht eigentlich dagegen, die ISR nicht viermal zu kopieren,> sondern von dort aus ein Unterprogramm aufzurufen, das als einzigen> Parameter neben dem emfangenen Zeichen einen Index bekommt, welche der> jeweils vier Puffer- und Statusvariablen zu benutzen ist?
Setze doch in der jeweiligen ISR den Index/Pointer für die Verarbeitung
der Daten vom Port und springe dann mit einem GOTO in den gemeinsam
verwendeten Code, der mit RTI endet. Was bringt eine Subroutine da für
Vorteile, außer der zusätzliche Stackwurschtelei?
>Im Hauptprogramm in der Endlosschleife wird dann nur auf die Flags>gewartet und dann der Parser aufgerufen,
Die ankommenden Daten kommen ja (bedingt durch die UART) Byteweise an.
Warum diese beim Eintreffen nur auf Prüfsumme hin aufaddieren?
Tue die doch gleich beim Eintrudeln mittels einer StateMaschine parsen
und das fertige Ergebnis per flag der main geben.
So läufst du nur einmal über die Daten, statt:
1.) Beim Empfang für die Summe,
2.) Beim èbergeben zum main,
3.) Beim Abholen von main,
4.) Beim Parsen....
Du mußt zwei Fälle berücksichtigen:
1. Eine Interruptserviceroutine kann nicht durch eine andere
unterbrochen werden
-> dann wird die Unterfunktion immer ohne Unterbrechung abgearbeitet und
es sind keine Probleme zu erwarten.
2. Ein höherpriorer Interrupt kann eine andere ISR unterbrechen und die
Unterfunktion kann von der hochprioren ISR neu aufgerufen werden,
während sie gerade abgearbeitet wird
-> dann muß die Unterfunktion "reentrant" programmiert sein, d.h. für
eben diesen Fall ausgelegt sein.
Beides ist möglich und erlaubt, allerdings ist Reentranz aufwendiger und
eher fehlerträchtig.
Ein UART vierfach zu haben ist keine allzuhohe Belastung bei hinreichend
tiefer Baudrate. Die Mega-Interruprs sind nicht priorisiert und
unterbrechen einander nicht.
Wenn man GCC verwendet, und eventuell auch bei anderen Compilern führt
der Unterprogrammaufruf zu einem relativ großen Stackverbrauch und die
ISR wird auch länger / Langsamer. So lange man genug Flasch speicher
frei hat, könnte man den Code eventuell noch mit Unterprogramm schreiben
und dann per Inline dafür sorgen das der Code trotzdem einfach 4 mal
hineinkopiert wird, und man ohne den Overhead auskommt. Wie weit das
gleiche Problem auch bei Goto auftritt müsste man sehen. Da muss man
dann aber aufpassen das jeweils gleichen Register gerettet werden - das
könnte ein Problem werden !.