mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik UART Rx Bits


Autor: Bernd Schuster (mms)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

ich hab gerade ein Problem mit dem Xmodem Protokoll und der usart 
schnittstelle vom AT91Rm9200 controller.

Wenn ich versuche Daten vom Hyperterminal via Xmodem an den Controller 
zu schicken, erhalte ich das SOH Bit allerdings keine weiteren Bits 
mehr.

Die einzelnen Bits / Charakter lese ich folgendermaßen aus:
char cn; 

cn = AT91F_Rx_Char (); 
// if(cn == SOH) -> dann nächstes zeichen auslesen

//entspricht paket-number
cn = AT91F_Rx_Char (); 

//usw


char AT91F_Rx_Char (void)
{
  if (AT91F_US_RxReady((AT91PS_USART)AT91C_BASE_DBGU)) 
  {
    return((char)AT91F_US_GetChar((AT91PS_USART)AT91C_BASE_DBGU));
  }

  return(0); 
} 


AT91F_US_RxReady gibt als Rückgabewerte 1 zurück, wenn ein Charakter 
ausgelesen werden kann aus dem US_RHR register. Muss man nach dem ersten 
Lesen, irgendwelche Register zurücksetzen?

Gruß
Bernd

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Du solltest näher auf den ersten Codeteil eingehen. Die drei Zeilen sind 
für eine Diagnose zu wenig.

Generell finde ich die Funktion AT91F_Rx_Char() unglücklich geschrieben, 
weil man nicht zwischen einem empfangenen <NUL> und "kein Zeichen 
ausgelesen" unterscheiden kann.

Man könnte das verbessern, indem man den Rückgabewert auf int erweitert 
und z.B. -1 für "kein Zeichen ausgelesen" verwendet (andere negative 
Zahlen entsprechend für andere Fehler) und legale Zeichen 0-255 im 
Lowbyte zurück gibt.

Weitere Probleme können auftreten, weil AT91F_Rx_Char() keine wartende 
Funktion ist. um darauf genauer einzugehen, bräuchte man mehr Einblick 
in den Auswertecode (s.o.)

Autor: Bernd Schuster (mms)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Generell finde ich die Funktion AT91F_Rx_Char() unglücklich geschrieben,
>weil man nicht zwischen einem empfangenen <NUL> und "kein Zeichen
>ausgelesen" unterscheiden kann.

das ist genau das problem. Hab mir grad mal eine for-schleife 
geschrieben, die solange nicht verlassen wird bis ein Zeichen ungleich 
0x00 ankommt. Und es handelt sich tatsächlich um das 0x01, welches ich 
auch erwarte.

>Weitere Probleme können auftreten, weil AT91F_Rx_Char() keine wartende
>Funktion ist

hab mich hier zu sehr vom datenblatt verleiten lassen, indem steht:

"RXRDY - receiver ready: -> wenn 1 => At least one complete character 
has been received and US_RHR has not yet been read"

-> ich bräuchte ein Register, welches wirklich nur dann seinen Wert 
ändert, wenn neue Daten / ungleich NULL angekommen sind.


>Weitere Probleme können auftreten, weil AT91F_Rx_Char() keine wartende
>Funktion ist. um darauf genauer einzugehen, bräuchte man mehr Einblick
>in den Auswertecode (s.o.)

Im Prinzip ist mein kleiner Code-Abriss oben genau das was ich mache.
void Xmodem_Start(unsigned char *ptr)
{
  unsigned char cn;
 
  for(;;)
  {
     cn = AT91F_Rx_Char ();

     if(cn == SOH)
        break;       //SOH angekommen 
  }

  //nächstes zeichen: paket number
  cn = AT91F_Rx_Char ();

  //paket number inverse auslesen
  cn = AT91F_Rx_Char ();

  //.... usw 
 
  //anschließend daten auslesen von xmodem 
  for(i=0; i<128; i++)
  {
     *ptr++ = AT91F_Rx_Char ();
 
  } 


  //checksum überprüfen 
}

Im Prinzip suche ich jetzt nach einer Möglichkeit um erst die Funktion 
AT91F_Rx_Char() aufzurufen, wenn wirklich neue Daten angekommen sind und 
keine NULL-Bytes.

Gruß
Bernd

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Du bekommst keine weiteren Bytes nach dem SOH, weil deine 
Einlesefunktion nicht auf Bytes wartet und im Verhältnix zu den 
reinkommenden Daten viel zu schnell ist. Du bekommst quasi immer ein 
Nullbyte als Resultat dafür, dass noch oder gerade keine Zeichen 
empfangen wurden.

Du hast mehrere sich gegenseitig ausschliessende Möglichkeiten...

1/ Forme AT91F_Rx_Char() generell in eine wartende Funktion um.

char AT91F_Rx_Char (void)
{
  while(1)
    if (AT91F_US_RxReady((AT91PS_USART)AT91C_BASE_DBGU))
    {
      return((char)AT91F_US_GetChar((AT91PS_USART)AT91C_BASE_DBGU));
    }
}

Diese Lösung kann ich nicht wirklich empfehlen, weil es komplett 
blockiert, wenn erwartete Zeichen ausbleiben.

2/ Behalte AT91F_Rx_Char() als nicht wartende Funktion, aber ändere den 
Rückgabewert, so dass du Fehler (kein Zeichen) erkennen kannst.

Damit kannst du je nach Programmablauf eine wartende Funktion oder eine 
nicht-wartende Funktion daraus machen.

Die Funktion kann dafür einen Datentyp zurückgeben, der char (oder 
unsigned char je nach Geschmack) zurückgeben kann plus den Fehlercode 
(s.o), also z.B. int.

Es geht auch, wenn man mit weiteren Argumenten arbeitet.

char AT91F_Rx_Char (char *err)
{
  if (AT91F_US_RxReady((AT91PS_USART)AT91C_BASE_DBGU))
  {
    *err = 0;
    return (char) AT91F_US_GetChar((AT91PS_USART)AT91C_BASE_DBGU);
  }

  *err = 1;
  return 0 ;
}

Im Programm selbst prüfst du die Fehlerbedingung ab und reagierst 
darauf.

  char err;
  do
  {
    //nächstes zeichen: paket number
    cn = AT91F_Rx_Char (&err);
  } while (err); // AUF ZEICHEN WARTEN!

Man kann auch Rückgabewert und Argument tauschen. Man findet das üfters 
in Bibliotheken:

char AT91F_Rx_Char (char *c)
{
  if (c && AT91F_US_RxReady((AT91PS_USART)AT91C_BASE_DBGU))
  {
    *c = AT91F_US_GetChar((AT91PS_USART)AT91C_BASE_DBGU);
    return ZEICHEN_DA;
  }

  // *c unverändert lassen
  return KEIN_ZEICHEN_DA;
}

  char cn;
  while ( AT91F_Rx_Char (&cn) == KEIN_ZEICHEN_DA )
    ; // AUF ZEICHEN WARTEN!

  // hier liegt ein gültiges cn vor.

Das blockiert aber auch, wenn den Sender mitten im Protokoll nichts mehr 
schickt.

Günstiger finde ich es daher, das Protokoll in einer state machine zu 
implementieren, die Zustände für Warten und Timeout kennt.

Autor: Bernd Schuster (mms)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
vielen dank für deine erklärungen. Polling ist für mich hier völlig 
ausreichend, da der Processor währenddessen eh nichts zu tun hat. 
Ansonsten ist natürlich eine Interrupt-Routine besser.

werd meine funktion entsprechend umformen.

Gruß
Bernd

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.