Forum: Compiler & IDEs AtMega16 UART mit Interrupt Problem


von M. V. (bmtil)


Angehängte Dateien:

Lesenswert?

Hallo,
nachdem ich in letzen Paar Wochen mich vertsärkt mit µC-Programmierung 
auseinandergesetzt hab und im Rahmen meines Fachpraktikums schon ein 
paar kleinere Programme geschrieben hab (hier vielen Dank an 
mikrocontroller.net, wirklich hervorragende Seite, wie Forum) bin ich 
auf ein kleines Problem mit meiner UART gestoßen (natuerlich hab ich 
einige Teile des Codes aus dem mikrocontroller Tutorial).
Das Programm soll folgendes machen:
wenn ich per HTerm sag: "LEDaus" soll die LED ausgehen, und der µC soll 
mir sagen "LED ist aus" (also nicht unbedingt ein Echo, ein anderer Text 
waere besser). Natürlich soll das ganze auch gehen wenn ich in HTerm 
sag: "LEDein", soll sie sicherlich angehen, und ich soll wieder einen 
Text sehen vom µC dass sie an ist. Momentan geht es nur dass ich ihr 
sagen kann "beliebiger text" , LED geht dann aus. Ich kann im Interrupt 
irgendwie nicht einstellen dass sie bei einer expliziten Eingabe 
ausgehen soll. Das ist momentan das größte Problem (dass ich halt: if 
(uart_str_complete == 1)  ) und es anders irgendwie gerade nicht geht, 
bzw. ich was uebersehe.
Eine Uart ohne Interrupts die sowas koennen muss ist recht simpel, hab 
ich auch schnell hinbekommen, aber da durch dass sie nur einzelne 
Zeichen senden kann ist es halt bloed.
Ich hab mal meinen Quellcode als .txt angehangen und hoff dass mir 
weitergeholfen wird.
Mal gucken ob ichs heute hinkrieg und vielen Dank im voraus.

von Oliver (Gast)


Lesenswert?

>if ( uart_str == "LEDein")

C hat es nicht so mit Strings. Die Standardempfehlung in solchen Fällen 
ist daher immer die selbe:
Kauf dir bitte ein Buch zur Programmiersprache C. Als Kompromiss geht 
auch ein Online-Tutorial. Ohne gewisse Grundlagen wird das sonst nichts.

>LED_PORT &= (0<<LED_PORTPIN);

Das Kapitel zur Bitmanipulation hier im Artikelbereich solltest du dir 
auch nochmal ansehen.

Oliver

von M. V. (bmtil)


Lesenswert?

Eine wunderprächtigere Antwort haette ich mir nie im Leben vorstellen 
koennen.
Latuernich weiss ich dass C es "nicht so mit strings hat", dennoch 
aendert es nichts an der Tatsache dass an diesem einem bloeden 
Stueckchen Code gerade haenge, in welchem ich zu sagen versuche dass die 
LED ausgehen soll nicht wenn irgendwas gesagt wird, sondern was genaues.
Grueße.

PS. zum Thema Buch/Online Tutorial. Learning bei doing ist das Motto, 
das was ich bis jetzt an lernmaterialö fuer C gelesen hab, war 
irgendwelcher kryptischer Kram, der ungklaublich schwer verdaulich ist, 
fuer mich zumindest.

von Oliver (Gast)


Lesenswert?

Mikhail V. schrieb:
> Latuernich weiss ich dass C es "nicht so mit strings hat",

Nix weisst du...

http://www.c-howto.de/tutorial-strings-zeichenketten.html
Lesen, mit Unterkapiteln.

Mikhail V. schrieb:
> Learning bei doing ist das Motto,

Du bist nicht der erste, der das versucht, aber du bist auch nicht der 
erste, bei dem das nicht funktionieren wird.

Oliver

von M. V. (bmtil)


Lesenswert?

Ok, jut, mal anders gefragt:

Warum funktioniert dieser Code in der ISR (halt aus der ISR aus der 
angehangenen .txt Datei) nicht:
1
 if ( uart_str == "LEDaus")    //wenn µC "LEDaus" bekommt, dann
2
 {
3
      LED_PORT |= (1<<LED_PORTPIN);    //LED soll ausgehen
4
      uart_puts("aus");
5
 }

Danke, grueße

von XXX (Gast)


Lesenswert?

Hallo

Da kann man nur Oliver wiederholen:
C hat es nicht so mit Strings.

Gruß
Joachim

von M. V. (bmtil)


Lesenswert?

Ok, mir ist durchaus bewusst dass ich mit den oben erwaehnten Variante 
der if-Bedinung nur ein Zeichen aus dem String rauslese.
wenn ich statt der oberen if-Bedienung, diese hier reinhacke:
1
if (uart_str [0] == 'a')
2
{     LED_PORT |= (1<<LED_PORTPIN);    //LED soll ausgehen
3
      uart_puts("aus");
4
}
passiert folgendes:
die LEd geht aus, im Hterm Recieve Fenster erscheint zwei (!) mal das 
"aus".
und das bringt mich so langsam zur weissglut.

von Klaus F. (kfalser)


Lesenswert?

XXX schrieb:
> C hat es nicht so mit Strings.

Um es deutlicher zu sagen :
Man kann Strings in C nicht auf diese Art vergleichen.

Und bitte: Lerning by doing ist schön und gut, aber doing ohne zu wissen 
was man tut bringt es halt auch nicht...

von M. V. (bmtil)


Lesenswert?

Ok, wie kann man Strings in C vergleichen?
Muss ich das tatsaechlich Schritt fuer Schritt mit der for-Schleife 
erledigen?

Lustigerweise mecker der Compiler (AVR Studio 5) bei beiden if - 
Bedienungen nicht.
hab mir jetzt zig mal die Erklärungen zu der UART String senden und zu 
den Strings in C allg. durchgelesen, aus verschiedenen Quellen und es 
trotzdem nicht verstanden.
Zur vollstaendigen verwirrung fuerht dann die Tatsache dass das ganze 
ohne Interrupts mit den einfachen "UART_Recieve", "putc" und "puts" 
Funktionen wunderbar funktionier hat, genau so wie ich das wollte.

Grueße.

von Peter D. (peda)


Lesenswert?

Klaus Falser schrieb:
> Man kann Strings in C nicht auf diese Art vergleichen.

Und man muß sich auch erstmal aus dem Empfangenen einen String basteln.
Z.B. alle Bytes in ein Array schreiben (Überlauf abfangen!).
Und dann kann man das CR+LF am Ende durch ein '\0' ersetzen und ein Flag 
setzen, daß nun ein String da ist.
Dann erst kann man ihn auswerten (parsen).


Peter

von M. V. (bmtil)


Lesenswert?

Erste wirklich hilfreiche Antwoirt, vielen Dank, Peter.

Ich werd mal schauen was sich da machen laesst.
Eine Frage noch:
das Zusammensetzen der einzelnen "Stringbytes" zum String muss in der 
ISR erfolgen, oder?

von Chris (Gast)


Lesenswert?

Hier ist ein Beispiel für Interrupt Betrieb

http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial/Der_UART#Empfangen_.28RX.29

Da wird auch der String in der ISR zusammen gesetzt.

von Oliver (Gast)


Lesenswert?

Mikhail V. schrieb:
> hab mir jetzt zig mal die Erklärungen zu der UART String senden und zu
> den Strings in C allg. durchgelesen, aus verschiedenen Quellen und es
> trotzdem nicht verstanden.

Mikhail V. schrieb:
> Ok, wie kann man Strings in C vergleichen?

Ich weiß ja nicht, was du gelesen hast, aber zum Thema Strings in C ist 
da mit Sicherheit nichts dabei gewesen.

Oliver schrieb:
> http://www.c-howto.de/tutorial-strings-zeichenketten.html
> Lesen, mit Unterkapiteln.

Oliver

von M. V. (bmtil)


Lesenswert?

Chris schrieb:
> Hier ist ein Beispiel für Interrupt Betrieb
>
> http://www.mikrocontroller.net/articles/AVR-GCC-Tu...
>
> Da wird auch der String in der ISR zusammen gesetzt.

Genau dieses Beispiel hab ich fuer meine ISR verwendet. Und genau in 
dieser ISR funktioniert das was ich will nicht.
Nun wenn dort schon die Bytes zum String zusammengesetzt werden, und 
zwar hier:
1
if( nextChar != '\n' &&
2
        nextChar != '\r' &&
3
        uart_str_count < UART_MAXSTRLEN - 1 ) {
4
      uart_string[uart_str_count] = nextChar;
5
      uart_str_count++;
6
    }

Versteh ich nicht wieso ich dann nicht einfach sagen kann:
"Empfange "xyz", dann setz es eben durch die obere if-Bedienung (aus dem 
Tutorial) zusammen, schalte die bloede LED aus, und sag mir dass die 
bloede LED aus ist"

Grueße.

von Chris (Gast)


Lesenswert?

Hier wird aber nur ein Zeichen überprüft und dann dem String 
hinzugefügt.
Du, so habe ich es verstanden, willst aber den ganzen String 
vergleichen.

Also musst du erst mal mit der ISR den String empfangen, zusammen 
setzten und dann kannst ihn mit der Funktion strcmp vergleichen.
Beschreibung sihe unten.


///
Mit strcmp (String Compare) können wir zwei Strings vergleichen. Der 
Rückgabewert kann hierbei folgende Werte haben:

    * 0 die Strings sind gleich
    * 1 das erste ungleiche Zeichen in str1 ist größer als in str2
    * -1 das erste ungleiche Zeichen in str1 ist kleiner als in str2

///

Dann musst den Rückgabewert auswerten und dann weißt du ob du den 
gewünschte String empfangen hast oder nicht.

von Klaus W. (mfgkw)


Lesenswert?

Mikhail V. schrieb:
> Erste wirklich hilfreiche Antwoirt

nein, das ist falsch.

Ohne C-Gruindlagen kommst du nicht weiter, und in C Strings mit == zu 
vergleichen, geht nun mal nicht aus ganz elementaren Gründen.

Die ersten Atworten sind sehr hilfreich bzw. wären es, wenn du sie
verstehen und akzeptieren würdest.
Man kann die Wahrheit verleugnen, darf das dann aber nicht den
Boten vorwerfen, die sie mitteilen wollen.

von Karl H. (kbuchegg)


Lesenswert?

Oliver schrieb:
> Mikhail V. schrieb:
>> Latuernich weiss ich dass C es "nicht so mit strings hat",
>
> Nix weisst du...
>
> http://www.c-howto.de/tutorial-strings-zeichenketten.html
> Lesen, mit Unterkapiteln.

Hier gibt es auch eine 'Kurzeinführung' über das Allernotwendigste von 
Strings

String-Verarbeitung in C

> PS. zum Thema Buch/Online Tutorial. Learning bei doing ist das Motto,

Gutes Motto!
Ein Buch nur zu lesen, bringt nichts. Man muss es durcharbeiten! Genau 
aus dem Grund hat ein Buch nach jedem Kapitel Übungen, die das gelesene 
vertiefen. Und genau an diesem Punkt kommt dann "Learning by doing" ins 
Spiel. Beim Bearbeiten der Übungen eines Kapitels.
Auch klar sollte sein, dass man nicht mitten drinn anfangen darf sondern 
sich von vorne nach hinten durcharbeitet. Spätere Kapitel bauen auf den 
vorderen Kapitel auf. Und wenn man die nicht intus hat, versteht man nur 
noch Bahnhof.

Du bist nicht der Erste dem das so geht und du bist nicht der Letzte, 
der meint, bei ihm wäre das alles anders. Und allen gemeinsam ist, dass 
sie scheitern.

von Oliver (Gast)


Lesenswert?

Chris schrieb:
> Also musst du erst mal mit der ISR den String empfangen, zusammen
> setzten

Ein kurzer Blick in die ganz oben anghängte Datei zeigt, daß das in 
seiner ISR alles schon drin ist. Auch das passende Flag 
uart_str_complete gibt es da schon.

Das jetzt in main() zusammen mit den passenden Stringfunktionen richtig 
ausgewertet, dann läufts.

Oliver

von Karl H. (kbuchegg)


Lesenswert?

Oliver schrieb:
> Chris schrieb:
>> Also musst du erst mal mit der ISR den String empfangen, zusammen
>> setzten
>
> Ein kurzer Blick in die ganz oben anghängte Datei zeigt, daß das in
> seiner ISR alles schon drin ist. Auch das passende Flag
> uart_str_complete gibt es da schon.

Ein kurzer Blick zeigt aber auch, dass er nicht verstanden hat, was der 
Vorgabecode wann und warum macht.

von M. V. (bmtil)


Lesenswert?

Oliver schrieb:
> Das jetzt in main() zusammen mit den passenden Stringfunktionen richtig
> ausgewertet, dann läufts.

Warum in der main() und nicht in der ISR?

Wird jetzt nun in der ISR aus dem Tutorial zu der Uart der String 
zusammengesetztr oder nicht? Jetz nach dem durchlesen vieler String 
Artikel kommt es mir so vor als ob man immer eine for-Schleife braucht, 
da es ja immer Arrays sind, stimmt es?

PS: und warum ist das nicht so einfach und vertstaendlich wie partielle 
Differentialgleichungen, Maxwell, Thermodynamik oder Theoretische 
Elektrotechnik -.-

von Karl H. (kbuchegg)


Lesenswert?

Mikhail V. schrieb:
> Oliver schrieb:
>> Das jetzt in main() zusammen mit den passenden Stringfunktionen richtig
>> ausgewertet, dann läufts.
>
> Warum in der main() und nicht in der ISR?

Weil eine ISR schnell abgearbeitet werden soll.
Die ISR hat eine AUfgabe:
1 Zeichen empfangen und an den bisherigen Teilstring drann hängen. Ist 
die Zeile fertig, kriegt die Hauptschleife ein Signal (in Form einer 
globalen Variablen), dass eine Zeile empfangen wurde.
Was mit der Zeile weiter geschieht ist nicht mehr das Bier der ISR.

>
> Wird jetzt nun in der ISR aus dem Tutorial zu der Uart der String
> zusammengesetztr oder nicht? Jetz nach dem durchlesen vieler String
> Artikel kommt es mir so vor als ob man immer eine for-Schleife braucht,
> da es ja immer Arrays sind, stimmt es?

Die Schleife steckt in den ISR Aufrufen.

> PS: und warum ist das nicht so einfach und vertstaendlich

Es IST einfach. Wenn man die Grundlagen kennt.


Die ISR sammelt die Einzelzeichen und wenn sie eine Zeile beisammen hat, 
teilt sie das mittels uart_str_complete der Hauptschleife mit.
That's all.

von M. V. (bmtil)


Lesenswert?

So, hab jetzt bissle rumgespielt und tatsaechlich was vernuefntiges 
dabei rausgekommen:
1
 
2
//hier erstmal den kompletten string empfangen:
3
if (uart_str_complete == 1) 
4
  {  //hier soll der string mit der "strcmp" fkt. aus den #include 
5
           //<string.h> mit dem gewuenschten string "xzyxzxzxzxfusdhfs" 
6
           //vergliechen werden:
7
                                       
8
    if (strcmp( uart_str, "LED aus" ) == 0  )   
9
    {  
10
           //wenn die strings gleich sind, soll das passieren was unten //in           der if-bedienung steht:
11
          LED_PORT |= (1<<LED_PORTPIN);         //LED soll ausgehen
12
            uart_puts("LED aus");
13
    }

nicht wundern wegen des Befehls zum ausschaltend er LED, die hab 
absichtlich so an den Port verschaltet, damit die immer leuchtet wenn 
der Port auf 0 liegt.

So funktioniert es in der Interruptroutine wenn ich das tatsaechlich 
meinen Text zum LED ausmachen reinschreib.
Allerdings wenn ich den Code entsprechend abaender zum einschalten der 
LED funktioniert es nicht mehr.

In der while{} von der main() funktioniert der code auch


Danke schonmal fuer die Hilfe, jetz bin ich ein Stueckchen weiter, die 
mikrocontroller.net Artikel zu den Strings sind hilfreicher als das Buch 
und das Uni Skript.

PS.: Und natuerlich sind die Dinge, die ich erwaehnt einfacher, man muss 
ja nicht eine zusaetzliche Maschinensprache lernen, Stift und Papier 
reichen aus zum verstehen.

von Karl H. (kbuchegg)


Lesenswert?

Mikhail V. schrieb:
> So, hab jetzt bissle rumgespielt und tatsaechlich was vernuefntiges
> dabei rausgekommen:
>
1
> //hier erstmal den kompletten string empfangen:
2
> if (uart_str_complete == 1)
3
>   {  //hier soll der string mit der "strcmp" fkt. aus den #include
4
>            //<string.h> mit dem gewuenschten string "xzyxzxzxzxfusdhfs"
5
>            //vergliechen werden:
6
> 
7
>     if (strcmp( uart_str, "LED aus" ) == 0  )
8
>     {
9
>            //wenn die strings gleich sind, soll das passieren was unten
10
> //in           der if-bedienung steht:
11
>           LED_PORT |= (1<<LED_PORTPIN);         //LED soll ausgehen
12
>             uart_puts("LED aus");
13
>     }
14
> 
15
>

Du musst uart_str_complete dann auch wieder auf 0 setzen.
Solange uart_str_complete auf 1 ist, sammelt die ISR Routine keine 
weiteren Zeichen mehr.

> So funktioniert es in der Interruptroutine wenn ich das tatsaechlich
> meinen Text zum LED ausmachen reinschreib.
> Allerdings wenn ich den Code entsprechend abaender zum einschalten der
> LED funktioniert es nicht mehr.

Ein heißer Tip:
Wenn du Strings empfängst und die Auswerten sollst, dann ist es eine 
extrem gute Idee, wenn du dir den empfangenen String zu Testzwecken 
ausgeben lässt.
1
    if (uart_str_complete == 1)
2
    {
3
      uart_puts( "Empfangen: #" );
4
      uart_puts( uart_str );
5
      uart_puts( "#\n" );
6
7
      if (strcmp( uart_str, "LED aus" ) == 0  )
8
      {
9
        LED_PORT |= (1<<LED_PORTPIN);         //LED soll ausgehen
10
        uart_puts("LED aus");
11
      }
12
13
      else if (strcmp( uart_str, "LED ein" ) == 0 )
14
      {
15
        LED_PORT &= ~(1<<LED_PORTPIN);
16
        uart_puts("LED ein");
17
      }
18
19
      uart_str_complete = 0;
20
    }

Vor und hinter der Kontrollausgabe macht man sich ein Sonderzeichen 
rein, damit man sieht, ob da nicht zufällig zb führende oder 
nachfolgende Leerzeichen sind, oder ob sich nicht zb ein Zeilenumbruch 
an der falschen Stelle eingeschlichen hat.

Die Kontrollausgabe muss so aussehen
1
Empfangen: #LED aus#
Sieht sie so aus
1
Empfangen: #LED aus #
dann ist da ein Leerzeichen hinten drann. Sieht sie so aus
1
Empfangen: #LED aus
2
#
dann ist im String (am Ende) ein Zeilenumbruch drinnen, der da nicht hin 
gehört. Sieht sie so aus
1
Empfangen: #
2
LED aus#
dann ist im String (am Anfang) ein Zeilenumbruch drinnen, der da nicht 
hin gehört und zb vom vorhergehend empfangenen String übrig geblieben 
ist. etc. etc.

Wenn etwas nicht so funktioniert wie du dir das vorstellst, dann liegt 
es an dir, dir vom Programm in Form von Kontrollausgaben helfen zu 
lassen um rauszufinden, was vor sich geht. Ich weiß schon: Für Neulinge 
ist das immer etwas Überwindung, Code zu schreiben, von dem man genau 
weiß, dass er im Endprogramm nichts zu suchen hat. Der Trugschluss 
besteht darin, zu glauben, dass dir dieser zusätzliche Code großartig 
'Entwicklungszeit' kostet. Das Gegenteil ist der Fall. Derartige 
Kontrollausgaben sparen dir Summa Summarum eine Menge Entwicklungszeit, 
weil du damit sofort das Stochern im Nebel abstellst und gezielt nach 
Fehlern suchen kannst. Nur wenn du die Daten kennst, die in einen 
'Algorithmus' hineingehen kannst du auch entscheiden ob der Algorithmus 
fehlerhaft ist oder nicht. Und oftmals sind die Eingangsdaten eben nicht 
die, die du stillschweigend vorausgesetzt hast. In der Kette 
Eingabe-Verarbeitung-Ausgabe gibt es in allen 3 Stufen die Möglichkeit 
für Fehler. Also muss man jede der 3 Stufen kontrollieren.

von M. V. (bmtil)


Lesenswert?

Vielen Dank fuer die Hilfe.
Natuerlich hab ich den Anfaengerfehler gemacht und das str_complete 
nicht auf 0 gesetzt, nun funktioniert es.
Zur Kontrolle:
Danke fuer den Tipp, ich dachte die ganze Zeit dass es reicht der puts 
zu sagen, dass sie mir eben Dinge senden soll, wenn die UART 
tatsaechlich was empfangen hat.
Irgendwie hab ich durch das Thread mehr gelernt als in 3 Vorlesungen zu 
Informatik (da waren Programmiergrundlagen dabei, Assembler und noch 
jede menge Rechnerarchitektur).

von Karl H. (kbuchegg)


Lesenswert?

Mikhail V. schrieb:

> Zur Kontrolle:
> Danke fuer den Tipp, ich dachte die ganze Zeit dass es reicht der puts
> zu sagen, dass sie mir eben Dinge senden soll, wenn die UART
> tatsaechlich was empfangen hat.

So wird das auch in deinem Endprodukt sein.

Aber noch ist das Endprodukt ja nicht fertig! Und du brauchst jede 
Hilfe, die du kriegen kannst um Fehler frühzeitig zu sehen und wenn geht 
auch ihre Entstehung zu verfolgen. Kontrollausgaben können das leisten. 
Und sie kosten dir nichts ausser 20 Sekunden um sie einzubauen. Dafür 
sparen sie dir aber Stunden in der Fehlersuche.

Und wenn alles fertig ist, dauert es noch mal ein paar Minuten alle 
Kontrollausgaben wieder zu entfernen. Das heißt, sofern man sie nicht 
überhaupt drinn lässt und mittels eines #define einfach abschaltet.
1
// #define DEBUG_ECHO
2
3
4
....
5
6
int main()
7
{
8
  ....
9
10
    if (uart_str_complete == 1)
11
    {
12
#ifdef DEBUG_ECHO
13
      uart_puts( "Empfangen: #" );
14
      uart_puts( uart_str );
15
      uart_puts( "#\n" );
16
#endif
17
18
      if (strcmp( uart_str, "LED aus" ) == 0  )
19
      {
20
        LED_PORT |= (1<<LED_PORTPIN);         //LED soll ausgehen
21
        uart_puts("LED aus");
22
      }
23
24
      else if (strcmp( uart_str, "LED ein" ) == 0 )
25
      {
26
        LED_PORT &= ~(1<<LED_PORTPIN);
27
        uart_puts("LED ein");
28
      }
29
30
      uart_str_complete = 0;
31
    }

Jetzt ist der Kontrollausdruck abgeschaltet. Brauchst du ihn aus 
irgendeinem Grund wieder, dann nimmst du den Kommentar beim #define weg 
und der Kontrollausdruck ist wieder aktiv. Brauchst du ihn nicht mehr, 
dann setzt die die Kommentar-// wieder vor das #define und die ganzen 
Kontrollausgaben sind wieder verschwunden.

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.