Forum: Mikrocontroller und Digitale Elektronik String empfangen und auswerten


von Markus S. (Firma: A.S.) (xray)


Lesenswert?

Hallo !

Ich bin noch Anfänger in Sachen "c" und steh grad vor nem Problem, das 
ich mit Hilfe meines tollen Lehrbuchs irgendwie auch nicht gelöst 
bekomme. Wahrscheinlich für die meisten eine  simple Sache. Wie kann ich 
mehrere Bytes, welche über den USART kommen (maximal 64Byte) in einen 
Buffer speichern und auswerten ? Ich möchte also Display Befehle die in 
etwa so ankommen"11 04 1B 41 01 01 73" (11 gleich Anfang, 04 gleich 
länge der Nutzdaten, 73 = Checksumme) mit einem Switch Case auswerten 
können. Hier mal ein Codeschnipsel;
1
 //********************FUNKTIONEN******************************
2
3
//--------------------DATEN IM EDIP-PUFFER--------------------
4
int paket_fordern()
5
6
{
7
  SBUF_EDIP=0;
8
9
  putch(0x12);   //<DC2>
10
  putch(0x01);  //1(len)
11
  putch(0x53);  //S
12
  putch(0x66);  //66(bcc)
13
14
  while((!(UCSRA & (1<<UDRE))))
15
  {
16
    getche();
17
  }
18
19
  char x=UDR; 
20
  switch(x)
21
  {
22
23
    case '11 04 1B 41 01 01 73':   //rote LED an  
24
    {
25
      PORTB=(1<<PB0);
26
    }
27
      
28
    break;
29
30
    case '11 04 1B 41 01 02 74' :   //grüne LED an    
31
    {
32
      PORTB=(1<<PB2);
33
    }
34
    
35
    break;
36
37
    default :         
38
    {
39
      ;              //beide aus
40
    }
41
    
42
    break;
43
  }
44
  
45
  return(0);
46
}
Ich müsste wahrscheinlich ein ARRAY anlegen richtig ? Aber wie genau ? 
Und kann ichs dann wirklich mit switch case machen ???

Die Daten werden auf jeden Fall schonmal so empfangen, das hat mir AVR 
Term gezeigt. Schonmal DANKE für jede Hilfe !

Achso, hier noch die Funktion getche():
1
//Eingabe mit Echo von USART oder UART
2
3
unsigned char getche (void)  //warten und lesen mit echo
4
{
5
int x;        //Hilfsvariable
6
#ifdef UCSRA      //USART
7
while (!( UCSRA & (1<<RXC)));  //warte bis zeichen da
8
x=UDR;        //abholen und speichern
9
while (!( UCSRA & (1<<UDRE)));  //warte solange sender besetzt
10
#else        //UART
11
while (!( USR & (1<<RXC)));  //warte bis zeichen da
12
x=UDR;        //abholen und speichern
13
while (!( UCSRA & (1<<UDRE)));  //warte solange sender besetzt
14
#endif
15
UDR=x;        //echo senden
16
return x;      //zeichen zurückgeben
17
}

von Peter II (Gast)


Lesenswert?

Markus S. schrieb:
> Ich möchte also Display Befehle die in
> etwa so ankommen"11 04 1B 41 01 01 73"

bist du sicher das sie wirklich so gesendet werden, oder werden sie nur 
so angezeigt? Hex mit leerzeichen zu senden ist recht ungeöhnlich. Ich 
vermute mal das eigentlich nur "bytes" gesendet werden.

von Markus S. (Firma: A.S.) (xray)


Angehängte Dateien:

Lesenswert?

Achso, gute Frage. Aber laut dem Datenblatt(EDIP Display) ist das so 
richtig. Hier auf der Seite 10 stehts so

von Peter II (Gast)


Lesenswert?

Markus S. schrieb:
> Hier auf der Seite 10 stehts so

ich lese das so, das hier wirklich binary daten übertragen werden also 
nicht HEX.

von Markus S. (Firma: A.S.) (xray)


Lesenswert?

Na gut, wär ja auch nicht das problem, aber wie ich die jetzt annehme 
und auswerte weiss ich trotzdem nicht :-)

von Markus S. (Firma: A.S.) (xray)


Lesenswert?

Da steht aber auch auf Seite 12 unten, dass Ascii und Binary möglich 
ist....

von Peter II (Gast)


Lesenswert?

Markus S. schrieb:
> Da steht aber auch auf Seite 12 unten, dass Ascii und Binary möglich
> ist....

dann sollte man erstmal in erfahrung bringen was wirklich ankommt. Er 
will ja scheinbar ein Display simulieren.

von Markus S. (Firma: A.S.) (xray)


Lesenswert?

Also da ja die letzten Zahlen der dargestelten Strings (73 bei grün und 
74 bei rot) ja in ASCII s und t sind, und ich in den Anfängen einzelne 
bytes im switch ausgewertet hab (in dem Beispiel Case s und Case t), 
haben die LEDs darauf reagiert. Also geh ich davon aus, dass ich mit 
ASCII darstellung arbeiten kann.

von Uwe (Gast)


Lesenswert?

Du empfängst mit dem UART immer nur 1 Byte. Es liegt an dir diese 
irgendwie zu speichern. Da wäre schon sowas wie eine Variable mit vielen 
Bytes gut. Also ein Array von chars. Das macht man so in C :
char Buffer [16];
danach kannst du über eine Zahl oder Variable (Index genannt) auf 
einzelne chars zugreifen
int i=0;
char was;
was=Buffer[5];
was=Buffer[i];

Wobei 0 das erste Element eines Arrays ist.


11 04 1B 41 01 01 73
11 04 1B 41 01 02 74

Du müßtest also an Position 5 gucken.

Aber du solltest dein Protokol interpretieren und die. Denn genau dafür 
braucht man so ein Startbyte und die Längeninformation damit man 
ausrechenen kann wann die Checksumme kommt. Statemachine bzw. 
Zustandsautomat programmieren der dir das Protokoll aufdröselt.

von Peter II (Gast)


Lesenswert?

Markus S. schrieb:
> Also geh ich davon aus, dass ich mit
> ASCII darstellung arbeiten kann.

gut dann sollte du erstmal anfangen das Protokoll umzusetzen. Du muss 
also den Anfang und das ende der Nachricht erkennen können.

du braucht einen einen Puffer für die daten der erstmal gefüllt wird

uint8_t[80]  data


dort muss du erstmal schaffen ein datenpacket abzulegen, dann kannst du 
mit dem auswerten erst weitermachen.

von Markus S. (Firma: A.S.) (xray)


Lesenswert?

Danke Leute, das könnte mich ja schonmal weiter bringen. Also könnte ich 
mir ja aus dem ARRAY jedesmal das zweite byte  also Buffer[1] auswerten, 
damit ich schonmal die Länge der Nutzdaten habe. Der Anfang ist ja immer 
DC1 (also die 11), das steht ja fest

von Peter II (Gast)


Lesenswert?

Markus S. schrieb:
> Der Anfang ist ja immer
> DC1 (also die 11), das steht ja fest

und was ist wenn eine 11 gesendet wird (also eine 11 dargestllt werden 
woll)?

von Markus S. (Firma: A.S.) (xray)


Lesenswert?

Hm ? Die soll ja nie dargestellt werden. Im Grunde gehts grad nur um die 
DOWNCODES der Touchbuttons. Der Button "grün" z.B. hat jetzt grad für 
Tests die "1", und die steht immer nach "A 1". Also weiss ich, dass 
wennich ein Button abfrage, wo ich gucken muss.

von Markus S. (Firma: A.S.) (xray)


Lesenswert?

Mann mann mann.... ich bekomme bei dem Drücken auf "grün" ja direkt 
meinen Code zum Displayspeicher auslesen, das ACK vom Display, dann 
nochmal den Auslesecode und dan erst Den Inhalt des Displaypuffers 
zurück - alles gleichzeitig !. Ich werde noch verrückt mit der 
Auswertung :-(

Das sieht so aus:
12 01 53 66 (Anforderung Sendepuffer) 06 (Das ACK vom Display= 12 01 53 
66 (wieder der Code) 11 04 1B 41 01 01 73 (Pufferinhalt des Displays) 
Was ein "KOT" !

Ist das denn so möglich ??
1
uint8_t Buffer[64]; // 
2
3
//********************FUNKTIONEN******************************
4
5
//--------------------DATEN IM EDIP-PUFFER--------------------
6
int paket_fordern()
7
8
{
9
  SBUF_EDIP=0;
10
11
  putch(0x12);   //<DC2>
12
  putch(0x01);  //1(len)
13
  putch(0x53);  //S
14
  putch(0x66);  //66(bcc)
15
16
  while (!( UCSRA & (1<<RXC)));  //warte bis zeichen da
17
  {
18
  Buffer[64]=UDR;
19
  }
20
  
21
  int i=0;
22
  char Tastencode;
23
  Tastencode=Buffer[14];
24
25
  switch(Tastencode)
26
  {
27
28
    case '0x01' :   //rote LED an  
29
    {
30
      PORTB=(1<<PB0);
31
    }
32
33
    break;
34
35
    case '0x02' :   //grüne LED an    
36
    {
37
      PORTB=(1<<PB2);
38
    }
39
40
    break;
41
42
    default :         
43
    {
44
      ;              //beide aus
45
    }
46
47
    break;
48
  }
49
50
  return(0);
51
}

von Peter II (Gast)


Lesenswert?

Markus S. schrieb:
> Buffer[64]=UDR;

was erwartest was was hier passieren soll?

Du sollst zuerst ein vollständiges Packet (mehre zeichen) einlesen und 
wenn das vollständig ist auswerten.

von Markus S. (Firma: A.S.) (xray)


Lesenswert?

Danke, habs auch grad erst verstanden, aber schon umgesetzt. Die 
Auswertung stimmt aber immer noch nicht, obwohl ich mit dem Pointer 
mehrere Positionen probiert habe.
1
//--------------------DATEN IM EDIP-PUFFER--------------------
2
int paket_fordern()
3
4
{  Buffer[64]=0;
5
6
  SBUF_EDIP=0;
7
8
  putch(0x12);   //<DC2>
9
  putch(0x01);  //1(len)
10
  putch(0x53);  //S
11
  putch(0x66);  //66(bcc)
12
  
13
  while (!( UCSRA & (1<<RXC)));  //warte bis zeichen da
14
  {
15
  Buffer[0]=UDR;
16
  Buffer[1]=UDR;
17
  Buffer[2]=UDR;
18
  Buffer[3]=UDR;
19
  Buffer[4]=UDR;
20
  Buffer[5]=UDR;
21
  Buffer[6]=UDR;
22
  Buffer[7]=UDR;
23
  Buffer[8]=UDR;
24
  Buffer[9]=UDR;
25
  Buffer[10]=UDR;
26
  Buffer[11]=UDR;
27
  Buffer[12]=UDR;
28
  Buffer[13]=UDR;
29
  Buffer[14]=UDR;
30
  Buffer[15]=UDR;
31
  Buffer[16]=UDR;
32
  Buffer[17]=UDR;
33
  Buffer[18]=UDR;
34
  Buffer[19]=UDR;  
35
  }
36
37
  int i=0;
38
  char Tastencode;
39
  Tastencode=Buffer[6];
40
41
  switch(Tastencode)
42
  {
43
44
    case '01' :   //rote LED an  
45
    {
46
      PORTB=(1<<PB0);
47
    }
48
49
    break;
50
51
    case '02' :   //grüne LED an    
52
    {
53
      PORTB=(1<<PB2);
54
    }
55
56
    break;
57
58
    default :         
59
    {
60
      ;              //beide aus
61
    }
62
63
    break;
64
  }
65
66
  return(0);
67
}

von Karl H. (kbuchegg)


Lesenswert?

1
  while (!( UCSRA & (1<<RXC)));  //warte bis zeichen da
2
  {
3
  Buffer[0]=UDR;
4
  Buffer[1]=UDR;
5
  Buffer[2]=UDR;
6
  Buffer[3]=UDR;
7
  Buffer[4]=UDR;
8
  Buffer[5]=UDR;
9
  Buffer[6]=UDR;
10
  Buffer[7]=UDR;
11
  Buffer[8]=UDR;
12
  Buffer[9]=UDR;
13
  Buffer[10]=UDR;
14
  Buffer[11]=UDR;
15
  Buffer[12]=UDR;
16
  Buffer[13]=UDR;
17
  Buffer[14]=UDR;
18
  Buffer[15]=UDR;
19
  Buffer[16]=UDR;
20
  Buffer[17]=UDR;
21
  Buffer[18]=UDR;
22
  Buffer[19]=UDR;  
23
  }

Nein.
Was soll das sein?

Tu dir selbst einen Gefallen und lern doch erst mal die Grundlagen. 
Versteh, was die einzelnen Komponenten machen und warum der Code so ist 
wie er ist
http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial/Der_UART

Das hat keinen Sinn was du da machst.

Benutz wenigstens die Funktionen, die du im Link finden kannst. Da gibt 
es eine Funktion, die auf 1 Zeichen wartet und das dann zurückliefert. 
Das ist dein Basisbaustein, den lässt du so wie er ist und den benutzt 
du um die Bytes zu empfangen, die einen Frame ausmachen.

von Klatec (Gast)


Lesenswert?

Hallo Markus

Ich verwende ebnfalls eine UART und lese Telegramme von einer 
Gegenstelle ein.
Ich verwende hizu einen Puffer z.B. InPuffer[255] in dem ich 255 Zeichen 
speichern kann. Ich habe zwei Adressen eine Adresse InPufferAdrWr mit 
der ich den Puffer beschreibe und eine Adresse InPufferAdrRd mit der ich 
den Puffer auslese. Zusätzlich wird bei jedem eingelesenem Zeichen 
(8Bit)ein Zähler inc. der die noch nicht ausgewerteten Zeichen zählt. 
Ist der Null dann kann ich mir die Auswertung ersparen.
Ich nehem an du weißt wieviele Zeichen du erhalten sollts und erst wenn 
die Anzahl eingelangt ist werte ich diese aus.
Ich erkenne einmal das Startzeichen, setze ein Bit für die Erkennung des 
Startzeichen lösche das augelesenen Zeichen aus dem Puffer und gehe dann 
zur Detailauswertung der verschiedenen Telegammtypen.
Jedesmal wenn ich Zeichen ausgelesen habe werden sie aus dem Puffer 
gelöscht, Achtung nicht zu früh löschen du musst ja auch die Checksum 
berechnen um einen Vergleich zur Empfangen Sum zu haben.

Lg.

Johann K.

von Markus S. (Firma: A.S.) (xray)


Lesenswert?

Erstmal vielen Dank für die Tipps!

Aber das klingt ja schon etwas kompliziert für nen Neuling wie mich :-)
Dafür das man "nur " ne Taste auswerten möchte ....

Na ich werd ja nicht drumherum kommen. Hast Du denn mal ein Muster für 
mich, ich kann mir das beseer beibringen, wenn ich weiss wie es 
auzusehen hat.

von Karl H. (kbuchegg)


Lesenswert?

Markus S. schrieb:
> Erstmal vielen Dank für die Tipps!
>
> Aber das klingt ja schon etwas kompliziert für nen Neuling wie mich :-)
> Dafür das man "nur " ne Taste auswerten möchte ....

Das was du vorhast, erfordert schon einiges an Können.

von Klatec (Gast)


Lesenswert?

Bitte, hier meine Einleseroutine

Ist nich schwierig, ich habe zu den einzelnen Zeilen Ziffen 
hinzugeschrieben

1... ich beginne den Puffer bei 1 zu beschreiben, wenn die Adresse 512 
ist dann schreibe ich 1.

2... ich kontrolliere ob ich vorhanden Daten überschreibe

3... erhöhe den Zähler der noch nicht behandelten Zeichen

4... schreibe das empfangene Zeichen in den Puffer

5... nächste Schreibadresse wird erzeugt.

Einmal der Empfang.

Ich schick dir noch eine Auswertung, aber später.

tschau.
************************************
void vInSerielPufWr(char cData){

1  if(iServInPufWrAdr==512){iServInPufWrAdr=1;}

2  if(caServInPuf[iServInPufWrAdr]!= 0){  //Speicherplatz leer?
    //Fehlertabelle beschreiben

  }
3  iServInPufCount++;  //Anzahl der unbearbeiteten Byte's
4  caServInPuf[iServInPufWrAdr]=cData;  //Daten in den Puffer  schreiben
5  iServInPufWrAdr++;    //nächste Adresse
}//vInSerielPufWr

von Markus S. (Firma: A.S.) (xray)


Lesenswert?

Wow, das ist ja mal supernett !!! THX

von Karl H. (kbuchegg)


Lesenswert?

Klatec, deine Bemühungen in allen Ehren. Aber schau dir seinen Code an. 
Da scheiterts daran eine Anzahl Zeichen hintereinander zu empfangen! 
Multibuffering ist 3 Stufen über dem Level auf dem seine Probleme 
liegen.

Erst mal muss er 1 Zeichen empfangen. In einer Funktion.
Dann in einer Schleife eine antsprechende Anzahl Zeichen empfangen, 
indem er die Funktion aufruft.
Das beste am besten gleich unter Berücksichtigung des Protokolls. D.h. 
in Frame beginnt mit 0x11 und alles was nicht 0x11 wird verworfen, ehe 
der Frameanfang kommt.

Aber eines nach dem anderen. Erst mal die Einzelzeichenfunktionen in 
Betrieb nehmen. Und das am besten erst mal im Zusammenspiel mit einem PC 
damit man auch sieht was man schickt bzw. per Tastatur gezielt antworten 
kann.

von Klatec (Gast)


Lesenswert?

2. Teil

Ich verwende den Interrupt der UART für den Enpfang der Zeichen und 
springe von der Serviceroutine eben zur Beschreibung des Puffers.



Diese Routine löscht die gelsenen Zeichen aus dem Puffer

void vInServPufClear(void)
int i = 0;
  for(i=0;i<512;i++){
    caServInPuf[i]=0;
  }
}//vInServPufClear

*************************************


Diese Routine verwende ich zum auswerten der Zeichen, wobei ich 
Telegramme mit fixer Länge und variabler Länge oder ein ACK-Zeichen mit 
einem Byte verwende.
Ich habe mal den Großteil der Funktionen gelöscht so das der Code 
einfach zum überschauen ist.

Es ist nur mehr die Auswertung der Telegramme mit fixer Länge geblieben.
Kopier den Code heraus und formatiere ihn neu, weil so sieht er 
furchtbar aus.

1... keine neuen Zeichen, dann wieder raus

2... wurde schon ein Startbyte erkannt?  (10h)

3... wenn ja, dan warten bis genügend Zeichen vorhanden

4... Startzeichenerkennung

5... Zeichen aus dem Puffer löschen

***************************************

void vInZeichAusweServ(void){

1  while(iServInPufCount!=0)  //sind nicht bearbeitet Zeichen im 
Eingagnspuffer?
  {

2    if(cStartByteServFix == 0xFF){  // Startbyte für Tel. fixer Länge

3      if(iServInPufCount > 6) //Telegrammlänge 8 Byte
      {
        ucTimeOutServ=0;  //Timeout rücksetzen
         vInTelServFixErk();
        cStartByteServFix=0;
        return;
      }
      else{return;}

    }

4    if(caServInPuf[iServInPufRdAdr] == 0x10)  /* Startbyte für Tel. 
fixer Länge*/
    {
      ucTimerTimeOutServ=vServsTimeOutCal(7);  //Timerladen
      cStartByteServFix = 0xFF;

    }

5    vServsInCountClear(1);


    }
}


**************************+

Lg.

Johann K.

von Markus S. (Firma: A.S.) (xray)


Lesenswert?

DANKEEEEEEEE Johann - Das einlesen hab ich selbst hinbekommen, aber 
Deine Auswertung ist Klasse - LÄUFT !! ;-)

von Klatec (Gast)


Lesenswert?

Hallo Markus

NIchts zu danken, hab dich bloß an meinen Gedanken teilhaben lassen.
Ich halt von Internet normalerweise nicht viel aber in diesem Falle 
ist's super. Wenn ich an die ersten Schritte denke dich ich mit dem 
80C535 (51er Familie) gemacht habe und das in Assambler. Ich benötige 
für einen Progammcode der nur über 4 oder 5 Zeilen gegangen ist, zwei 
Wochen bis ich ihn verstanden habe und das ohne Internet (1994). Laß 
dich von so manchen Aussagen nicht entmutigen.

Lg.

Johann K.

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.