hallo Leute,
ich versuche mehrere String durch UART zu empfangen aber klappt nicht,
hat
jemanden eine Ahnung? Die Daten sind von meinem CPU gesendet.In mein
snprint Funktion bekomme ich nur der erste String und das letze
Buchstabe von zweitem String.Gibt es eine andere Möglichkeit zu
überprüfen, ob alle Daten vorhanden
sind.
Die zweite Frage ist:Wie kann ich nach der Einschaltung von Interrupt in
die Routine gehen und nach dem Empfang von Daten im main Funktion
zurückgehen.
Auf eine Antwort freue ich mich schon.
Danke
Ich hab mir mal dein Send Programm vorgenommen.
Ausschnitt:
1
charsCmd[254];
2
3
...
4
5
sCmd[0]=0x44;
6
sCmd[1]=0x43;
7
sCmd[2]=0x42;
8
sCmd[3]=0x40;
9
10
...
11
12
if(!writeport(fd,sCmd)){
Und in writeport
1
intwriteport(intfd,char*chars){
2
intlen=strlen(chars);
Wie denkst du, dass der strlen in writeport die Stringlänge
sauber feststellen kann, wenn in sCmd keine Abschluss-'\0'
enthalten ist?
Ausserdem: Bitte, bitte, bitte. Gewöhn dir das Herumwerfen mit
ASCII Codes gleich wieder ab. Das ist doch Unsinn und überhaupt
nicht cool!
Warum willst du ...
1
sCmd[0]=0x44;
2
sCmd[1]=0x43;
3
sCmd[2]=0x42;
4
sCmd[3]=0x40;
schreiben, wenn ...
1
sCmd[0]='D';
2
sCmd[1]='C';
3
sCmd[2]='B';
4
sCmd[3]='@';
... genau das Gleiche ausdrückt aber um 3 Zehenerpotenzen lesbarer
ist.
Noch lesbarer, und auch richtig, wird das Ganze, wenn du es so
schreibst:
1
strcpy(sCmd,"DCB@");
denn dann ist auch das abschließende '\0' Byte, welches für
writePort (da dort strlen() benutzt wird) fundamental wichtig ist,
automatisch mit drinnen.
Dein Receiver Interrupt ist komplett daneben.
* Es ist sinnlos in der Interrupt Routine abzufragen, ob
ein Zeichen eingetroffen ist. Die Interrupt Funktion wurde
aufgerufen weil ein Zeichen eingetroffen ist.
* In der Interrupt Funktion wird ein Zeichen empfangen und
ausgewertet. Wenn du das Zeichen zwischenspeichern willst,
dann tu das. Aber warte nicht in der ISR bis das nächste
Zeichen eintrifft. Wenn ein 2-tes Zeichen eintrifft, dann
wird die ISR (warum verwendest du eigentlich SIGNAL und nicht
das seit inigen Jahren übliche ISR?) ein weiteres mal
aufgerufen, und du kriegst das 2-te Zeichen.
Du musst weg von der Vorstellung auf etwas zu warten.
Du kriegst ein Zeichen und bearbeitest es. Wenn es das
letzte Zeichen deiner Übertragung war, dann löst das eine
Aktion aus. Wenn nicht, dann wird das Zeichen gespeichert
und die Kontrolle wieder abgegeben.
Wenn ein Beamter zur Bearbeitung eines Vorgangs 5 Formulare
benötigt, dann wartet er ja auch nicht und dreht Däumchen
bis alle 5 Formulare beisammen sind. Er nimmt die ersten 2
Formulare von dir entgegen, stellt fest, dass das noch nicht
reicht, legt sie in ein dir zugeordnetes Ablagefach und bearbeitet
in der Zwischenzeit einen anderen Vorgang. Erst dann, wenn du
übermorgen wiederkommst und die fehlenden 3 Formulare nachreichst,
wird deine Eingabe bearbeitet.
hallo karl,
zuerst danke für deine Hilfe.Es gab einen Schreibsfehler im code ich
habe immer das Null-Byte am ende des Strings eingefügt.Ich habe
korrigiert aber ich kriege nicht alle Zeichen.Bitte sag mir wie ich die
beide String in der Routine kriegen kann.Warum wird das Programm
abgebrochen, wenn es das erste Null-byte findet, obwohl der Buffer nicht
voll ist.
Wenn ich ein String mehr als 3 Zeichen schicke, bekomme ich nur 3
Zeichen.
Danke.
Dein Hauptproblem dürfte immer noch sein, dass deine Empfangs ISR
viel zu viel macht!
Die soll einfach nur 1 Zeichen (in Worten: ein Zeichen) empfangen,
entscheiden ob das das Ende des empfangenen Strings ist und wenn
nicht, das Zeichen zwischenspeichern. Mehr nicht!
Also ungefähr so
1
charstring[100];
2
unsignedcharnextCharPos;
3
volatileunsignedcharstringReady;
4
5
ISR(SIG_UART0_RECV)
6
{
7
unsignedcharc=UDR0;
8
9
if(c=='\r'){// das wars, der String ist vollständig
10
string[nextCharPos]='\0';
11
12
StringReady=1;
13
nextCharPos=0;
14
}
15
16
else{
17
string[nextCharPos]=c;
18
nextCharPos++;
19
}
20
}
in deiner main() Funktion wertest du dann aus, welcher String
empfangen wurde.
1
intmain()
2
{
3
charreceivedString[100];
4
5
...
6
...
7
8
nextCharPos=0;
9
stringReady=0;
10
11
sei();
12
13
while(1){
14
15
if(stringReady==1){// von der ISR wurde ein String komplett
16
// empfangen
17
cli();
18
strcpy(receivedString,string);
19
stringReady=0;
20
sei();
21
22
// hier kann jetzt nach Herzenslust mit receivedString
23
// gearbeitet werden, selbst wenn im Hintergrund von der ISR
24
// bereits der nächste String empfangen wird.
25
26
....
27
}
28
}
29
}
Du musst die Auswertung aus der ISR raus kriegen!
Die ISR muss so kurz wie nur irgend möglich sein! Alles was
dort Zeit kostet und nicht unbedingt dort gemacht werden
muss fliegt raus.
PS:
Wenn deine Empfangsroutine am Erhalt eines '\r' erkennt
dass der String dadurch vollständig ist, dann wäre es auch
ganz gut, wenn deine Sendefunktion auch mal das Zeichen '\r'
wegschicken würde.
strcpy( sCmd,"ABC\0" );
//strcpy( sCmd,"ABCGHIJKL\0" );
char sCmd1[254];
strcpy( sCmd1,"DEF\0" );
Was soll denn das sein?
Wenn du einen String angibst "DEF" dann ist das abschliessende
'\0' Zeichen automatisch enthalten. Das macht der Compiler
für dich!
http://www.mikrocontroller.net/articles/FAQ#Wie_funktioniert_String-Verarbeitung_in_C.3F
Ev. wäre es ganz gut, wenn du anstelle des '\r' Zeichens mal irgend
ein anderes Zeichen für die String-Ende Kennung benutzt. Zb. ein ';'
Dadurch kannst du nämlich dein Problem sehr einfach in 2 Teilprobleme
aufteilen, die du getrennt testen kannst.
Anstatt 2 Programme gleichzeitig zu schreiben, die zusammenarbeiten
müssen und bei denen du nie weißt, wo du einen Fehler gemacht hast,
kannst du die Programm einzeln schreiben und auch einzeln testen.
Alles was du dazu brauchst, ist ein Terminal oder ein Terminalprogramm,
welches das was du tippst über die serielle Schnittstelle verschickt,
bzw. alles was über die serielle Schnittstelle empfangen wird einfach
nur anzeigt.
Du testest erstmal
Terminal -> Receiver
und kannst den Text der zum Receiver Programm geht über die Tastatur
eingeben. Dadurch bist du erst mal unabhängig von einem funktionierenden
Sender Programm und kannst den Empfänger entwickeln und auch testen.
Dann testest du
Sender -> Terminal
und das Terminal zeigt dir an, was tatsächlich gesendet wurde.
Das machst du solange, bis der Text der am Terminal ankommt exakt
dem entspricht, was du haben möchtest (und den du die ganze Zeit
am Terminal eingetippt hast um den Receiver zu testen).
Wenn dann alles klappt, dann kannst du ja das Terminal rausnehmen
und das Gesendete direkt vom Sender zum Receiver schicken lassen.
Wenn dann noch Probleme auftauchen, dann liegt das daran, dass der
Sender schneller sendet als der Recevier das Empfangene verarbeiten
kann. Du weißt aber, dass die Programme grundsätzlich funktionieren
und du dich nur noch mit einem Handshake beschäftigen musst.
Im Moment führst du einen 2-Frontenkrieg an Sender und Empfänger
gleichzeitig. Das hat schon ganz anderen als dir das Genick gebrochen.
Karl heinz Buchegger wrote:
> PS:> Wenn deine Empfangsroutine am Erhalt eines '\r' erkennt> dass der String dadurch vollständig ist, dann wäre es auch> ganz gut, wenn deine Sendefunktion auch mal das Zeichen '\r'> wegschicken würde.>
Mein Fehler. Hab übersehen, dass deine writeport Funktion an
jede Zeile ein 0x0D anhängt.
hallo karl,
ich habe alle Veänderungen gemacht und jetzt klappt gut. ich danke dir
für alle Tipps .Ich werde trotzdem mit dem Terminal probieren, wie du
gestern vorgeschlagen hat.
Jetz habe ich zwei String in der Variable sCmd kopiert ich kekomme die
beide String im empfang Funktion.Jetz möchte ich, dass ein Ziffer von
meiner LED blinkt nach dem Empfang von jedem String, oder wenn jedes mal
ein '\r'gefunden wird.
Danke