Hallo! Problem: an die UARTs gesendete Zeichen werden verschluckt Aufbau: ATmega2560, UART1: GPS-Empfänger, UART2: ich (Hyperterminal), jeweils interruptgesteuert, ISR saukurz Symptom: ATmega antwortet fleissig auf meine Eingabe übers Terminal. Wenn jedoch der GPS-Empfänger seine sekündlichen Quark abgibt, werden Zeichen, die ich ("gleichzeitig") per HT gesendet habe, teilweise verschluckt (kommen jedenfalls nicht im ATmega an). Vermutung: zwei Interrupts kollidieren, einer davon wird "wegignoriert" Frage: wie elegant lösen? Gruß: Simon
ISR noch saukürzer machen (Zeichen aus UART holen, in Buffer schreiben, fertig). Oliver
>Vermutung: zwei Interrupts kollidieren, einer davon wird "wegignoriert"
Wie kommst Du auf diese Vermutung? Und wie soll das denn gehen?
chick schrieb: > Wie kommst Du auf diese Vermutung? Und wie soll das denn gehen? Stelle mir vor, dass, während die eine ISR gerade ihren Dienst aufgenommen hat, die andere dazwischenfunkt und die erstere abbrechen muss. Wie das dann gehen soll: gar nicht. Merk ich ja bei mir. :) Dünne gerade meine ISR aus....
Ausdünnen ist der ganz falsche Ansatz. Luafzeiten bleiben immer, wenn auch sehr kurz. Infomier Dich lieber was der Prozessor wirklich macht, wenn zwei Interrupts auftauchen. Vermuten hat in der E-Technik nix verloren, es gibt Datenblätter, Tutorials, Applikationen. Da wird doch wohl was zu finden sein. Würd Dich gern beraten, kann mich aber nur bei den PICs aus.
Simon schrieb: > chick schrieb: >> Wie kommst Du auf diese Vermutung? Und wie soll das denn gehen? > > Stelle mir vor, dass, während die eine ISR gerade ihren Dienst > aufgenommen hat, die andere dazwischenfunkt und die erstere abbrechen > muss. Nicht beim AVR in einer ISR Standardkonfiguration. Das Auftreten des zweiten Interrupt-Auslösers wird registriert und die ISR wird angestossen, wenn die erste fertig abgearbeitet wurde. In einer UART dauert das Übertragen eines Zeichens wesentlich länger als das Abarbeiten der zugehörigen ISR (normalerweise. Wenn man sich an die Regel hält: nur das in einer ISR machen, was unbedingt notwendig ist - nicht mehr), so dasss das überhaupt kein Problem sein dürfte.
Und wie sieht das beim Senden aus? Wenn der Controller ans Terminal Daten (Kursorpositionierungs- und Anzeigestrings) schickt und dabei das GPS seinen Senf abgibt, kommt es vor, dass Zeichen auf dem Terminal dargestellt werden, die eigentlich als Steuerzeichen verstanden und nicht angezeigt werden sollen. Nimmt die ISR des Empfangens auch Rücksicht und wartet, dass das Senden eines Zeichend abgeschlossen ist?
Simon schrieb: > Und wie sieht das beim Senden aus? JEDE ISR wird komplett abgeschlossen, ehe die nächste arbeiten kann. Egal ob Timer, ADC, UART, Pinchange, externer Interrupt, etc. etc. Wenn eine ISR aufgerufen wird, werden die Interrupts global gesperrt und mit dem Ende einer ISR werden sie wieder freigegeben. (Es sei denn du pfuscht da rein und machst in der ISR selber einen sei(), was in den meisten Fällen eine ganz schlechte Idee ist)
@ Simon (Gast) >Vermutung: zwei Interrupts kollidieren, einer davon wird "wegignoriert" Eher nicht, ich tippe auf schlechte, blockierende Programmierung, vielleicht sogar mit Delays, bähh. >Frage: wie elegant lösen? Siehe Interrupt und Multitasking. MfG Falk
Falk Brunner schrieb: > @ Simon (Gast) > >>Vermutung: zwei Interrupts kollidieren, einer davon wird "wegignoriert" > > Eher nicht, ich tippe auf schlechte, blockierende Programmierung, > vielleicht sogar mit Delays, bähh. Das denke ich auch. Alleine der Terminus > Dünne gerade meine ISR aus.... In einer UART ISR gibt es normalerweise nicht viel zum ausdünnen: Zeichen aus UDR holen und ab damit in den Ringbuffer. Eventuell noch ein Flag setzen, dass ein \r oder \n reinkam, dann braucht die Hauptschleife sich nicht dauernd das letzte empfangene Zeichen ansehen. Aber summa summarum nichts was wesentich länger als 40 oder 50 CPU Takte dauert und damit für die restliche Funktion der UART ziemlich uninteressant.
Hi! Falls du ein Oszi hast: Beim Eintritt in die ISR einen unbenutzten Pin auf HIGH setzen und beim Verlassen der ISR auf LOW. Idealerweise für jede ISR einen eigenen Pin. Oszilloskope mit 16 Digitalkanäle sind echt eine tolle Erfindung! Gruß PP
Wie groß ist dein Empfangs-Buffer für den GPS-UART und wie viele Zeichen sendet der GPS-Empfänger maximal? Wenn der Buffer zu klein ist wird der AVR im Normalfall aktiv warten und so werden auch nicht die Bytes von zweiten UART abgeholt.
Frage zur Kürze einer ISR: ist die Beispiel-USART_RX_vect, welche im Tutorial nachzulesen ist, ungeeignet lang oder in Ordnung? ISR (USART1_RX_vect) { unsigned char nextChar; nextChar = UDR1; if (uart1_str_complete == 0) { if( nextChar != '\n' && nextChar != '\r' && uart1_str_count < UART1_MAXSTRLEN-1) { uart1_string[uart1_str_count] = nextChar; uart1_str_count++; } else { uart1_string[uart1_str_count] = '\0'; uart1_str_count = 0; uart1_str_complete = 1; } } }
Diesmal ist mein Kopf am Glühen, ich suche einen Denkfehler: Ich verwende die o.g. ISR und in der main folgende Schleife: while(1) { send_GSM ("at"); //sende an GSM-Modul "at" (gefolgt von <CR>) if(uart1_str_complete == 1) //wenn die ISR einen vollständigen String hat { uart2_puts (uart1_string); //ans Terminal senden uart1_str_complete = 0; //und von vorn } Das Modul antwortet auch artig mit "at<CR><CR><LF>OK<CR><LF>". Mein Programm "sieht darin aber nur den String "at" und nicht das (viel wichtigere) "OK". Sieht jemand meinen Fehler?
Simon schrieb: > Sieht jemand meinen Fehler? Du sendest zuerst und stellst dann erst uart1_str_complete auf 0. Das hat zur Konsequenz, daß deine ISR alle während dieses Sendevorgangs ankommenden Zeichen ignoriert, da sie nichts tut, wenn usart1_str_complete 0 ist.
Simon schrieb: > Sieht jemand meinen Fehler? Ja. Mal dir auf, was da wann in welcher Reihenfolge passiert, dann kommst du auch dahinter. Das ist mal eine gute Übung zum Thema "zwei Sachen gleichzeitig durchführen". Oliver
Du hast es dir nicht aufgemalt. Das war nur der eine Fehler, den zweiten musst du noch suchen. Man sollte auch kopierte Sourcen verstehen, bevor man sie verwendet, selbst (oder gerade) wenn sie aus Tutorials stammen. Oliver
Lautmalerei der ISR: Zeichen reingeholt. Wenn noch Platz, und kein LF und kein CR und mehr als ein Zeichen Platz denn Zeichen anfügen und hochzählen. Ansonsten letztes Zeichen NUL und String fertig melden und Zähler zurücksetzen. Malung der Schleife: Wenn ein String vollständig, dann Zähler nullen String senden von vorn. Falsch verstanden?
Mals dir richtig auf. Du hast 2 Uarts, auf denen gleichzeitig etwas passiert. Und gleichzeitig heisst wirklich gleichzeitig. Du hast aber ein Programm, welches nur eine Sache gleichzeitig machen kann. Überleg dir, was mit UDR, nextchar, und vor allem in uart1_string passiert. Oliver
Oliver schrieb: > Das ist mal eine gute Übung zum Thema "zwei Sachen > gleichzeitig durchführen". Wo (zum Teufel, Entschuldigung) werden in diesem Miniprogramm zwei Dinge gleichzeitig gemacht?!
Also: während mit UART2 gerade mal gesendet wird flattern in der ISR der UART1 fleissig Zeichen rein. Das sollte doch gehen (lt. K-H Buchegger wartet ein Interrupt auf den anderen). Mglw. ist der eine String ja schon wieder fertig während der andere noch gar nicht fertig gesendet ist- ist es das?
Simon schrieb: > Mglw. ist der eine String ja schon wieder fertig während der andere noch > gar nicht fertig gesendet ist- ist es das? interessiertnachfrag Falls: was tun? Interrupts abschschalten für kurze Zeit?
Nein. sichr nicht. Es sollte doch moeglich sein, zwei Interrupts parallel laufen zu lassen. Solange die verwendeten Variablen unabhaenig sind, sollten sich die beiden Interrupts nicht stoeren. Jeder Interupt hat seinen eigenen Buffer und seine eigenen Variablen dazu.
Simon schrieb: > Lautmalerei der ISR: [ ... textuelle Beschreibung eines Algorithmus ] Wikipedia: << Die Onomatopoesie (auch Onomatopöie, von griech. ὄνομα: ónoma: „Name“, und ποίησις: poíēsis: hier „Erschaffung, Herstellung“, folglich ὀνοματοποιεῖν: onomatopoiein: „einen Namen prägen, benennen“), deutsch Lautmalerei, Tonmalerei, Schallwort, ist die Nachahmung eines Naturlautes oder eines sonstigen außersprachlichen akustischen Phänomens durch die klanglich als ähnlich empfundene Lautgestalt eines sprachlichen Ausdrucks >> müßtest du die laut-gemalerte ISR dann nicht als .wav oder .mp3 Datei anhängen, und sich das anhören wie die Piepstöne von einer C64 Datasette?
Wegstaben Verbuchsler schrieb: > müßtest du die laut-gemalerte ISR dann nicht als .wav oder .mp3 Datei > anhängen, und sich das anhören wie die Piepstöne von einer C64 > Datasette? Das erinnert mich an das erste Lied, was ich je auf einem PC gehört habe,als nämlich -nach sehrsehr langer Ladezeit- das 1541-II C64-Floppy tatsächlich Karma Chameleon vibrierte. Gut, habe ich halt nicht lautgemalt sondern meine Malung aufgeschrieben.
Oliver schrieb: > Überleg dir, was mit UDR, nextchar, und vor allem in uart1_string > passiert. Habe überlegt und sehe das Prblem nicht.
Also... ich stehe wirklich auf dem Schlauch. Vermutlich reichen meine Kenntnisse nicht aus, den Fehler zu erkennen. Wäre arg dankbar wenn mir jemand den Fehler zeigen würde. Habe gemalt und geschrieben und komme stets aufs gleiche hinaus: alles supi. Würde jemand an einer Frage aus meinem Fachgebiet verzweifeln, ich würde sie ihm auch irgendwann sagen. Herzlichst- Simon
Die beiden UART laufen in Hardware völlig unabhängig von deinem Programm, und empfangen un senden passiert da gleichzeitig. Die zugehörigen ISR's sind kurz genug (vermutlich, du zeigst ja nie den ganzen Code), daß die abwechselnd die beiden UARTS bedienen können. Aber was passiert mit den Daten? Oliver
Damit es noch etwas klarer wird: Simon schrieb: > während mit UART2 gerade mal gesendet wird flattern in der ISR der UART1 > fleissig Zeichen rein. > Das sollte doch gehen (lt. K-H Buchegger wartet ein Interrupt auf den > anderen). Das geht, aber wo flattern die Daten hin? Und wie sehen diese aus? Wie viele Strings kann dein Programm zur weiteren Verarbeitung abspeichern? Was kann hier alles passierern: > uart2_puts (uart1_string); //ans Terminal senden wenn gleichzeitig dein GPS sendet? Was passiert, wenn, wie in deinem GPS-String, mehrere CFs/LFs nacheinander kommen? Fragen über Fragen ;) Oliver
Nur mal kurz um die Dimensionen klarzustellen: uC = schnell UART = langsam GPS = langsamer User = am langsamsten Kurz: da ist ein Fehler im weitgehend unbekannten Programm. So ein paar nach und nach auftretende UART Interrupts steckt jeder uC locker weg... Simon schrieb: > Wäre arg dankbar wenn mir jemand den Fehler zeigen würde. Die Fehlerursache ist, dass du den Parser zur Hälfte in die ISR gepackt hast. Für eine exakte Analyse wäre arg hilfreich, wenn du dein aktuelles Programm zeigen würdest...
Gibts nen Kochrezept um die vielen Fragen zu umkochen? In etwa, den kompletten String, sobald er fertig ist, zu kopieren und mit der Kopie weiterzuarbeiten damit die ISR das Original neu beschreiben kann? War so meine Idee..
Mein Miniprogramm: int main(void) { while(1) { if(uart1_str_complete == 1) //GSM { uart1_str_complete = 0; uart2_puts (uart1_string); } } ISR (USART1_RX_vect) //GSM { unsigned char nextChar; nextChar = UDR1; if (uart1_str_complete == 0) { if( nextChar != '\n' && nextChar != '\r' && uart1_str_count < UART1_MAXSTRLEN-1) { uart1_string[uart1_str_count] = nextChar; uart1_str_count++; } else { uart1_str_complete = 1; uart1_string[uart1_str_count] = '\0'; uart1_str_count = 0; } } } void uart1_putc(unsigned char c) { while (!(UCSR1A & (1<<UDRE1))) { } UDR1 = c; } void uart1_puts (char *s) { while (*s) { uart1_putc(*s); s++; } uart1_putc('\r'); }
@ Simon (Gast) >Mist, hätte natürlich die uart2_puts und uart2_putc sein sollen. Lies mal was über Netiquette!!! Man poste IMMER VOLLSTÄNDIGEN Originalquellcode, NIEMALS was schnell hingeschriebenes!
1 | while(1) |
2 | {
|
3 | send_GSM ("at"); //sende an GSM-Modul "at" (gefolgt von <CR>) |
4 | |
5 | if(uart1_str_complete == 1) //wenn die ISR einen vollständigen String |
6 | hat
|
7 | {
|
8 | uart2_puts (uart1_string); //ans Terminal senden |
9 | uart1_str_complete = 0; //und von vorn |
10 | }
|
uart1_str_complete ist eigentlich ein etwas fälschlicher Name. Eigentlich sollte das uart1_line_complete heissen. Und immer schön drann denken: Die ISR meldet dir, wenn eine ZEILE fertig übertragen wurde. Auf den String "AT\n" antwortet das Modem aber mit 2 Zeilen! Und zu dem Zeitpunkt, an dem du das erste mal "AT" zum Modem schickst, kann es durchaus eine Zeitlang dauern, bis das Modem seinerseits mit dem "AT\nOK\n" antwortet. Was macht dein Programm in der Zwischenzeit? Und auch drann denken: Ein uart2_puts braucht seine Zeit, bis er etwas ausgegeben hat. Zb. das "AT" welches in der ertsen Antwortzeile des Modems kommt. Du gibst dieses AT aus, aber in der Zwischenzeit überträgt das Modem schon die zweite Zeile der Antwort, das "OK", welches in welchen Variablen abgelegt wird? (werden würde, wenn uart1_str_complete richtig stehen würde) Du willst Dinge 'gleichzeitig' machen? Gut. Dann musst du aber in deinem Programm an jeder einzelnen Stelle berücksichtigen und bedenken, was in den jeweils anderen Programmpfaden alles passieren könnte. Im Moment tust du das nicht. Deine Denkweise geht immer noch seriell: Zuerst passiert das, dann passiert das.
String kopieren ist nicht sinnvoll, ist nur rumgedoktore. Wie lange dauert denn die Verarbeitung?
Simon schrieb: > Gibts nen Kochrezept um die vielen Fragen zu umkochen? In etwa, den > kompletten String, sobald er fertig ist, zu kopieren und mit der Kopie > weiterzuarbeiten damit die ISR das Original neu beschreiben kann? > War so meine Idee.. Das wäre zb gar keine sooo schlechte Idee. (Auch wenn chick das anders sieht)
Karl Heinz Buchegger schrieb: > Auf den > String "AT\n" antwortet das Modem aber mit 2 Zeilen! Nee. Viel schlimmer... Das Modem antwortet > "at<CR><CR><LF>OK<CR><LF>". Das ergibt in seinem Programm 5 Zeilen, wovon 3 ziemlich kurz sind... Oliver
Sitz leider grad nicht am "Arbeitsplatz" (sondern im Schafstall) und kanns nicht testen, aber sollte ich denn in die ISR eine Abfrage einbauen, ob eine vermeintlich fertige String-Zeile nur aus CR bzw LF besteht und diese verwerfen? Ist es das?
Überlass alle Auswertungen dem Hauptprogramm. Da dein GPS ja nun auch noch andere Antworten schicken kann, und dein Programm irgendwann einmal mehr machen wird, als die empfangenen Strings einfach wieder zu senden, brauchst du ein Konzept, um eine unbekannte Anzahl von Strings empfangen und für die weitere Bearbeitung Speichern zu können. du
@ Simon (Gast) >einbauen, ob eine vermeintlich fertige String-Zeile nur aus CR bzw LF >besteht und diese verwerfen? Ist es das? Nein, das ist nur eine kleine Verbesserung. Dein Problem ist u.a. das blockiernde Senden der String. Während dieser Zeit ist deine CPU tot für alles andere. Lösung? Strings kopieren und mit TX-ISR senden. Oder gleich ein FIFO nutzen. MFG Falk
Simon schrieb: > Das Modul antwortet auch artig mit "at<CR><CR><LF>OK<CR><LF>". Du hast ECHO eingeschaltet, deshalb "siehst" Du alles alles, was Du sendest, nochmal als Echo. Ich nehme "at<CR><CR><LF>OK<CR><LF>" mal auseinander: Du sendest at<CR> Du siehst: at<CR> # das ist das Echo Du siehst: <CR><LF> # das ist der Zeilenvorschub, vom Modem generiert. Du siehst: OK<CR><LF> # das ist die Antwort OK mit erneutem Zeilenvorschub Du würdest Dir das Leben einfacher machen, wenn Du das Echo abschaltest. Das ist nur sinnvoll bei Terminal-Verbindungen, damit der Mensch, der da rumtippt, auch sieht, was er tippt. Bei rechnergesteuerten Anwendungen ist das nicht sehr sinnvoll. Bei Modems kann man das echo mit ATE0<CR> abstellen. Am besten speicherst Du diese Einstellung im Modem ab. Die Antworten reduzieren sich dann auf das wesentliche, nämlich das, was du auch auswerten willst. Gruß, Frank
Falk Brunner schrieb: > Dein Problem ist u.a. das > blockiernde Senden der String. Während dieser Zeit ist deine CPU tot für > alles andere. Na ja, ganz tot nicht. Die Receive-ISR kann schon, wenn sie dran ist. Und das reicht in der Regel, um in einen Ringpuffer zu schreiben. Oliver
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.