Hallo, ich hab ich jetzt mit dem UART versucht.
Ich möchte mit meinen uC über RS232 mitn PC übers Terminal Programm
reden.
Text ausgeben und Zahlen einlesen funktioniert alles Einwand frei.
Nun möchte ich ein Wort auf dem Terminal eingeben und der uC soll es
wieder geben zur Kontrolle. Dies funktioniert leider nicht. Ich blicke
nicht ganz durch die gets und string Geschichte beim UART durch. ? Ich
arbeite mit printf und scanf.
________________________________________________
Hier mal der Code aus der Main :
________________________________________________
________________________________________________
Auf dem Terminal sieht es so aus :
Geben sie jetzt eine Zahl ein = 888
Deine Eingabe war 888
Ein Sinnloses Wort eingeben = jkjk
Der Courser liegt nach der Eingabe auf dem E von Eingabe.
nicht nur die Tasten 8, 8 und 8 gedrückt hast, sondern auch noch auf
Return drüclken musstest.
EIn
1
scanf("%u",&input);
holt sich zwar die 3 8-er, aber es belässt den Return im Eingabestrom.
Die nächste Eingabeoperation muss sich darum kümmern. Genauer gesagt:
Wenn ein scanf eine Zahl einlesen soll, dann hört er beim ersten Zeichen
auf, das nicht zur Zahl gehört. Das kann irgendein Zeichen sein, zum
Beispiel ein Leerzeichen, ein 'a' oder aber auch ein Return. Da dieses
Zeichen nicht zur Zahl gehört kann es aber dieser scanf hier nicht
einfach weglesen, sondern muss es im Eingabestrom belassen.
Ein
1
gets(str);
hingegen ist so definiert, dass er alle Zeichen einliest, bis er auf
einen Return stösst.
Tja. Aber genau den Fall hast du. Von der Eingabe der 888 ist da noch
ein Return im Eingabestrom. Und genau den sieht das gets als
allererstes, holt ihn sich und erklärt damit die Eingabe des Strings für
beendet.
Gewöhn dich daran, dass direkte Eingaben per printf und scanf auf einem
µC eist keine so gute Idee sind. Das scanf, so wie du das betreibst,
sowieso schon nicht. Denn auf einem µC ist der Normalfall der, dass der
Prozessor nicht Däumchen drehen darf, nur weil er auf eine Eingabe vom
Benutzer wartet. D.h. hier ist man im Endeffekt mit anderen Methoden
viel besser bedient.
Hallo, ich hab mal die Routine genommen die ich im TuT gefunden habe
habe die main jetzt folgendermaßen geschrieben, der Effekt ist der
selbe. Ich gebe das Wort ein drücke auf Enter und er springt zum Anfang
des Satzes, zum E von Ein.
Jakob schrieb:> Jakob schrieb:>> uart_puts( "\r\n" );>> uart_puts( Line );>>> Dies wird ja dann so zu sagen gar nicht bearbeitet sondern bleibt im> uart_gets stecken ?
Das kannst du ganz leicht rausfinden :-)
1
uart_puts("\r\n Ich hab verstanden: \"");
2
uart_puts(Line);
3
uart_puts("\"");
Und schon hast du einen unzweideutigen Fixtext an der Ausgabe, der
eindeutig belegt, ob es zu den puts überhaupt kommt.
Gewöhn dich an die Idee, dass du über die UART dir auch dir bekannte
Fixtexte ausgeben kannst, die dir in der Entwicklungsphase des Programms
helfen nachzuvollziehen, wie die Ablöufe im Programm sind. Es ist nicht
verboten sich derartige Hilfen zunächst ins Programm einzubauen, die
dann nach Ende der Entwicklung, bzw. wenn man ein Problem verstanden und
behoben hat, wieder entfernt.
genau aus dem Grund ist es auch eine gute Idee, sich zb Texte mit
Sonderzeichen einzurahmen, weil man dann auch Sonderzeichen, wie zum
Beispiel Zeilenvorschübe im ausgegegbenen Text 'sehen' kann, indem man
analysiert, ob diese Sonderzeichen dort in der Ausgabe auftauchen, wo
sie auftauchen sollten. in einem
1
"Test.txt "
ist nun mal am Ende des eigentlichen Textes ein Leerzeichen, das man
sonst nicht sehen würde. In
1
"Test.txt
2
"
hat sich ganz offensichtlich ein Carriage Return / Line Feed in den Text
eingeschmuggelt. In
1
"
2
Test.txt"
steht der Carriage Return / Line Feed offenbar am Anfang des Textes.
Allen Fällen gemeinsam ist, dass man ohne die zusätzlichen
Sonderzeichen, diese Spezialitäten nicht oder nur sehr schwer sehen
würde.
Hab es...das Programm hat so funktioniert musste aber die 40 Zeichen
Eingeben und bei Enter hat er nur Unsinn gemacht, aber hab mir die
Routine nochmal genauer angeschaut und hab gemeckert das ich statt denn
\n ein \r schreiben muss damit er mit Enter beendet :S
Jakob schrieb:> Hab es...das Programm hat so funktioniert musste aber die 40 Zeichen> Eingeben und bei Enter hat er nur Unsinn gemacht, aber hab mir die> Routine nochmal genauer angeschaut und hab gemeckert das ich statt denn> \n ein \r schreiben muss damit er mit Enter beendet :S
Ja, das kann sein.
Das hängt von der Einstellung deines Terminalprogramms ab, mit dem du
arbeitest. Da gibt es alle Möglichkeiten, auch Kombinationen davon.
Und ja. das ist ein konstantes Ärgerniss.
> Ist der Aufbau so besser, als mit Printf etc ?
printf geht noch. Aber mit scanf wirst du nicht wirklich glücklich
werden. Aus dem schon genannten Grund, dass in einem normalen
µC-Programm die Heizungssteuerung ja nicht stehen bleiben darf, nur weil
du eine Eingabe angefangen hast und zwischendurch mal aufs Klo musstest.
µC-Programmierung funktioniert am besten, wenn man diese sequentielle
Vorgehensweise "erst mach dies, dann warte auf das" über Bord wirft und
nach dem Muster vorgeht: Welches Ereignis ist eingetreten, wie muss ich
darauf reagieren.
1
lineCnt=0;
2
3
while(1){
4
5
if(uart_char_available()){// Ist ein Zeichen an der UART eingetroffen?
6
nextChar=uart_getc();// hole das Zeichen.
7
// was soll damit geschehen?
8
9
if(nextChar!='\r')// noch nicht das Ende einer Eingabezeile
PORTB&=~(1<<PB0);// beispielsweise LED einschalten
19
20
elseif(strcmp(nextLine,"aus")==0)
21
PORTB|=(1<<PB0);// beispielsweise LED ausschalten
22
}
23
}
24
25
// mach was ganz wichtiges, was regelmässig erfolgen muss
26
// zb. Überwachen ob ein motorgesteuerter Schlitten seine Endposition
27
// erreicht hat.
28
}
auf die Art läuft der Teil 'mach was ganz wichtiges, ...' auch dann
weiter, während du an deinem Terminal sitzt und tippst und dir während
des Tippens einen Kaffee holst. Trudelt das nächste getippte Zeichen
beim AVR ein, dann wird es geholt, entschieden was damit passieren soll
(in den meisten Fällen wird es einfach an die bisher empfangenen Zeichen
hinten drann gehängt) und nur dann, aber auch wirklich nur dann, wenn du
auf Return drückst, startet die Auswertung der übertragenen Zeile.
Auf etwas zu warten ist in der µC-Programmierung in 95% der Fälle eine
ganz schlecht Design-Entscheidung.
Und genau deswegen ist scanf (nicht aber sscanf!) meist nicht wirklich
brauchbar. Genausowenig wie ein _delay_ms ausser in ganz wenigen
Ausnahmefällen etwas verloren hätte. Der Schlüssel zu einem Programm,
das scheinbar mehrere Aufgaben gleichzeitig erledigen kann, besteht
darin, dass auf nichts und niemanden gewartet wird. Ausser vielleicht
auf die Antwort von einem DS1820 Temperatursensor. Aber da reden wir
nicht von Millisekunden sondern von Mykrosekunden im Übertragungstakt
:-)
Und auch bei Sensoren kann das Signal gestört sein und dein Mc wartet
auf eine Flanke etc. Da ist es dann schön wenn auch dort eine Art
timeout Variable vorhanden ist. Das ist mir bei wilden Steckbrett
Aufbauten schon öfter passiert.
Und wieder Vielen Dank an Karl Heinz für die tollen Ausführungen.
Ich habe mir angewöhnt, beim Empfang sowohl \r als auch \n zu
akzeptieren. Außerdem noch die Sonderlocke dass ein \n ignoriert wird,
wenn das vorherige Zeichen ein \r war (DOS Programme und daran
angelehnte beenden Zeilen häufig mit \r\n).