www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik mit USART auf bestimtes Zeichen warten


Autor: Hari (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
möchte mit dem USART auf ein bestimmtes Zeichen warten, bespielsweise 
auf '#'
kann man das so machen oder habt ihr bessere vorschläge:

while(USART_Receive()!='#');  //verweile in dieser Schlaufe bis # 
ankommt

USART_Receive liefert das empfange char zurück

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hari wrote:

> kann man das so machen oder habt ihr bessere vorschläge:

Das kommt drauf an, ob der4 µC in der Zwischenzeit noch
andere Aufgaben zu erledigen hat.

Meistens vermeidet man solche Warteschleifen, wie der Teufel
das Weihwasser. Üblicherweise ist der µC Code ja in eine
Hauptschleife eingebunden.

  while( 1 ) {
    ... Programmlogik
  }

Wenn jetzt etwas passieren soll, wenn ein # empfangen wird,
dann schreibt man das auch genau so


  while( 1 ) {
    ...
    id( USART_Receive() == '#' ) {
      ... mach was wenn # empfangen wird
    }
  }

Aus dem gleichen Grund ist es auch oft nicht ratsam, die
USART_Receive Funktion als wartende Funktion auszuführen.
Die USART_Receive sollte auch in dem Fall in dem kein
Zeichen empfangen wurde sofort zurückkehren und diesen
Umstand (kein Zeichen empfangen) durch einen Returncode
mitteilen.

Wenn es darum geht, dass von der Gegenstelle eine Empfangssequenz
kommt, in der das # irgendetwas kannzeichnet, dann ist es meist
besser, zb mittels einer Interrupt Steuerung das komplette
Kommando zu empfangen (als String) und erst dann, wenn die
komplette Befehlssequenz empfangen wurde, mit der Auswertung
zu beginnen.

Autor: Hari (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ja ich empfange eine ganze Seqeunz, wobei eben das '#' den Startpunkt 
kennzeichnet. das ganze sieht dann folgendermassen aus:

Bsp:
#0558,1067,0844
#0168,0937,0359
...

diese Sequenz gibt mir die Beschleunigungen in alle drei Richtungen 
wieder.
Diese Zeichenfolge wird dann mit einer bestimmten Frequenz ständig 
wiedergegeben, so alle 50HZ.
Was ich schlussendlich will sind die Zahlenwerte natürlich und ich 
dachte ich könnte es eben folgendermassen machen:

while(1){
while(USART_Receive()!='#');
USART_Receive();
xAcc[0]=USART_Receive();
xAcc[1]=USART_Receive();
xAcc[2]=USART_Receive();
xAcc[3]=USART_Receive();
USART_Receive(); // Komma empfangen
yAcc[0]=USART_Receive();
yAcc[1]=USART_Receive();
yAcc[2]=USART_Receive();
yAcc[3]=USART_Receive();
USART_Receive();
zAcc[0]=USART_Receive();
zAcc[1]=USART_Receive();
zAcc[2]=USART_Receive();
zAcc[3]=USART_Receive();
...auswerten usw...
}

Nebenbei will ich ja eigentlich ja gar nichts anderes tun, deshalb denke 
ich kann ich gut in dieser schlaufe verweilen und auf # warten. Was 
meint ihr zum restlichen Programmstück, sollte das so klappen(leider 
konnte ich es noch nicht ausprobieren)?

Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@ Hari (Gast)

>Was ich schlussendlich will sind die Zahlenwerte natürlich und ich
>dachte ich könnte es eben folgendermassen machen:

Prinzipiell möglich, aber praktisch bisweilen problematisch. Du solltest 
ERST den String koplett empfangen, dann prüfen und dann erst die Zahlen 
ind die Variablen schreiben. Ist nicht nur übersichtlicher sondern auch 
sicherer.

>Nebenbei will ich ja eigentlich ja gar nichts anderes tun, deshalb denke
>ich kann ich gut in dieser schlaufe verweilen und auf # warten. Was

Und was ist, wenn das Startzeichen durch einen Übertragungsfehler 
verfälscht wird?

MFG
Falk

Autor: holger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>(leider konnte ich es noch nicht ausprobieren)?

Und was möchtest du jetzt ? Eine Funktionsgarantie ?
Probier deinen Kram bitte selber aus bevor du Fragen stellst.
Wenns irgendwo klemmt dann fragst du nochmal nach.

Autor: Magnus Müller (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
holger wrote:
> Und was möchtest du jetzt ? Eine Funktionsgarantie ?
> Probier deinen Kram bitte selber aus bevor du Fragen stellst.

Für einen Gast bist du aber ziemlich unhöflich!

> Wenns irgendwo klemmt dann fragst du nochmal nach.

Und du bist dann auch bestimmt der Erste, der einen hilfreichen Tipp 
abgibt, oder?

Gruß,
Magnetus

Autor: holger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>> Probier deinen Kram bitte selber aus bevor du Fragen stellst.
>Für einen Gast bist du aber ziemlich unhöflich!

Warum ? Es war ein "bitte" in der Antwort.

>Und du bist dann auch bestimmt der Erste, der einen hilfreichen Tipp
>abgibt, oder?

Sicher, warum nicht.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Und was ist, wenn das Startzeichen durch einen Übertragungsfehler
> verfälscht wird?

@OP

...
Muss ja nicht nur das Startzeichen sein.
Was, wenn auf der UART zb dieses empfangen wird

#5300,786,z9u&&%

Das Problem:
Die ersten beiden Variable hat bereits die neuen Werte erhalten,
während die dritte Kombinationh ganz offensichtlich einer
Störung zum Opfer gefallen ist.

Schon aus dem Grund ist es vernünftiger die ganze Zeile zunächst
mal als String zu empfangen, danach Plausibilitätstests
durchzuführen und erst dann die Werte tatsächlich zu übernehmen.

Damit stellt sich aber die Frage *Ich will auf ein '#' warten'
gar nicht mehr. Du willst auf den Erhalt einer kompletten Zeile
warten.
In dieser Zeile muss das erste Zeichen ein '#' sein, gefolgt
von 3 Zahlen, die durch ',' getrennt sind. Erst wenn diese
Bedingungen erfüllt sind, werden die erhaltenen Zahlen
weiterverteilt.

Das Leben als Programmierer kann man sich so viel einfacher
machen, wenn man sich an die Reihenfolge:
   Eingabe
   Eingabe prüfen, wenn gültig, dann
      Verarbeitung
      Ausgabe
hält.

Autor: 2923 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Der Standardansatz ist eine Zustandsmaschine im main oder im interrupt.

interrupt rx;
 rxb:=UARTRx;
 rxcame:=true;
end;

state:=0;

main :
..
while true do
 if rxcame then
  case state of
  0: if rxb='#' then ... state:=1; |
  1: if rxb=............ state:=2; |
  ..
  end;
  rxcame:=false;
 end; // rxcame

Autor: Hari (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Schon aus dem Grund ist es vernünftiger die ganze Zeile zunächst
> mal als String zu empfangen, danach Plausibilitätstests
> durchzuführen und erst dann die Werte tatsächlich zu übernehmen.

Leider bin ich mit dem USART noch nicht ganz so vertraut, deshalb meine 
Frage: Wie kann ich die ganze Zeile zuerst als String empfangen? War 
bisher immer eher zeichenorientiert damit umgegangen.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hari wrote:
>> Schon aus dem Grund ist es vernünftiger die ganze Zeile zunächst
>> mal als String zu empfangen, danach Plausibilitätstests
>> durchzuführen und erst dann die Werte tatsächlich zu übernehmen.
>
> Leider bin ich mit dem USART noch nicht ganz so vertraut, deshalb meine
> Frage: Wie kann ich die ganze Zeile zuerst als String empfangen? War
> bisher immer eher zeichenorientiert damit umgegangen.

Die Gegenstelle sendet ein bestimmtes Zeichen, das als 'Ende
der Zeile' gilt. Genau dieses Zeichen wird zb übertragen, wenn du
in einem Terminal auf Return (Die grosse Taste mit dem Haken)
drückst. In C schreibt sich dieses Zeichen als '\r'.

Du sammelst also Zeichen in einem Array, bis von der Gegenstelle
ein '\r' daherkommt. Dann hast du eine komplette Zeile empfangen
und kannst dich daran machen, diese Auszuwerten.

Beitrag "ASCII Verarbeitung optimieren"

Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert

Autor: Hari (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ok angenommen dieser Programmabschnitt funktioniert soweit:

while(initialCharacter!='#'){
  initialCharacter=USART_Receive();
}

xAcc[0]=USART_Receive();
xAcc[1]=USART_Receive();
xAcc[2]=USART_Receive();
xAcc[3]=USART_Receive();
USART_Receive();
yAcc[0]=USART_Receive();
yAcc[1]=USART_Receive();
yAcc[2]=USART_Receive();
yAcc[3]=USART_Receive();
USART_Receive();
zAcc[0]=USART_Receive();
zAcc[1]=USART_Receive();
zAcc[2]=USART_Receive();
zAcc[3]=USART_Receive();

xRate[4]='\0';  //für String Nullcharakter setzen, richtig???
yRate[4]='\0';
zRate[4]='\0';
xAcc[4]='\0';
yAcc[4]='\0';
zAcc[4]='\0';

hier wandle ich jetzt die strings in integer um, geht das so?

/*** process signals ***/
xAcceleration=atoi(xAcc);
yAcceleration=atoi(yAcc);
zAcceleration=atoi(zAcc);

und hier will ich die x-beschleunigung wieder zurück in einen string 
wandeln (nur für debugging zwecke, um zu schauen ob itoa und atoi das 
amchen was ich will) diesen string sende ich dann an den PC der jetzt 
den richtigen Wert erhalten sollte, tut er aber nicht :-( irgendwo 
steckt noch der Wurm drin.

itoa(xAngularRate,xAngStr,10);
USART_Transmit(xAngStr[0]);
USART_Transmit(xAngStr[1]);
USART_Transmit(xAngStr[2]);
USART_Transmit(xAngStr[3]);

Bin dankbar für eure Hilfe!

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hari wrote:

> itoa(xAngularRate,xAngStr,10);
> USART_Transmit(xAngStr[0]);
> USART_Transmit(xAngStr[1]);
> USART_Transmit(xAngStr[2]);
> USART_Transmit(xAngStr[3]);

Schreib dir als allererstes mal eine Funktion, mit der
du einen String ausgeben kannst. Dieses ständige Rumhantieren
mit einzelnen Charactern ist ja nicht zum aushalten.
void USART_Transmit_String( const char* String )
{
  while( *String ) {
    USART_Transmit( *String );
    String++;
  }
}

Jetzt probierst du diese Funktion mal aus:
int main()
{
  ....

  while( 1 ) {
    USART_Transmit_String( "Hallo" );
  }
}

Wenn das soweit in Ordnung ist, gehts weiter:

int main()
{
  char xAngStr[20];
  int xAngularRate = 25;

  while( 1 ) {
    itoa( xAngularRate, xAngStr, 10);
    USART_Transmit_String( xAngStr );
  }
}


Und dann überprüfst du als allererstes mal, ob dein µC die
Texte auch so empfängt wie du sie abschickst:

char xAcc[5];
char yAcc[5];
char zAcc[5];

  ....

  while(initialCharacter!='#'){
    initialCharacter=USART_Receive();
  }

  xAcc[0] = USART_Receive();
  xAcc[1] = USART_Receive();
  xAcc[2] = USART_Receive();
  xAcc[3] = USART_Receive();
  xAcc[4] = '\0';

  USART_Receive();
  yAcc[0] = USART_Receive();
  yAcc[1] = USART_Receive();
  yAcc[2] = USART_Receive();
  yAcc[3] = USART_Receive();
  yAcc[4] = '\0';

  USART_Receive();
  zAcc[0] = USART_Receive();
  zAcc[1] = USART_Receive();
  zAcc[2] = USART_Receive();
  zAcc[3] = USART_Receive();
  zAcc[4] = '\0';

  USART_Transmit_String( "Received X:#" );
  USART_Transmit_String( xAcc );
  USART_Transmit_String( "# Y:#" );
  USART_Transmit_String( yAcc );
  USART_Transmit_String( "#Z: #" );
  USART_Transmit_String( zAcc );
  USART_Transmit_String( "#\r" );

  ....

Du musst dir angewöhnen alles und jeden zu überprüfen.
Wenn du einen String empfängst, dann wird als allererstes
gecheckt, ob das auch funktioniert. Es ist sinnlos mit
falschen Daten weiterzurechnen und hinterher sich zu beschweren,
dass da was falsches rauskommt.

Ob einzelne Character korrekt übertragen werden, hast du hoffentlich
schon getestet.

> ok angenommen dieser Programmabschnitt funktioniert soweit:
     **********

Dieses Wort musst du auf jeden Fall vermeiden. Entweder etwas
funktioniert oder es funktioniert nicht. Aber 'angenommen dass'
ist ein Schuss der öfter als dir lieb ist nach hinten losgeht.

Autor: Hari (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Besten Dank für die tolle Hilfe, bin wirklich dankbar! jetzt läufts mal 
grob, und morgen gehts dann noch darum das Programm "schön" zu machen 
mit Interrupts und Charakterprüfung usw. Aber nochmals vielen Dank an 
alle und speziell an Karl Heinz!

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.