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.
>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
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.
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.
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...
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.
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
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?
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
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.
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.
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.
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.
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
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.
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 -.-
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.
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.
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
elseif(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.
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).
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
intmain()
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
elseif(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.