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


von Hari (Gast)


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

von Karl H. (kbuchegg)


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.

von Hari (Gast)


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)?

von Falk B. (falk)


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

von holger (Gast)


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.

von Magnus Müller (Gast)


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

von holger (Gast)


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.

von Karl H. (kbuchegg)


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.

von 2923 (Gast)


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

von Hari (Gast)


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.

von Karl H. (kbuchegg)


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"

von Falk B. (falk)


Lesenswert?


von Hari (Gast)


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!

von Karl H. (kbuchegg)


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.
1
void USART_Transmit_String( const char* String )
2
{
3
  while( *String ) {
4
    USART_Transmit( *String );
5
    String++;
6
  }
7
}

Jetzt probierst du diese Funktion mal aus:
1
int main()
2
{
3
  ....
4
5
  while( 1 ) {
6
    USART_Transmit_String( "Hallo" );
7
  }
8
}

Wenn das soweit in Ordnung ist, gehts weiter:
1
int main()
2
{
3
  char xAngStr[20];
4
  int xAngularRate = 25;
5
6
  while( 1 ) {
7
    itoa( xAngularRate, xAngStr, 10);
8
    USART_Transmit_String( xAngStr );
9
  }
10
}


Und dann überprüfst du als allererstes mal, ob dein µC die
Texte auch so empfängt wie du sie abschickst:
1
char xAcc[5];
2
char yAcc[5];
3
char zAcc[5];
4
5
  ....
6
7
  while(initialCharacter!='#'){
8
    initialCharacter=USART_Receive();
9
  }
10
11
  xAcc[0] = USART_Receive();
12
  xAcc[1] = USART_Receive();
13
  xAcc[2] = USART_Receive();
14
  xAcc[3] = USART_Receive();
15
  xAcc[4] = '\0';
16
17
  USART_Receive();
18
  yAcc[0] = USART_Receive();
19
  yAcc[1] = USART_Receive();
20
  yAcc[2] = USART_Receive();
21
  yAcc[3] = USART_Receive();
22
  yAcc[4] = '\0';
23
24
  USART_Receive();
25
  zAcc[0] = USART_Receive();
26
  zAcc[1] = USART_Receive();
27
  zAcc[2] = USART_Receive();
28
  zAcc[3] = USART_Receive();
29
  zAcc[4] = '\0';
30
31
  USART_Transmit_String( "Received X:#" );
32
  USART_Transmit_String( xAcc );
33
  USART_Transmit_String( "# Y:#" );
34
  USART_Transmit_String( yAcc );
35
  USART_Transmit_String( "#Z: #" );
36
  USART_Transmit_String( zAcc );
37
  USART_Transmit_String( "#\r" );
38
39
  ....

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.

von Hari (Gast)


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!

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.