Hallo Leute,
ich will mit der Uart Lib von Fleury einen String vom PC zum AVR
schicken. Einzelne Zeichen Funktionieren ach wunderbar, aber ich möchte,
dass alle Zeichen erst in einen char Array geschrieben werden und das
dann beispielsweise komplett zurückgegeben wird ( Später natürlich eine
andere Anwendung). Wie muss ich denn die for-Schleife erweitern, dass
erst der komplette String ausgegeben wird?
1
intmain(void)
2
{
3
unsignedintc;
4
chartest[20];
5
inti;
6
7
/*
8
* Initialize UART library, pass baudrate and AVR cpu clock
Ist doch schon mal ein schöner Ansatz.
Du solltest dir zur Gewohnheit machen, für in sich abgeschlossene
Aufgaben eine eigene Funktion zu machen.
In deinem Fall lautet die Aufgabe: Empfange einen String, wobei
auf den String gewartet werden kann.
Soweit so gut. Aber: Woher weist du eigentlich, dass ein String
zu Ende ist. Nur weil bei einem Aufruf von uart_getc() kein
Character zurückkommt, heist das ja nicht, das deswegen der
String zu Ende ist. Es könnte ja auch sein, dass der Benutzer
am anderen Ende einfach nur langsamer tippt.
-> Du musst dich für eine Strategie entscheiden, mit der
du zweifelsfrei erkennen kannst, dass der String jetzt zu
Ende ist.
Oft wird dazu der Empfang des Zeichens '\n' (Return) benutzt.
Für viele Benutzer ist es mitlerweile zur zweiten Natur geworden
eine Eingabe durch Druck auf 'Return' zu beenden. Und genau
das ist dann für deine Funktion das Kennzeichen, dass der String
zu Ende ist.
Was muss deine Funktion also machen? Formulier das mal
umgangssprachlich
es muss irgendwo ein character Array geben, in dem
empfangene Zeichen zwischengespeichert werden können um
den C-String aus den einzelnen Zeichen aufzubauen
so muss in einer Schleife auf jeweils den Empfang eines
Zeichens warten
War das Zeichen ein '\n', dann ist der Text komplett
übertragen worden. In guter C-Manier, wird an den bisherigen
Text im character Array noch ein '\0' angehängt um daraus einen
gültigen C-String zu machen und die Funktion ist zu Ende.
War das Zeichen kein '\n', dann wird es ganz einfach an den
bisherigen Text im character Array angehängt. Das erfordert
allerdings, dass man weiss, wo denn das letzte Zeichen im
Array eingefügt wurde -> man braucht eine Variable dafür.
Je nach Bedarf ist es auch eine gute Idee, das Zeichen über
die UART wieder zurück zu schicken, damit der Benutzer auch
sieht was er tippt.
Wenn du willst, kannst du auch rudimentäre Edit-Funktionalität
einbauen, um zb. dem Benutzer die Möglichkeit zu geben, mittels
Backspace wieder zurückzugehen:
Wird ein '\b' empfangen, so verminderst du die Textzählung um 1
und gibst die Sequenz '\b', ein Leerzeichen und noch ein '\b'
aus.
Wie auch immer, es geht auf jeden Fall in der Schleife innerhalb
der Funktion weiter. Diese Schleife innerhalb der Funktion kann
nur durch den Empfang eines '\n' verlassen werden.
Tja. Das wars dann auch schon. Damit hast du eine Funktion, die
auf den Erhalt eines Textes (einer Eingabezeile) wartet. Und die
verwurschtest du dann in deiner main() Schleife weiter.
Den String solltest du immer mit einem Nullbyte abschliessen.
test[i] = c;
i++;
test[i] = '\0'; // <===
Du solltest nie mehr Zeichen in das Array test reinschreiben als Platz
reserviert ist.
if (i < (20-1)) // -1 wg. abschliessendem Nullbyte
{
test[i] = c;
i++;
test[i] = '\0'; // <===
}
Im Moment gibst du bei jedem empfangenen Zeichen den String in test aus,
so weit er bereit gefüllt ist. Schlauer wäre es, den String erst
auszugeben, wenn das Zeilenendezeichen empfangen wurde oder der String
"voll" ist.
if (c == '\n' || i == (20-1))
{
uart_puts(test);
i = 0; // zurücksetzen für nächsten String
test[i] = '\0'; // leerer String
}
eine frage hätt ich dann doch noch. hab das ganze jetzt mal in meinen
code eingebaut und es funktioniert auch...aber leider immer nur einmal.
Ich gebe einen String im terminal ein, dieser wird wie er soll
verarbeitet, und auch wieder ausgegeben. gebe ich dann den nächsten
string ein, so wird er nicht mehr verarbeitet, jedoch noch ausgegeben.
bei der nächsten eingabe passiert dann garnichts mehr:( nicht über die
merkwürdigen umrechnungen und hin und herschiebereien das wundern, das
wird alles noch vereinfacht^^ aber wo liegt das problem, dass das
programm nicht bei jedem neu eingebenen String normal weiterarbeitet? (
Die eingegeben Strings haben immer die Länge 64)
Hallo ich möchte jetzt auch nochmal auf die Thematik UART Lib und String
empfangen zurück kommen.
Ich verwende den Mega32 jedoch ist es mir nicht möglich einen String zu
empfangen und anschließend auszugeben.
Einzelne Zeichen zu empfangen und senden geht fehlerfrei.
Ich habe dabei die UART LIB von Peter Fleury mit Interupts verwendet und
zudem den Quellcode aus dem AVR-GCC Tutorial.
Ich würde mich über Tipps freuen.
1
/* Include Dateien */
2
#include<stdlib.h>
3
#include<avr/io.h>
4
#include<avr/interrupt.h>
5
#include<avr/signal.h>
6
#include<avr/pgmspace.h>
7
8
#include"uart.h"
9
10
/* CPU Frequenz definieren */
11
#define F_CPU 16000000UL
12
13
/* Baudrate 19200 */
14
#define UART_BAUD_RATE 19200
15
16
voiduart_gets(char*Buffer,uint8_tMaxLen)
17
{
18
uint8_tNextChar;
19
uint8_tStringLen=0;
20
21
NextChar=uart_getc();// Warte auf und empfange das nächste Zeichen
Mh okay da ist etwas dran.
Jedoch dachte ich ist diese Lib Interuptgesteuert?
Oder irre ich da?
Wenn Nein, dann würde mich interessieren ob und wie ich diese Lib
anpassen muss oder ob ich dann selber mir ne funktion uart_getc()
schreiben muss....
Denn eigentlich ist diese Lib ja schon ganz net.
Maik wrote:
> Jedoch dachte ich ist diese Lib Interuptgesteuert?
Eben, deshalb wartet die Funktion ja auch nicht. Wenn die Funktion immer
so lange warten würde, bis ein Zeichen da ist, welchen Sinn hätte dann
der Interrupt gesteuerte Empfang?
> Wenn Nein, dann würde mich interessieren ob und wie ich diese Lib> anpassen muss oder ob ich dann selber mir ne funktion uart_getc()> schreiben muss....
Es wäre sinnvoller, die Funktion uart_gets anzupassen.
Maik wrote:
> Wenn Nein, dann würde mich interessieren ob und wie ich diese Lib> anpassen muss oder ob ich dann selber mir ne funktion uart_getc()> schreiben muss....
Wozu?
Das lustige ist:
In deiner main() hast du ein perfektes Beispiel dafür, wie man uart_getc
aus der Fleury Lib korrekt einsetzt.
Vielleicht einfach mal die Beispiele, die mit der Lib kommen, studieren
und abklären ob deine Vorstellungen darüber wie die Lib zu benutzen ist
richtig sind, ehe man drangeht eine gut funktionierende Lib
umzuschrieben :-)
So jetzt hab ich mich nochmal mit der Lib beschäftigt.
Die empfangen Zeichen hängen ja in einem Ringpuffer und die uart_getc
holt sich die zeichen aus diesem puffer. Dies geschieht ja bei jedem
Durchlauf der FOR-Schleife im main. So und dann wird ja auch direkt
überprüft ob jetzt ein Zeichen da ist oder ein Fehler aufgetreten ist
oder nicht.
Soweit so gut.
Wenn ich also jetzt einen String empfangen möchte muss ich mich ans Ende
der ELSE Funktion hängen, da dann ja gewährleistet ist, das ein Zeichen
korreckt empfangen wurde und verfügbar ist zur weiterverarbeitung.
jetzt habe ich dann meine uart_gets() Funktion dahingehend umgebaut.
Also diese While schleife weg und durch if ersetzt.
Hier jetzt nochmal der Teil in der main
Soweit ich das jetzt testen konnte führt er diese funktion auch richtig
aus.
Jedoch habe ich das gefühl, das der string nicht richtig in das Array
LINE wandert.
Ebenso glaube ich hab ich noch nen Knoten im Kopf wie ich das Array dann
wieder an den PC zurücksenden kann.
Ich habe zum testen einfach mal jedes Feld des Arrays mit uart_getc()
ausgegeben, jedoch kommt da alles andere an als das was ich gesendet
habe.
Achso, die Variable flag ist
Das ist aber ziemlich umständlich zu benutzen :-)
Warum lässt du nicht einfach uart_gets im Prinzip so wie sie ist, und
jubelst ihr einen Ersatz für uart_getc unter, der tatsächlich auf das
Eintreffen eines Zeichens wartet? Ist doch mit der uart_getc aus der Lib
kein Problem sowas zu machen.
1
uint8_tuart_getc_wait()
2
{
3
unsignedintc;
4
5
do{
6
c=uart_getc();
7
}while(c==UART_NO_DATA);
8
9
return(uint8_t)c;
10
}
11
12
voiduart_gets(char*Buffer,uint8_tMaxLen)
13
{
14
uint8_tNextChar;
15
uint8_tStringLen=0;
16
17
NextChar=uart_getc_wait();// Warte auf und empfange das nächste Zeichen
18
19
// Sammle solange Zeichen, bis:
20
// * entweder das String Ende Zeichen kam
21
// * oder das aufnehmende Array voll ist
22
while(NextChar!='\n'&&StringLen<MaxLen-1){
23
*Buffer++=NextChar;
24
StringLen++;
25
NextChar=uart_getc_wait();
26
}
27
28
// Noch ein '\0' anhängen um einen Standard
29
// C-String daraus zu machen
30
*Buffer='\0';
31
}
> Jedoch habe ich das gefühl, das der string nicht richtig in das> Array LINE wandert.
Das ist richtig. So wie uart_gets momentan geschrieben ist, ist
uart_gets darauf angewiesen, dass es die Kontrolle behält, während sie
einen String empfängt. WEnn du das so umändern möchtest, dass das
Empfangen eines Strings komplett im Hintergrund ohne aktives Warten
erfolgt, dann geht das so nicht. Die Funktion uart_gets müsste dazu
wissen, wo das nächste Zeichen im Buffer abzulegen ist. Und das wird ihr
in der Argumentliste nun mal nicht mit übergeben.
Vielen Dank Karl heinz, jetzt funktioniert es.
Ich denke die völlig autake lösung werde ich ein anderes mal anstreben.
Vielleicht noch für die Nachwelt.
Wenn interesse besteht könnte man diese Variante auch ins AVR-GCC Tut
übernehmen.
Kann hier mal jemand einen Kompletten simple source erstellen, ich
werkle seit Tagen rum und bekomme alles (HIN) aber nicht das was ich
will. Ich stehe hier gerade voll auf dem schlauch.
Sven Schwiecker schrieb:> Kann hier mal jemand einen Kompletten simple source erstellen, ich> werkle seit Tagen rum und bekomme alles (HIN) aber nicht das was ich> will. Ich stehe hier gerade voll auf dem schlauch.
Was gefällt dir denn an der Lösung von 2009, 2 Postings weiter oben,
nicht?