Forum: Mikrocontroller und Digitale Elektronik Daten empfangen über UART


von Katia (Gast)


Lesenswert?

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

von Katia (Gast)


Angehängte Dateien:

Lesenswert?

anbei steht meine Code. hab vergessen in der 1. Beitrag hochzuladen

von klugscheisser (Gast)


Lesenswert?

und meine küche spricht auch spanisch, aber nur wenn der geschirrspüler 
tango schreibt....

von Spice (Gast)


Lesenswert?

cool wäre es zu wissen, was für einen controller du verwendest wenn du 
schon jemanden zur fehlersuche in einem mehrzeiler suchst...

von katia (Gast)


Lesenswert?

ich benutze den AT90CAN128
danke

von Karl H. (kbuchegg)


Lesenswert?

Ich hab mir mal dein Send Programm vorgenommen.
Ausschnitt:
1
  char sCmd[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
int writeport(int fd, char *chars) {
2
  int len = 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.

von Karl H. (kbuchegg)


Lesenswert?

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.

von Katia B. (katia)


Angehängte Dateien:

Lesenswert?

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.

von Karl H. (kbuchegg)


Lesenswert?

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
char string[100];
2
unsigned char nextCharPos;
3
volatile unsigned char stringReady;
4
5
ISR (SIG_UART0_RECV)
6
{  
7
  unsigned char c = 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
int main()
2
{
3
  char receivedString[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.

von Karl H. (kbuchegg)


Lesenswert?

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.

von Karl H. (kbuchegg)


Lesenswert?

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.

von Katia B. (katia)


Angehängte Dateien:

Lesenswert?

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

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.