Forum: Mikrocontroller und Digitale Elektronik UARTS am Glühen?


von Simon (Gast)


Lesenswert?

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

von Oliver (Gast)


Lesenswert?

ISR noch saukürzer machen (Zeichen aus UART holen, in Buffer schreiben, 
fertig).

Oliver

von chick (Gast)


Lesenswert?

>Vermutung: zwei Interrupts kollidieren, einer davon wird "wegignoriert"

Wie kommst Du auf diese Vermutung? Und wie soll das denn gehen?

von Simon (Gast)


Lesenswert?

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....

von chick (Gast)


Lesenswert?

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.

von Karl H. (kbuchegg)


Lesenswert?

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.

von Simon (Gast)


Lesenswert?

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?

von Karl H. (kbuchegg)


Lesenswert?

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)

von Falk B. (falk)


Lesenswert?

@  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

von Karl H. (kbuchegg)


Lesenswert?

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.

von STK500-Besitzer (Gast)


Lesenswert?

Die USART-Trolle streiken...

von Simon (STK-600-Besitzer) (Gast)


Lesenswert?

STK500-Besitzer schrieb:
> Die USART-Trolle streiken...

Wie bitte?

von Paulchen Panther (Gast)


Lesenswert?

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

von B.A. (Gast)


Lesenswert?

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.

von Simon (Gast)


Lesenswert?

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;
    }
  }
}

von Falk B. (falk)


Lesenswert?

Ist vollkommen OK.

von Simon (Gast)


Lesenswert?

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?

von Rolf M. (rmagnus)


Lesenswert?

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.

von Oliver (Gast)


Lesenswert?

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

von Simon (Gast)


Lesenswert?

Klingt plausibel. Habs umgedreht aber immernoch der gleiche Effekt!

von Oliver (Gast)


Lesenswert?

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

von Simon (Gast)


Lesenswert?

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?

von Simon (Gast)


Lesenswert?

Streiche "Zähler nullen", setze "Komplettmelder nullen"

von Oliver (Gast)


Lesenswert?

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

von Simon (Gast)


Lesenswert?

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?!

von Simon (Gast)


Lesenswert?

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?

von Simon (Gast)


Lesenswert?

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?

von Purzel H. (hacky)


Lesenswert?

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.

von Wegstaben V. (wegstabenverbuchsler)


Lesenswert?

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?

von Simon (Gast)


Lesenswert?

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.

von Simon (Gast)


Lesenswert?

Oliver schrieb:
> Überleg dir, was mit UDR, nextchar, und vor allem in uart1_string
> passiert.

Habe überlegt und sehe das Prblem nicht.

von Simon (Gast)


Lesenswert?

Ists wirklich so dass jeder "den Fehler" sieht- nur ich nicht?

von Simon (Gast)


Lesenswert?

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

von Oliver (Gast)


Lesenswert?

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

von Oliver (Gast)


Lesenswert?

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

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

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...

von Simon (Gast)


Lesenswert?

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..

von Simon (Gast)


Lesenswert?

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');
}

von Simon (Gast)


Lesenswert?

Mist, hätte natürlich die uart2_puts und uart2_putc sein sollen.

von Karl H. (kbuchegg)


Lesenswert?

Zeig doch einfach ein vollständiges Minimalprogramm!

von Falk B. (falk)


Lesenswert?

@  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!

von Karl H. (kbuchegg)


Lesenswert?

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.

von chick (Gast)


Lesenswert?

String kopieren ist nicht sinnvoll, ist nur rumgedoktore.

Wie lange dauert denn die Verarbeitung?

von Karl H. (kbuchegg)


Lesenswert?

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)

von Falk B. (falk)


Lesenswert?

Beitrag "Re: UARTS am Glühen?"

Steht alles haarklein in den Links. Sollen wir noch vorlesen?

von Oliver (Gast)


Lesenswert?

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

von Simon (Gast)


Lesenswert?

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?

von Oliver (Gast)


Lesenswert?

Ü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

von Falk B. (falk)


Lesenswert?

@  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

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

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

von Oliver (Gast)


Lesenswert?

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
Noch kein Account? Hier anmelden.