Moin!
Ich lese mit einem Atmega 1248p (hat 2 USART) eine RC Fernsteuerung und
ein GPS Modul aus. Beides per interrupt.
Ich gehe davon aus dass eine Interruptroutine die andere unterbrechen
kann. Jetzt könnte man per cli() und sei() innerhalb der
Interruptroutine genau dies unterbinden. Läuft man dann nicht Gefahr
dass die eine oder andere Übertragung "unter den Tisch fällt"?
Wie macht man das richtig?
Danke!
Attila C. schrieb:> Läuft man dann nicht Gefahr dass die eine oder andere Übertragung "unter> den Tisch fällt"?
Das kommt drauf an, was die Interruptroutinen so treiben. Wenn sie
kurz sind, keine aufwendigen Berechnungen oder gar Warteschleifen
enthalten, wenn also die Laufzeit der Routinen deutlich kürzer ist als
die Zeit, die zwischen zwei Zeichen auf der UART vergeht, dann passiert
nichts.
Bei 9600 Baud hast Du etwa eine Millisekunde Zeit, da kann auch ein µC
einiges anstellen.
Wenn aber aus der Interruptroutine heraus aufwendiger Kram aufgerufen
wird, gar die Ausgabe von formatierten Strings auf eine andere
Schnittstelle, dann kracht es.
Warum aber willst Du die Interrupts abschalten? Greifen beide
Interruptroutinen auf gemeinsame Ressourcen zu?
Beide Routinen schauen nach einem Zeichen (um den Anfang einer
Übertragung zu identifizieren) um dann Zeichen in globale Arrays "zu
schaufeln" Das ganze bei 115200 Baud. Also 5 Zeilen Code etwa.
Mal angenommen eine Routine liest grade ein byte ein. Nach Übertragung
von z.B. 4 bit geht der andere interrupt los und unterbricht. Ist dieses
"Szenario" überhaupt denkbar?
Attila,
ich verwende jeweils einen TX-, und RX-Fifo pro USART. Die
Interruptservice Routinen lesen oder schreiben jeweils nur ein Byte in
die FIFO-Puffer.
Das wars.
Die gesamte Interpretation der eingegangenen Zeichen passiert in der
Hauptprogrammschleife, also außerhalb der Interruptverarbeitung !
Nachmals,
eine Unterbrechung einer Interruptservice Routinen findet nicht statt,
außer man programmiert es speziell und weis dass man einen Stacküberlauf
produzieren könnte.
Attila C. schrieb:> Ich gehe davon aus dass eine Interruptroutine die andere unterbrechen> kann.
Auf einem Atmega? Nö, der hat nur eine Interrupt Priorität - nur ein
Interrupt kann aktiv sein.
Mann muss sei/cli anwenden wenn man das so nicht haben will, also
Interrupts im Interrupt zulassen will. Dabei kann man sich aber prima in
den Fuß schiessen.
Nein. Wie schon geschrieben wurde, sind beim AVR serienmäßig innerhalb
von Interupptroutinen Interrupts gesperrt. So lange du also da einfach
die Finger von sei und cli lässt, ist alles in Ordnung.
Abgesehen davon empfangen die Usarts ihre Daten völlig unabhängig vom
Programmablauf. Das Szenario, das nach 4 Bit irgendwer irgendwas
unterbricht, gibt es überhaupt nicht.
Etwas Datenblattlektüre ist angeraten.
Oliver
Jim M. schrieb:> Auf einem Atmega? Nö, der hat nur eine Interrupt Priorität
das stimmt nicht ...
> - nur ein Interrupt kann aktiv sein.
das stimmt (im Normalfall) allerdings schon.
Die Prioritäten sind nur dann von Bedeutung, wenn
- 2 Interrupts exakt gleichzeitig auftreten
- innerhalb einer ISR mehrere andere Interrupts auftreten.
Dann wird die mit höherer Priorität zuerst ausgeführt - im 2. Fall nach
Verlassen der laufenden ISR.
Attila C. schrieb:> Mal angenommen eine Routine liest grade ein byte ein. Nach Übertragung> von z.B. 4 bit geht der andere interrupt los und unterbricht. Ist dieses> "Szenario" überhaupt denkbar?
Du solltest Dir ansehen, wie eine UART funktioniert und wann sie ihren
RX-Interrupt auslöst. Und wenn ein µC einen 8-Bit-Zugriff macht, erfolgt
der nicht sequentiell mit einzelnen Bits, sondern das ist ein Zugriff.
Attila C. schrieb:> Mal angenommen eine Routine liest grade ein byte ein. Nach Übertragung> von z.B. 4 bit geht der andere interrupt los und unterbricht. Ist dieses> "Szenario" überhaupt denkbar?
Nein.
-> Rx1_Byt1 -> Rx1_Byt2 -> Rx1_Byt3 -> Rx2_Byt1 -> Rx1_Byt4 usw.
Was soll da unterbrochen werden ?
Rufus Τ. F. schrieb:> Du solltest Dir ansehen, wie eine UART funktioniert und wann sie ihren
Genau. Wenn ein Byt empfangen worden ist, wird ein Interrupt
ausgelöst, nicht beim 5-ten bit oder so.
Da gibt es ganz einfach nichts was unterbrochen werden kann...
Jim M. schrieb:> Auf einem Atmega? Nö, der hat nur eine Interrupt Priorität - nur ein> Interrupt kann aktiv sein.
Und selbst wenn Interrupt 2 den Interrupt1 unterbricht, was soll
passieren? Ist ISR2 fertig, wird ISR1 fortgesetzt und alles ist gut.
Unter 2 Voraussetzungen:
1. Die ISR sind korrekt programmiert, sichern Register usw., aber sonst
funktioniert sowieso nichts.
2. Der Ablauf einer ISR ist viel kürzer als die Zeit zwischen 2 Zeichen.
Beides ist nicht schwierig sondern eher selbstverständlich.
Georg
Attila C. schrieb:> Ich lese mit einem Atmega 1248p (hat 2 USART) eine RC Fernsteuerung und> ein GPS Modul aus. Beides per interrupt.>> Ich gehe davon aus dass eine Interruptroutine die andere unterbrechen> kann.
Kann sie normalerweise nicht.
> Jetzt könnte man per cli() und sei() innerhalb der> Interruptroutine genau dies unterbinden.
Genau damit (mit sei()) machst du es erst möglich...
> Läuft man dann nicht Gefahr> dass die eine oder andere Übertragung "unter den Tisch fällt"?
Diese Gefahr besteht immer. Jedenfalls immer dann, wenn in der ISR mehr
passiert, als zwischen zwei Zeichen Rechenzeit verfügbar ist. Der Trick
ist also, die Programmierung so effizent zu gestalten, das zwischen zwei
Zeichen immer genug Rechenzeit verfügbar ist, um sie zu verarbeiten.
Bei den AVR-Hardware-UARTs ist es allerdings nicht ganz so kritisch,
weil die in Hardware bereits ein Double-Buffering bietet. Hier darf also
die Bearbeitung eines Zeichens auch "gelegentlich mal" etwas länger
dauern, nämlich fast zwei Zeichenlängen. Der dadurch aufgenommene
"Kredit" an Rechenzeit muss bei einer kontinuierlichen Übertragung
allerdings bei den nächsten Zeichen dadurch wieder ausgeglichen werden,
dass deren Behandlung schneller als in einer Zeichenlänge erfolgt, denn
ein weiterer "Kredit" ist erst dann möglich, wenn der vorige
zurückgezahlt wurde.
Man kann das Prinzip des Double-Buffering aber mittels Software-FIFO
noch ausweiten und damit weitere Entspannung bekommen. Die
Zeichenverarbeitung erfolgt dann nicht mehr in der ISR, sondern in
main(), in der ISR werden die Zeichen bloss in den FIFO verfrachtet, aus
dem sie dann in main() gelesen werden.
Aber auch mit allen Buffertricks muss am Ende gelten: Die Verarbeitung
der Zeichen muss im Schnitt mindestens mit der Geschwindigkeit des
Zeicheneingangs erfolgen. D.h.: Buffering löst nur das Problem
kurzfristiger Engpässe an Rechenzeit. Und dazu kommt: Software-Buffering
kostet weitere Rechenzeit, über die zur Zeichenverarbeitung eigentlich
nur nötige hinaus. In der Gesamtbilanz der Rechenzeit ist das also
eigentlich kontraproduktiv.
Rainer S. schrieb:> c-hater schrieb:>> Software-Buffering>> kostet weitere Rechenzeit>> Minimal.> Hat im Endeffekt aber mehr Vorteile.
Das kommt schlicht drauf an. Nämlich auf die Gesamtstruktur der
Anwendung und die Datenraten, die zu verarbeiten sind. Es gibt durchaus
Anwendungen, in denen Software-FIFOs kontraproduktiv sind.
Je höher die Datenrate, desto wahrscheinlicher ist das so. Denn, wie man
leicht erkennen kann, wirkt sich der Overhead eines Software-FIFO mit
steigender Datenrate immer stärker negativ aus.
D.h.: wenn es eng wird, sollte man vorzugsweise versuchen, den
Datenstrom mit der höchsten Rate direkt in der ISR zu verarbeiten.
c-hater schrieb:> vorzugsweise
"vorzugsweise"?
Dann habe ich ein anderes "vorzugsweise", als du.
Ich würde eher sagen:
> Nur, wenn es nicht anders geht!
c-hater schrieb:> sollte man vorzugsweise versuchen, den> Datenstrom mit der höchsten Rate direkt in der ISR zu verarbeiten.
Was immer man unter Verarbeiten versteht - empfangene Werte auf einer
Speicherkarte zu speichern gehört ganz sicher nicht in die ISR, solche
Behauptungen führen einen Anfänger nur in die Irre (gewollt?).
Georg
c-hater schrieb:> D.h.: wenn es eng wird, sollte man vorzugsweise versuchen, den> Datenstrom mit der höchsten Rate direkt in der ISR zu verarbeiten.Attila C. schrieb:> Ich lese mit einem Atmega 1248p (hat 2 USART) eine RC Fernsteuerung und> ein GPS Modul aus. Beides per interrupt.
Das sollte locker gehen.
Ich selbst benutze den Atmega 1248p, bzw. den etwas kleineren mit 2
seriellen Schnittstellen und mache es so, dass ich einen 16 Byte
Ringbuffer habe für beide Eingänge. Funktioniert einwandfrei. Eine
Schnittstelle mit maximal 19200 Baud (höher geht aber auch) und die
andere mit 100000 Baud.
Wobei hier noch die Frage ist, ob das GPS Modul unbedingt schnell
ausgelesen werden braucht.
Bei einem AVR-Controlelr musst du das UDR in einer Variablen
zwischenspeichern, wenn du es mehrfach verwenden willst. Beim ersten
Lesezugriff wird es gelöscht.
Außer der merkwürdigen Formatierung finde ich es auch wenig elegant und
mit vermutlich ineffizientem Ergebniscode gelöst. Ich würde ein const
char Array vorschlagen mit dem Inhalt "$GPRMC,".
Dann etwa so:
Über deine USART0 Routine freuen sich die Hackers. Schön Code
einschleusen wegen fehlender Überwachung. O.K. du killst wahrscheinlich
nur dein RAM, aber trotzdem böse.
@Rufus: Was ist an der Formatierung falsch oder wie müsste es besser
aussehen? Ich mache grundsätzlich bei jedem "blauen code" (Atmel Studio
7) ein tab und rücke somit nach rechts und zwar solange bis es um etwas
anderes geht. Beispiel:
Erbsen
Tomaten
Gurken
Speck
Leber
Hack
@Thomas: Es gelingt mir nicht deinen Vorschlag umzusetzen. Ich "erkenne"
zwar so wie Du vorschlägst das "$GPRMC" weiss aber nicht wie es dannach
weitergehen soll. Im besonderen ist mir nicht klar unter welcher
Bedingung denn z wieder 0 werden soll?
Attila C. schrieb:> @Rufus: Was ist an der Formatierung falsch oder wie müsste es> besser> aussehen? Ich mache grundsätzlich bei jedem "blauen code" (Atmel Studio> 7) ein tab und rücke somit nach rechts und zwar solange bis es um etwas> anderes geht. Beispiel:>> Erbsen> Tomaten> Gurken>> Speck> Leber> Hack>
Deine Abfragen haben doch alle die gleiche "Priorität": Sie werden alle
abgearbeitet.
Ein weiteres Einrücken liest sich, als würde der Programmteil vom
weniger stark eingerückten Programmteil abhängen.
Verwirrt einfach nur.
> @Thomas: Es gelingt mir nicht deinen Vorschlag umzusetzen. Ich "erkenne"> zwar so wie Du vorschlägst das "$GPRMC" weiss aber nicht wie es dannach> weitergehen soll. Im besonderen ist mir nicht klar unter welcher> Bedingung denn z wieder 0 werden soll?
z kannst =0 setzen, sobald ein "," auftaucht.
Dann musst du die vorher empfangenen Zeichen in eine Zahl umwandeln.
In der ISR solltest du aber nur einen Puffer füllen und vielleicht noch
das Start- und das Endezeichen erkennen.
Ich habe es jetzt so:
ISR(USART1_RX_vect)
{
static int y=0,z=0;
char desig[7]="$GPRMC,";
if (UDR1=='$')
{
y=1;
z=0;
}
if (UDR1==desig[y])
y++;
else
y=0;
if(y>6)
{
gpsdata[z]=UDR1;
z++;
}
}
@Marc: Danke! Ist ein "switch" schneller als 6 mal "if" ?
Die ISR ist schon zu überladen.
Bei der ISR das Zeichen kurz in den Ringbuffer schreiben (ist wirklich
nicht schwer) und in der main() alle andere verarbeiten. So hast Du auch
keine Probleme mit dem Mehrfachzugriff auf UDR0/1.
So wie oben beschrieben.
https://www.mikrocontroller.net/articles/FIFO
Attila C. schrieb:> @Marc: Danke! Ist ein "switch" schneller als 6 mal "if" ?
Nein, langsamer.
Aber switch wird normalerweise auch zu if übersetzt.
Es sind nur ein paar Takte mehr und es wird immer nur ein
case ausgeführt.
Attila C. schrieb:> Ups! Disregard: So funktionert es natürlich nicht!
Was funktioniert nicht ?
@Marc: Meine letzte Lösung finktionert nicht weil im "else" Teil y auf 0
gesetzt wird und somit die Bedingung y>6 genau ein mal gegeben ist.
@Rainer: 1) Danke! 2) Tatsächlich? Diese ISR wäre so "überladen?"
So, jetzt aber:
ISR(USART1_RX_vect)
{
static int y=0,z=0;
char desig[7]="$GPRMC,";
if (UDR1=='$')
{
z=0;
}
if (UDR1==desig[z])
z++;
if(z>6)
{
gpsdata[z]=UDR1;
z++;
}
}
Ist das immer noch zuviel "gerödel" für eine ISR?
Nein, aber deine UDR1 ist nach dem ersten Lesen bei der ersten IF
Schleife schon "leer". UDR wird nach dem Lesen gelöscht. Bei der zweiten
IF Abfrage liefert UDR dann immer 0x00.
Marc V. schrieb:> Eleganter ist nicht immer besser und schneller.
Hm - und welches Codemonster macht der Compiler aus Deinem switch-case?
Was soll an dem Array nicht gut sein? Einen Zeiger+Index auf ein (const
char) Array im ROM kriegt der Compiler sicher mit ein paar Befehlen
gebacken, und dann ist es maschinentechnisch nur noch eine einzige
Vergleichsoperation und ein bedingter Sprung, nicht womöglich 6 davon.
Ich gebe Dir Recht, daß "eleganter" nicht IMMER besseren Code erzeugt,
hier kann ich mir aber nicht vorstellen, daß eine "if" oder
"switch"-Orgie besser sein soll.
Außerdem ist das mit dem Array doch viel besser les- und wartbar, und
ließe sich ggf. auch leichter auf mehrere Schlüsselstrings erweitern,
was ich mir mit so einem Swirch-Case nicht so gut vorstellen kann.
Im Prinzip ist ein Ringpuffer schon besser, die Auswertung muss man aber
so oder so machen, und das Prinzip (ob mit Array, if oder switch) gilt
natürlich ggf. auch für eine Auswertung in der main().
Attila C. schrieb:> Ist das immer noch zuviel "gerödel" für eine ISR?
Natürlich nicht, aber die Abfrage mit Index ist langsamer als
Abfrage auf einzelne Zeichen.
Deswegen meine Bemerkung wegen Elegant.
Hier ist etwas schnelleres (wieder aus dem Kopf, ohne Gewähr auf
funktionieren)
1
volatileuint8_tgpsflag=0;// Flag dient zur Abarbeitung der GPS
2
3
ISR(USART1_RX_vect)
4
{
5
uint8_tgpschar=UDR1;
6
if(gpsflag==0){// Falls nicht abgearbeitet, wird gar nicht erst reingesprungen...
7
staticuint8_tz=0;
8
uint8_tstate=0;
9
switch(z)
10
{
11
case0x00:
12
if(gpschar!='$')z=0;
13
break;
14
case0x01:
15
if(gpschar!='G')z=0;
16
break;
17
case0x02:
18
if(gpschar!='P')z=0;
19
break;
20
case0x03:
21
if(gpschar!='R')z=0;
22
break;
23
case0x04:
24
if(gpschar!='S')z=0;
25
break;
26
default:
27
if(z>BufferSize){z=0;break;}
28
if(gpschar==0x0D)state=255;
29
elsestate=1;
30
}
31
if(state>0){
32
gpsdata[z++]=gpschar;
33
if(state==255)gpsflag=1;// main() setzt es wieder auf 0 nach Abarbeitung...
Thomas E. schrieb:> Hm - und welches Codemonster macht der Compiler aus Deinem switch-case?
LOL.
Das stimmt schon mal nicht.
Erstens ist mein "Codemonster" wenn nicht kürzer, dann bestimmt nicht
länger als deine bzw. Attila's Lösung.
Und schneller ist es auf jeden Fall.
Und du bzw. Attila hast nicht mal eine Prüfung auf Zeilenende,
Bufferüberschreitung, ob die vorige GPS-Meldung schon abgearbeitet
worden ist...
Und mein "Codemonster" hat das alles und ist trotzdem schneller und
kürzer als das, was du da bei Attila rumgeändert hast.
Aber das ist ein Irrtum der schon immer rumgeistert - kürzeren
C-code gleichzusetzen mit kürzeren und schnelleren ASM-Code.
Schneller als mit den von mir geposteten Codeschnipsel geht es nur
mit if-Abfragen, aber auch dann nur unwesentlich.
> Was soll an dem Array nicht gut sein? Einen Zeiger+Index auf ein (const> char) Array im ROM kriegt der Compiler sicher mit ein paar Befehlen> gebacken, und dann ist es maschinentechnisch nur noch eine einzige> Vergleichsoperation und ein bedingter Sprung, nicht womöglich 6 davon.
Aha.
Nur packt man die Arraydeklaration nicht in die ISR rein, sondern macht
das ausserhalb.
Aber lerne fleissig weiter, eines Tages wirst du es auch verstehen...
Marc V. schrieb:> Erstens ist mein "Codemonster" wenn nicht kürzer, dann bestimmt nicht> länger als deine bzw. Attila's Lösung.> Und schneller ist es auf jeden Fall.
Das glaube ich erst, wenn ich den erzeugten ASM-Code sehe.
Leider benutze ich keine Attinys und habe dehalb auch nicht den Compiler
installiert, um es selbst zu überprüfen.
Marc V. schrieb:> Und du bzw. Attila hast nicht mal eine Prüfung auf Zeilenende,> Bufferüberschreitung, ob die vorige GPS-Meldung schon abgearbeitet> worden ist...
Meine Absicht war nicht, mustergültigen und wasserdichten Code
abzuliefern, sondern das Prinzip zu zeigen, wie die empfangene
Zeichenkette erkannt werden soll.
Marc V. schrieb:> Nur packt man die Arraydeklaration nicht in die ISR rein, sondern macht> das ausserhalb.
Warum?
Das Array sollte im ROM abgelegt werden (deshalb "const") und muss nur
im Kontext der ISR gültig sein. Wenn der Compiler dafür Code in der ISR
selbst erzeugt, taugt er nichts...
Edit: ok, habe mal ein bisschen Google befragt, "const" alleine reicht
wohl nicht, um das Array ins ROM zu verlagern. Evtl. muss da noch so was
wie "PROGMEN" hin.
Thomas E. schrieb:> Das glaube ich erst, wenn ich den erzeugten ASM-Code sehe.
Dann compiliere es doch mal.
> Leider benutze ich keine Attinys und habe dehalb auch nicht den Compiler> installiert, um es selbst zu überprüfen.
Der TO benutzt auch keine ATTinys.
> Warum?
s.o.
> Meine Absicht war nicht, mustergültigen und wasserdichten Code> abzuliefern, sondern das Prinzip zu zeigen, wie die empfangene> Zeichenkette erkannt werden soll.
Hast du aber nicht, zumindest nicht richtig.
Und meine Absicht war es nicht, deinen Beitrag schlechtzumachen,
sondern nur dem TO aufzuzeigen dass kurzer C-Code nicht gleichzusetzen
ist mit kurzem ASM-Code.
Wie oben schon gesagt, mit if geht es am schnellsten und das sollte
in einer ISR schon wichtig sein.
switch ist nächstschnellere Variante, ist aber meistens übersichtlicher
und leichter anzupassen bzw. zu verändern als if.
Rechnen mit Arrays und zugehörigen Indexen gehört bestimmt nicht zu
den schnellsten Operationen. Man kann sich nur darauf verlassen, dass
der Compiler schlau genug ist, z.B. nach deinem Vergleich:
1
if(z>5)
die Register für gleich darauf folgenden Schreibvorgang nicht mit neuen
Werten zu laden, sondern die alten Werte zu behalten.
Ausserdem ist z als int deklariert, was die Sache noch zusätzlich
verlangsamt.
Marc V. schrieb:> Ausserdem ist z als int deklariert, was die Sache noch zusätzlich> verlangsamt.
Auf einem 8Bit AVR mit GCC wird doch int zu int8_t geschrieben, oder
täusche ich mich da?!
Marc V. schrieb:>> Leider benutze ich keine Attinys und habe dehalb auch nicht den Compiler>> installiert, um es selbst zu überprüfen.> Der TO benutzt auch keine ATTinys.
Ja, ich meinte "AVR" allgemein - ist aber wohl in Bezug auf das Thema
egal, um Tiny oder Mega.
Marc V. schrieb:> Rechnen mit Arrays und zugehörigen Indexen gehört bestimmt nicht zu> den schnellsten Operationen.
Sicher ist der Vergleich mit einer Konstanten direkt (cmpi-Befehl?)
schneller, als den Vergleichswert erst aus dem Flash holen zu müssen.
Aber in Deiner Variante hat man entweder 5 Vergleiche oder 5 cases (was
ungefähr auf das gleiche hinauslaufen müsste), die alle immer in der ISR
abgearbeitet werden müssen, bis der passende Case oder die passende
if-Bedingung gefunden wurde. Also muss man wohl mit 5x compare, branch
if (not) equal oder so, rechnen, macht min. 11 Befehle. um in den
passenden (default) Case-Zweig zu gelangen.
Beim Array muss nur einmal der Index auf die Startadresse addiert werden
(beim AVR wohl alles im Z-Register), dann kann er sich die Daten mit LPM
direkt aus dem Array holen, dann folgt schon direkt der Vergleich mit
den Daten, sollte also auf kaum mehr, als 5 oder 6 Befehle kommen.
Ich werde mir aber jetzt nicht extra AVR-Studio installieren, um das zu
überprüfen ;)
Thomas E. schrieb:> if-Bedingung gefunden wurde. Also muss man wohl mit 5x compare, branch> if (not) equal oder so, rechnen, macht min. 11 Befehle. um in den> passenden (default) Case-Zweig zu gelangen.
Ja, sind bei default case 5*3 Takte, ergibt 15 Takte oder 937.5ns.
Alle anderen Fälle sind nur schneller.
Und bei dir (Attila) wird aber 2 Mal geprüft, einmal auf ein Zeichen
aus "GPRMC," (mind. 8 Takte) und einmal auf z>5 (mind. 7 Takte).
Glaubst du, deine 15 Takte sind schneller als meine 15 Takte ?
Ganz abgesehen davon, dass die Abfrage:
Attila C. schrieb:> @Rainer: 1) Danke! 2) Tatsächlich? Diese ISR wäre so "überladen?"
Ja, finde ich schon.
Also da ist ja nur ein 'kleiner' Mikroprozessor am Werken.
Bei der ISR gilt meiner Meinung nach: So kurz wie möglich.
Ich hab' ein paar Jahre Programmiererfahrung.
Wenn Du einmal den Ringbuffer programmiert hast hast kannst Du den auch
für andere Projekte verwenden.
Marc V. schrieb:> und einmal auf z>5 (mind. 7 Takte).
Wieso sind das mindestens 7 Takte? Selbst wenn der Compiler blöd ist und
vergisst, daß er z schon in einem Register hat, kommt mir das zuviel
vor.
Und wenn Du schon den zusätzlichen Vergleich (z>5) bei mir in die
Zeitberechnung einrechnest, solltest Du aber auch Deine "if (gpsflag ==
0)" und "if(state > 0)" nicht unter den Tisch fallen lassen!
Marc V. schrieb:> Ganz abgesehen davon, dass die Abfrage: if (UDR1==desig[z])> z++;> else> z=0;>> immer in die Hose geht, nach z>5 sowieso...
Da ist was dran - wie gesagt, ging es mir nur um das Prinzip, die
Rx-Bytes mit dem Array zu vergleichen. Das lässt sich aber leicht
korrigieren, etwa so:
1
constchardesig[7]="GPRMC,";// von mir aus auch außerhalb der ISR...
Thomas E. schrieb:> Wieso sind das mindestens 7 Takte? Selbst wenn der Compiler blöd ist und> vergisst, daß er z schon in einem Register hat, kommt mir das zuviel> vor.
LOL.
Weil z als integer deklariert ist...
> Und wenn Du schon den zusätzlichen Vergleich (z>5) bei mir in die> Zeitberechnung einrechnest, solltest Du aber auch Deine "if (gpsflag ==> 0)" und "if(state > 0)" nicht unter den Tisch fallen lassen!
LOL.
Wenn wir schon bei Korinthen sind:
Was ist mit deinen " if (indata=='$') " ?
Unter den Tisch fallen lassen ?
Und damit das mal klar ist, mein Papa ist stärker als deiner !
Marc V. schrieb:> Erstens ist mein "Codemonster" wenn nicht kürzer, dann bestimmt nicht> länger als deine bzw. Attila's Lösung.
Naja - siehe unten! Ungefähr die doppelte Codegröße!
> Und schneller ist es auf jeden Fall.
LOL!
Um wieviel? 2 oder 3 Takte?
Wenn man noch den Fehler (z wird nicht incrementiert) korrigiert, ist
der Geschwindigkeitsvorteil dahin...
Original aus der .lss Datei kopiert:
1
void testfunc2(void)
2
{
3
uint8_t gpschar = UDR;
4
396a: 80 91 c6 00 lds r24, 0x00C6
5
if (gpsflag == 0) { // Falls nicht abgearbeitet, wird gar nicht erst reingesprungen...
6
396e: 90 91 0a 03 lds r25, 0x030A
7
3972: 91 11 cpse r25, r1
8
3974: 35 c0 rjmp .+106 ; 0x39e0 <testfunc2+0x76>
9
static uint8_t z = 0;
10
uint8_t state = 0;
11
switch(z)
12
3976: e0 91 08 03 lds r30, 0x0308
13
397a: e2 30 cpi r30, 0x02 ; 2
14
397c: 99 f0 breq .+38 ; 0x39a4 <testfunc2+0x3a>
15
397e: 28 f4 brcc .+10 ; 0x398a <testfunc2+0x20>
16
3980: ee 23 and r30, r30
17
3982: 41 f0 breq .+16 ; 0x3994 <testfunc2+0x2a>
18
3984: e1 30 cpi r30, 0x01 ; 1
19
3986: 59 f0 breq .+22 ; 0x399e <testfunc2+0x34>
20
3988: 16 c0 rjmp .+44 ; 0x39b6 <testfunc2+0x4c>
21
398a: e3 30 cpi r30, 0x03 ; 3
22
398c: 71 f0 breq .+28 ; 0x39aa <testfunc2+0x40>
23
398e: e4 30 cpi r30, 0x04 ; 4
24
3990: 79 f0 breq .+30 ; 0x39b0 <testfunc2+0x46>
25
3992: 11 c0 rjmp .+34 ; 0x39b6 <testfunc2+0x4c>
26
{
27
case 0x00:
28
if(gpschar != '$') z = 0;
29
3994: 84 32 cpi r24, 0x24 ; 36
30
3996: 21 f1 breq .+72 ; 0x39e0 <testfunc2+0x76>
31
3998: 10 92 08 03 sts 0x0308, r1
32
399c: 08 95 ret
33
break;
34
case 0x01:
35
if(gpschar != 'G') z = 0;
36
399e: 87 34 cpi r24, 0x47 ; 71
37
39a0: d9 f7 brne .-10 ; 0x3998 <testfunc2+0x2e>
38
39a2: 08 95 ret
39
break;
40
case 0x02:
41
if(gpschar != 'P') z = 0;
42
39a4: 80 35 cpi r24, 0x50 ; 80
43
39a6: c1 f7 brne .-16 ; 0x3998 <testfunc2+0x2e>
44
39a8: 08 95 ret
45
break;
46
case 0x03:
47
if(gpschar != 'R') z = 0;
48
39aa: 82 35 cpi r24, 0x52 ; 82
49
39ac: a9 f7 brne .-22 ; 0x3998 <testfunc2+0x2e>
50
39ae: 08 95 ret
51
break;
52
case 0x04:
53
if(gpschar != 'S') z = 0;
54
39b0: 83 35 cpi r24, 0x53 ; 83
55
39b2: 91 f7 brne .-28 ; 0x3998 <testfunc2+0x2e>
56
39b4: 08 95 ret
57
break;
58
default :
59
if (z > BUFFSIZE) { z=0; break; }
60
39b6: e1 32 cpi r30, 0x21 ; 33
61
39b8: 78 f7 brcc .-34 ; 0x3998 <testfunc2+0x2e>
62
if(gpschar == 0x0D) state = 255;
63
39ba: 8d 30 cpi r24, 0x0D ; 13
64
39bc: 11 f0 breq .+4 ; 0x39c2 <testfunc2+0x58>
65
else state = 1;
66
39be: 91 e0 ldi r25, 0x01 ; 1
67
39c0: 01 c0 rjmp .+2 ; 0x39c4 <testfunc2+0x5a>
68
case 0x04:
69
if(gpschar != 'S') z = 0;
70
break;
71
default :
72
if (z > BUFFSIZE) { z=0; break; }
73
if(gpschar == 0x0D) state = 255;
74
39c2: 9f ef ldi r25, 0xFF ; 255
75
else state = 1;
76
}
77
if(state > 0) {
78
gpsdata[z++]=gpschar;
79
39c4: 21 e0 ldi r18, 0x01 ; 1
80
39c6: 2e 0f add r18, r30
81
39c8: 20 93 08 03 sts 0x0308, r18
82
39cc: f0 e0 ldi r31, 0x00 ; 0
83
39ce: e0 5f subi r30, 0xF0 ; 240
84
39d0: fc 4f sbci r31, 0xFC ; 252
85
39d2: 80 83 st Z, r24
86
if (state == 255) gpsflag = 1; // main() setzt es wieder auf 0 nach Abarbeitung...
Thomas E. schrieb:> Wenn man noch den Fehler (z wird nicht incrementiert) korrigiert, ist> der Geschwindigkeitsvorteil dahin...z wird aber inkrementiert, genauer hinschauen.
Bei dir wird in der ISR nicht:
a) Auf Endzeichen geprüft
b) Das Ende der GPS-Daten signalisiert
c) Buffer Inhalt vom überschreiben geschützt
somit kann:
a) ISR nie wissen, ob ein GPS-Datensatz zu Ende ist - der Empfang
geht endlos weiter...
b) main() nie wissen, ob ein GPS-Datensatz empfangen worden ist -
es wird endlos gewartet...
c) Der alte Datensatz kann von neuen GPS-Daten überschrieben
werden oder, noch schlimmer, in der main() werden alte und neue
Daten gleichzeitig bearbeitet...
Lass es aber gut sein, das ist keine Raketenwissenschaft, es ist
absolut unnötig, hier irgendwelche Kenntnisse zu beweisen...
P.S.
Deine Routine ist besser, schneller und kürzer, ich bin raus,
jetzt OK ?
Marc V. schrieb:> z wird aber inkrementiert, genauer hinschauen.
Aber nicht an der richtigen Stelle - schau selber genau hin!
Ich will hier auch keine Kenntnisse beweisen, aber (sorry, mein
Eindruck) Deine etwas besserwisserische Art und Frechheiten wie diese:
> Aber lerne fleissig weiter, eines Tages wirst du es auch verstehen...
sind halt schon eine Vorlage...
Im Übrigen finde ich auch, daß das Thema hier genügend durch ist.
Schade eigentlich dass bei soviel Kompetenz das Ganze in einen
Schwanzvergleich ausarten muss!
Wie auch immer:
Ich habe mal wieder sehr viel gelernt und bedanke mich ganz herzlich bei
allen Beteiligten!