Hallo,
ich versuche bei der Kommunikation mit einem ESP8266 den empfangenen
String auszulesen und daraufhin etwas auszulösen. Mit Problem liegt in
der C - Programmierung des AVR:
while(uart_data_received()){// Wenn Daten empfangen wurden
41
42
rec=uart_getchar();// Daten nach rec speichern
43
44
sprintf(rec_conv,"%s%c",rec_conv,rec);// Alte und neue Zeichen nach rec_conv
45
46
}
47
48
// String teilen
49
token=strtok(rec_conv,delimiter);
50
51
while(token!=NULL){
52
if(strcmp(token,"test")==0){
53
PORTB=0xFF;}
54
else{
55
PORTB=0x01;
56
}
57
token=strtok(NULL,delimiter);
58
}
59
60
for(i=0;i<30;i++){
61
62
rec_conv[i]='\0';
63
64
}
65
66
}
67
68
}
Wenn ich mit HTerm einen String sende und ich lasse die Variable
"rec_conv" vor der Stringteilung ausgeben, erscheint exakt ein Echo.
Soweit so gut.
Wenn ich jedoch den String am Doppelpunkt teile und anschließend
vergleiche passiert leider nichts. Beispiel:
Senden -> 123:test
Der PortB schaltet jedoch nicht ein. Kann mir jemand helfen ?
Grüße
TUC
TUC schrieb:> while (uart_data_received()){ // Wenn Daten empfangen wurden>> rec = uart_getchar(); // Daten nach rec speichern>> sprintf(rec_conv,"%s%c",rec_conv,rec); // Alte und neue Zeichen> nach rec_conv
Äh. Da bin ich jetzt überfragt, ob du das überhaupt darfst. Bei sprintf
eine Quelle angeben und gleichzeitig diese Quelle als Buffer zu
benutzen. Sei es wies sei: sprintf ist da mit Kanonen auf Spatzen. Du
möchtest einen strcat benutzen. Dazu musst du aus rec einen String
machen, was weiter kein grosses Problem ist.
1
charrec[2]=" ";
2
3
4
...
5
rec[0]=uart_getchar();
6
strcat(rec_conv,rec);
7
}
aber das ist nicht dein eigentliches Problem. Dein eigentliches Problem
besteht darin, dass du hier
1
while(uart_data_received()){// Wenn Daten empfangen wurden
2
...
3
}
4
5
// Annahme: der String wurde fertig übertragen
viel zu optimistisch bist.
Nur weil momentan kein Zeichen in der UART vorliegt, heisst das noch
lange nicht, dass 30 Zeichen übertragen wurden!
UART Übertragung ist relativ langsam. Während sich da 1 Byte über die
Leitung quält hat dein µC ein paar hundert mal festgestellt, dass zur
Zeit kein Zeichen in der UART zur Abholung bereit steht. Du agierst wie
jemand der 30 Sendungen von Amazon erwartet und früh morgens 30 mal im
Postkasten nachsieht, ob was da ist und nach dem 30 mal nachsehen die
'Übertragung der Ware' als beendet erklärt.
Das funktioniert so nicht.
Der Sender muss dir mit einem Zeichen mitteilen "Das wars jetzt. Jetzt
ist die Übertragung fertig. Jetzt kannst du mit der Auswertung
loslegen". Oft nimmt man zb das Zeilenendezeichen '\n' für diesen Zweck
her. D.h. deine Schleife läuft so lange, so lange nicht dieses
Zeilenende gesichtet wurde.
1
rec=' ';// hier kann rec wieder ein einfacher char sein
2
// du wirst gleich sehen warum
3
i=0;
4
5
do{
6
if(uart_data_received()){
7
rec=uart_getchar();
8
rec_conv[i]=rec;
9
i++;
10
}
11
}while(rec!='\n');
12
13
rec_conv[i]='\0';
14
15
16
// Jetzt hast du einen gültigen String.
Jetzt hast du hier einen gültigen String. Der Sender hat dir ja
mitgeteilt, wann der String zu Ende ist.
Was man noch einbauen müsste. Die Absicherung, das der Sender nicht zu
viel schickt, so dass das Array über läuft.
TUC schrieb:> Wenn ich mit HTerm einen String sende
händisch getippt?
> und ich lasse die Variable> "rec_conv" vor der Stringteilung ausgeben, erscheint exakt ein Echo.
Das kann nicht sein.
Da musst du dich irgendwo vertan haben.
Du magst ein korrektes Echo bekommen haben, in dem du die einzelnen
Zeichen gleich nach dem Empfang zurück geschickt hast. Aber der String
war nie und nimmer korrekt. So schnell kannst wiederrum du gar nicht
tippen, dass du mit einer halbwegs moderaten Baudrate mithalten kannst
und der µC nicht aus deiner while( received ) Schleife rausgefallen
wäre.
Karl Heinz schrieb:> So schnell kannst wiederrum du gar nicht> tippen, dass du mit einer halbwegs moderaten Baudrate mithalten kannst
Bei Hterm kann man auch den gesamten Text schreiben und erst wenn man
mit Enter bestätigt wird alles hintereinander gesendet. Wenn der µC aber
schon fertig ist mit dem sprintf bevor das nächste Zeichen da ist
verlässt er aber trotzdem die while().
Max H. schrieb:> Karl Heinz schrieb:>> So schnell kannst wiederrum du gar nicht>> tippen, dass du mit einer halbwegs moderaten Baudrate mithalten kannst> Bei Hterm kann man auch den gesamten Text schreiben und erst wenn man> mit Enter bestätigt wird alles hintereinander gesendet.
Ja, da hast du recht.
Das ist aber trotzdem nicht die Erklärung für das was er ursprünglich
gesehen hat (mit seiner Beschreibung, dass das Echo stimmen würde).
Das korrekte Echo stammt nicht daher, dass der eine String korrekt
empfangen wurde, sondern daher, dass er viele Strings mit wahlweise 0
oder 1 Zeichen zusammengebaut hat (manchmal mögen eventuell sogar 2
Zeichen direkt hintereinander aus der UART gepurzelt sein). Und wenn man
die echot, dann sieht es am Terminal so aus, als ob es nur 1 String
wäre, in dem alle Zeichen drinn sind.
-> Es ist oft eine gute Idee, sich in Ausgaben zum Terminal ein paar
Sonderzeichen einzubauen. Dann kann man besser beurteilen, wo am
Terminal eine einzelne Ausgabe anfängt und wo sie endet. Hätte er im
Originalcode sein Echo so gemacht:
1
while(1){
2
3
while(uart_data_received()){// Wenn Daten empfangen wurden
4
5
rec=uart_getchar();// Daten nach rec speichern
6
7
sprintf(rec_conv,"%s%c",rec_conv,rec);// Alte und neue Zeichen nach rec_conv
8
9
}
10
11
uart_putc('#');// <--- der entscheidende Punkt
12
uart_puts(rec_conv);
13
uart_putc('#');
14
....
dann hätte er unmissverständlich gesehen, was da los ist. Der µC hätte
ihm das Terminal mit '#' geflutet, während er tippt :-) Das wiederrum
hätte ihn auf die Spur gebracht, dass die Schleifensteuerung über
data_received keine gute Idee ist.
TUC schrieb:> Es funktioniert jetzt, vielen Dank !!
Vorsicht:
Du solltest hier
1
while(1){
2
i=0;
3
do{
4
if(uart_data_received()){
5
rec=uart_getchar();
6
rec_conv[i]=rec;
7
i++;
8
}
9
}while(rec!='\r');
sicher stellen, dass rec nicht '\r' ist, wenn es das erste mal in die
Schleife reingeht. Denn niemand sagt, dass da sofort wieder ein Zeichen
aus der UART raus kommt. D.h. rec kann immer noch den Wert haben, den es
aus dem 'Durchgang' vorher hatte. Und der war - Trommelwirbel - '\r'
Was natürlich sofort dazu führen würde, dass die Schleife gleich wieder
abbricht.
wie gesagt:
derartige Ausgaben sind gut:
> uart_puts(rec_conv);
Aber noch besser sind sie, wenn du sicherstellst, dass du sie auf keinen
Fall übersehen kannst. Selbst dann nicht, wenn rec_conv ein leerer
String ist
1
uart_puts("-> #");
2
uart_puts(rec_conv);
3
uart_puts("#\r");
jetzt kannst du das auf keinen Fall mehr übersehen. Genausowenig wie du
übersehen kannst, wenn am Anfang des Strings (oder am Ende) zusätzliche
Leerezeichen drinnen stehen. Eine Ausgabe von
1
-> # 123.test
2
#
zeigt dir das unmissverständlich. Genauso wie dir der Zeilenumbruch im
Terminal vor dem 2-ten # unmissverständlich anzeigt, dass da wohl ein
'\r' im String sein muss, denn du sonst nicht sehen würdest.
Ja das ergibt Sinn, danke für den Tipp!
Deinen ersten Einwand kann ich aber noch nicht ganz nachvollziehen:
rec bekommt doch bei jedem Durchlauf (wenn etwas neues angekommen ist)
erst einmal einen neuen Wert zugewiesen !?
Z.B.: Ich übertrage irgendetwas und das letzte Zeichen ist \r, dann ist
rec='\r' und die Schleife bricht ab. Wenn nun beim nächsten mal
festgestellt wird, dass etwas Neues angekommen ist, dann wird rec doch
ersteinmal ein neuer Wert zugewiesen (wenn ich "abcd\r" übertrage z.B.
'a') und die Schleife würde wieder durchlaufen !?
Vllt. habe ich das Problem auch einfach noch nicht erkannt.
LG TUC
TUC schrieb:> Ja das ergibt Sinn, danke für den Tipp!>> Deinen ersten Einwand kann ich aber noch nicht ganz nachvollziehen:> rec bekommt doch bei jedem Durchlauf (wenn etwas neues angekommen ist)
*******************************
> erst einmal einen neuen Wert zugewiesen !?
Der ***** ist der springende Punkt.
Was, wenn noch nichts neues angekommen ist?
> Vllt. habe ich das Problem auch einfach noch nicht erkannt.>
Pimp dir die Ausgabe wie vorgeschlagen und du wirst es sehen.
Karl Heinz schrieb:> Pimp dir die Ausgabe wie vorgeschlagen und du wirst es sehen.
Dein Programm versucht dann ständig erneut den (jetzt leeren) String in
rec_conv auszuwerten. Erst wenn dann wieder das erste neue Zeichen
eintrudelt, bleibt es in der while Schleife und wartet auf das Ende der
neuen Übertragung.