Forum: Compiler & IDEs über uart string empfangen und auswerten!


von Oli K. (waldmeister)


Angehängte Dateien:

Lesenswert?

hallo zusammen,

ich beschäftige mich momentan mit der seriellen schnittstelle. daten 
senden und empfangen bekomme ich auch schon hin (siehe code). was ich 
nun machen möchte ist, dass ich einen string von bestimmter größe 
empfange und diesen nachher bytweise weiterverarbeite. dazu möchte ich 
auch nur einen bestimmten buffer reservieren!(was ich im moment wohl mit 
dem unsigned string bufer(100] mache)
danach möchte ich an meine bytes, sprich in jedem byte stecken infos. in 
der theorie bin ich der meinung, dass ich meinen string speicher, un 
dann byte für byte über einen pointer darauf zugreife. was ich mit einer 
switch case anweisung lösung machen könnte. allerdings hänge ich im 
moment noch bei der verwirklichung dieser geschichte. vllt. bin ich 
allerdings auch auf dem holzweg.
muß ich evtl auch einen rx_counter einsetzen, um die größe zu 
überprüfen? und wäre die lösung getchar() besser, also zuerst das 
abholen der daten und dann   das ganze weiter verarbeiten??

von unsichtbarer WM-Rahul (Gast)


Lesenswert?

>unsigned string
gibbet net!

Dein String (unsigned char string[100]) muß global deklariert sein, weil 
man sonst nur in der ISR darauf zugreifen kann.
In der ISR macht man dann nichts anderes als
string[rx_counter++] = UDR;

"rx_counter" ist die Index-Variable, die die neue Schreibposition in 
deinem Empfangspuffer und den belegten Platz im Puffer anzeigt.

>//hier  meine switch (help)
>// case 1....   anweisung
sollte man eher nicht in die ISR packen, ausser wenn das Programm nichts 
anderes machen soll (macht es zwar momentan nicht, aber schöner ist es, 
das ganze Zeug gleich in die main-while-Schleife zu packen.

Sonst liegst du übrigens richtig...



PS: Deine Shift-Taste scheint kaputt zu sein :-}



von Martin (Gast)


Lesenswert?

Hi Oli,

vielleicht kannst Du mal Dein Lösungsansatz posten. Ich hab auch ne 
Switch-Case Anweisung mit der ich Strings auswerte, allerdings 
funktioniert das momentan auch nicht so gut.

Evtl. hilft Dir auch

http://www.cplusplus.com/ref/cstring/

weiter, da sind gute Beispiele bzgl. String- Be-/Verarbeitung.

von unsichtbarer WM-Rahul (Gast)


Lesenswert?

Interessant wäre, wie die Strings aussehen; es muß ja Regeln zu deren 
Entstehung und Verarbeitung geben.

von Oli K. (waldmeister)


Lesenswert?

die strings sind binär codiert, d.h. byte für byte wird gesendet. im 
ersten byte steht die länge des strings und um welchen aufruf es sich 
handelt. in den nachfolgenden bytes stehen dann die informationen für 
den entsprechenden aufruf. ich bin unter anderem dabei, den code zu 
schreiben. wenn ich den hab, werde ich ihn auf jeden fall posten.
aber vielen dank mal für den link und an den wm-rahul!

von unsichtbarer WM-Rahul (Gast)


Lesenswert?

>ersten byte steht die länge des strings

Das ist doch schon mal eine wichtige Information:
In der ISR muß unterschieden, ob es sich um das "Startbyte" oder ein 
anderes handelt. Das kann man i.d.R. dadurch, dass der Puffer-Pointer 
noch auf das erste Element zeigt. Dann decodiert man die String-Länge 
und merkt sie sich. Bei jedem eintreffenden Byte wird der Puffer-Pointer 
um eins erhöht und mit der String-Soll-Länge verglichen. Ist die 
Soll-Länge erreicht, wird ein Flag gesetzt, das das Hauptprogramm dazu 
bringt, den String auszuwerten. Wenn das Hauptprogramm mit der 
Bearbeitung fertig ist, wird der Pointer wieder zurückgesetzt. Dabei muß 
man eigentlich nur beachten, dass während der Bearbeitung kein neuer 
String eintreffen darf. Sonst muß man mit mehreren Puffern und Pointern 
arbeiten...

von Martin (Gast)


Lesenswert?

Es würde ja reichen, wenn Du ein einzelnes Charakter über den UART an 
den µC schickst. Dann brauchst Du nur eine einzelne "char" variable, 
würdest das Zeichen speichern und in der Switch Anweisung abfragen.

von Oli K. (waldmeister)


Angehängte Dateien:

Lesenswert?

so, hier mal die ersten überlegungen dazu. allerdings ist das ganze noch 
nicht ausgereift und auch noch nicht zu gebrauchen. wenngleich beim 
compillieren schon keine fehler mehr auftauchen, was aber nichts zu 
bedeuten hat. es sind auf jeden fall noch fehler drinnen, aber ich 
wollte das jetzt doch mal posten.
bisher habe ich niczht viel drinnen, sprich ich möchte meine stringlänge 
vergleichen ist=soll. die länge kann allerdings variiern, deshalb <= 
wenn diese überschritten wird, gibts später nen fehler.(jetzt noch net)
in meiner switch case werden die fälle bei meinem ersten byte 
untersucht. und dann auf lcd ausgegeben. allerdings sind die einzelnen 
fälle in bite 5-7 und die länge in 0-4 somit stimmt das auch noch nicht 
überein.
allerdings ist das jetzt mal mein lösungsansatz, wie martin darum 
gebeten hatte.

von unsichtbarer WM-Rahul (Gast)


Lesenswert?

>das ganze noch nicht ausgereift und auch noch nicht zu gebrauchen.
Stimmt!

Handelt es sich bei deinem Compiler wirklich um den avr-gcc?

help(0) ruft doch eigentlich eine Funktion mit dem Namen "help" und dem 
Parameter "0" auf (zumindest wäre das in meinen Augen C-Standard).

Könntest du vielleicht mal das Protokoll bzw. dessen Aufbau posten?

>allerdings ist das jetzt mal mein lösungsansatz, wie martin darum
>gebeten hatte.
Ehrlich gesagt ist das eigentlich nur Mist...(meine subjektive Meinung)

Übrigens finde ich es sehr anstrengend nur Kleinbuchstaben lesen zu 
müssen.

von Martin (Gast)


Lesenswert?

Ich versteh nichit ganz:

>if(pstring == help(0))

Wieso sollte pstring Zeiger mit help(0) identisch sein?

>case 001: help(0) == 0b001;

help(0) wird ja dann wieder mit gleichem Inhalt überschrieben.

Was bezweckst Du überhaupt mit der if- und Switch- Abfrage?

von unsichtbarer WM-Rahul (Gast)


Lesenswert?

>>case 001: help(0) == 0b001;
Da wird nichts überschrieben, sondern ein Vergleich durchgeführt.

von Karl heinz B. (kbucheg)


Lesenswert?

> Könntest du vielleicht mal das Protokoll bzw. dessen Aufbau posten?

Rahul hat recht.
Da sollte man mal loslegen.

Die Frage die sich mir stellt:
Wie ist das mit dem Protokoll? Hat man dir das aufs
Auge gedrückt, oder ist da noch Spielraum? Wenn das
noch änderbar ist, dann hätte ich da schon einige
Ideen, wie man das ganze wesentlich simpler hinkriegt
als mit deinen variabel langen Kommandos. Wenn das
Protokoll allerdings von einem externen Gerät stammt,
dann musst du das wohl so nehmen wies ist.
Dreh und Angelpunkt ist dann meistens zunächst mal einen
kompletten Datensatz aus dem Protokoll rauszuholen. Das
ermöglichen eigentlich so ziemlich alle Protokolle indem
sie ein spezielles Zeichen haben, welches das Ende eines
Datensatzes (also Kommando + Argumente) anzeigt. Wenns
sowas nicht gibt, wird die Sache meist haarig, da dir
ein einziger Übertragunsfehler an der richtigen Stelle
alles lahmlegt, bzw. es dann nicht mehr so einfach ist
die Synchronisierung zwischen Sender und Empfänger
auf Protokollebene herzustellen, wenn sich der Empfänger
in eine laufende Übertragung einklinkt.

von Martin (Gast)


Lesenswert?

Wie sähe denn ein geeignetes Protokoll aus?

Wenn man nur ein paar Fälle zu überprüfen hätte, könnte man das auch ja 
so machen:




while( 1 )
{


buffer = uart_getc();


switch (buffer)
  {
  case 'F':
  uart_puts("Führe Frequenzmessung durch... ");
  //result = frequenzmessung();
  //itoa(result, asciresult, 10);
  //uart_puts("Frequenz beträgt: "); uart_puts(asciresult); uart_puts(" 
kHz");

  break;

  case 'A':

  uart_puts("Führe AD Wandlungen durch... ");
  ACSR |= (1 << ACIE);      // Interrupt Freigeben für Analog Komparator

  break;

  case 'D':
  uart_puts("D wurde gedrückt\n");
  break;

  case 'S':
  uart_puts("S wurde gedrückt\n");
  break;
  }
}

von Martin (Gast)


Lesenswert?

Oh sorry, falsch gepostet war ne Codeleiche, aber so ähnlich stelle ich 
mir das vor.

Vorher natürlich den buffer als char anlegen.

uart_putc() sendet ein Zeichen vom Uart
uart_getc() empfängt ein Zeichen

von unsichtbarer WM-Rahul (Gast)


Lesenswert?

@Martin: Wo drückt denn dein Schuh?

von Martin (Gast)


Lesenswert?

@ Rahul:

War ein Lösungsvorschlag wie man String/Zeichen empfangen und dann 
auswerten kann. Ok das Beispiel ist ein wenig aus dem Zusammenhang. 
Warum muss man die Länge des Befehls wissen? Das kommt ja stark auf das 
verwendete Protokoll und auf die Befehle die empfangen werden an. Wie 
und was in der Auswertung geschieht ist ja egal.

von Oli K. (waldmeister)


Lesenswert?

Also mein Compiler ist AVR GCC.
> Ehrlich gesagt ist das eigentlich nur Mist...(meine subjektive Meinung)
Hm, ist zwar hart, aber stimmt.
Der String kommt von men externen Prog., ist also fest. Das Protokoll 
sieht  vor, dass für case1 ein 4 byte großer String belegt ist, case2 - 
23bytes, case3 - 4bytes, case4 - 23 bytes, case5 - 23 bytes, case6 - 15 
bytes.
Was ich will, ist, als erstes byte0 zu prüfen. Danach möchte ich erst 
mit den nächsten bytes weiter machen. werde erst mal schauen, dass ich 
dass auf Vordermann bringe, bevor ich das wieder poste.

von unsichtbarer WM-Rahul (Gast)


Lesenswert?

Wenn es nur darum geht, auf einzelne Bytes zu reagieren, reicht die 
einfache Auswertung, wie du sie beschrieben hast.
Es gibt aber auch Protokolle, die aus mehr als nur einem Zeichen 
bestehen (z.B. VISCA von Sony, Protocol 2000 von Kramer-Electronics).
Bei VISCA werden maximal 16 Bytes übertragen und mit einem 0xFF das Ende 
markiert.
Olis Protokoll sieht so aus, dass das erste Byte die Gesamtlänge und 
einen bestimmten Befehl enthält, der mit den nachfolgenden Bytes seine 
Parameter geliefert bekommt. Da hat dann je nach Befehl das einzelne 
Byte im Puffer eine andere Bedeutung.
Parser arbeiten auch so - schliesslich ist es egal, ob der "Text" von 
der seriellen Schnittstelle oder aus einer Textdatei stammt.

Zu deinem Beispiel: Wenn du jetzt auch noch einen ADC verwenden würdest 
und dieser mehr als nur einen Kanal besitzt, würdest du zu dessen 
Auswahl vermutlich zwei Bytes schicken: z.B "A0" für ADC-Messung, Kanal 
0 oder "A1" für ADC-Messung, Kanal 1 usw.
Mit dem ersten empfangenen Byte erkennst du, welche Messung durchgeführt 
werden soll. Mit dem drauffolgenden dann den Kanal.

Wenn man die Länge eines Datenrahmens weiß (z.B. 4 Bytes beim Protocol 
2000), kann man die UART-RXC-ISR ganz alleine ihren Job machen lassen, 
indem sie die Zeichen in einen Puffer schreibt. Sind nun alle 4 Zeichen 
eingetroffen, wird ein Flag gesetzt, dass dem Hauptprogramm einen 
vollständig empfangenen Datenrahmen signalisiert.
Startbytes kann man auch über ein bestimmtes Muster erkennen bzw. 
sollten über ein bestimtes Muster erkennbar sein - notfalls als 
Hardware-Handshake.

von unsichtbarer WM-Rahul (Gast)


Lesenswert?

>Das Protokoll sieht  vor, dass für case1 ein 4 byte großer String belegt >ist, 
case2 - 23bytes, case3 - 4bytes, case4 - 23 bytes, case5 - 23 bytes, >case6 - 15 
bytes.

Jetzt wäre interessant, wie das byte 0 aussieht - also welche Funktionen 
die einzelnen Bits haben.
Vielleicht könntest du auch einen Beispiel-Datenrahmen posten.

Das vorhergehende Posting wendet sich überwiegend an Martin...

von Oli K. (waldmeister)


Lesenswert?

Als Bsp:

byte0:
0xCE = 11001110 bedeutet case 6, da bit 5-7 110 haben, die Länge ergibt 
sich aus den bites 0-4 1110 --> dies addiert ergibt den Wert von 14 
Array-Elementen.

von unsichtbarer WM-Rahul (Gast)


Lesenswert?

unsigend char buffer[32];       // maximal 32 Datenbytes
unsigned char buffer_pointer = 0; // aktuelle Schreibposition für den 
Buffer
unsigned char buffer_length = 0; // Anzahl der Zeichen im Puffer 
abhängig vom byte0
unsigend char Event=0;          // Ereignis-Flag

ISR(irgendwas mit RXC)
{
 buffer[buffer_pointer] = UDR;
 if (buffer_pointer == 0)
   buffer_length = buffer[buff_pointer] & 0x1F;
 if (++buffer_pointer >= buffer_length) Event = 1;
}

void main(void)
{
.
.
.

while(1)
{
 while(!Event);
 switch (buffer[0] >> 5) // verschieben der 3 obersten Bits nach ganz 
unten
 {
   case 1 : { // bearbeite 4 Byte;
             break;
            }
   case 2 : { // bearbeite 23 Byte;
             break;
            }
   case 3 : { // bearbeite 4 Byte;
             break;
            }
   case 4 : { // bearbeite 23 Byte;
             break;
            }
   case 5 : { // bearbeite 23 Byte;
             break;
            }
   case 6 : { // bearbeite 15 Byte;
             break;
            }
   default:;
 }
 buff_pointer = 0;
}
}

// Fertich...

von unsichtbarer WM-Rahul (Gast)


Lesenswert?

Mir fiel noch auf, dass das System überbestimmt ist: Je nach Fall 
scheint die Anzahl der Bytes ja festgelegt zu sein, weswegen eigentlich 
keine Länge mit übertragen werden müsste...

von Karl heinz B. (kbucheg)


Lesenswert?

In den 14: Ist da das Kommando schon mit drinnen oder ist
das die Anzahl der noch folgenden Bytes?

Egal. Notfalls musst du die Längenauswertung anpassen.
Ich würde das in etwa so machen:
1
volatile unsigned char Record[30];    // da passt dann auch das längste Kommando rein
2
unsigned char RecordIndex;
3
unsigned char RecordLen;
4
volatile unsigned char RecordReceived;
5
6
7
SIGNAL( SIG_UART_RECV )        // SIGNAL nehm ich nur weil du das auch genommen hast.
8
                               // Ev. Compiler mal auf die aktuelle Version upgraden
9
{
10
  unsigned char c = UDR;
11
12
  if( RecordIndex == 0 ) {     // war das erste Byte. Daraus mal die Länge des
13
                               // Datensatzes holen
14
    RecordReceived = FALSE;
15
    RecordLen = c & 0x0F;
16
    c = c >> 4;                // Das Kommandonibbel nach unten schieben
17
                               // Sont hat man bei der Auswertung immer die
18
                               // Längenangabe mit drinnen
19
  }
20
21
  Record[RecordIndex++] = c;
22
23
  if( RecordIndex == RecordLen ) {
24
    RecordIndex = 0;
25
    RecordReceived = TRUE;
26
  }
27
}
28
29
30
int main()
31
{
32
33
   ....
34
35
36
   while( 1 ) {
37
38
     if( RecordReceived ) {
39
       RecordReceived = FALSE;
40
41
       switch( Record[0] ) {
42
43
         case 0x01:
44
           // Kommando 1 abarbeiten
45
           // In Record[1] bis Record[n] steht alles weitere
46
           break;
47
48
         case 0x02:
49
           // Kommando 2 abarbeiten
50
           // In Record[1] bis Record[n] steht alles weitere
51
           break;
52
53
      }
54
    }
55
  }
56
}

  

von Karl heinz B. (kbucheg)


Lesenswert?

> // Fertich...

Diesmal warst du schneller :-)

von unsichtbarer WM-Rahul (Gast)


Lesenswert?

@Karl-Heinz: Die Länge besteht aus 5 Bits, weil sonst keine 23 Bytes 
übertragen werden könnten.

von Oli K. (waldmeister)


Lesenswert?

Da bin ich verdammt noch mal wirklich auf dem Holzweg gewesen. Aber ist 
ja auch noch kein Meister vom Himmel gefallen.

von unsichtbarer WM-Rahul (Gast)


Lesenswert?

>Aber ist ja auch noch kein Meister vom Himmel gefallen.

Aber zumindest die Treppe...

von Karl heinz B. (kbucheg)


Lesenswert?

> Karl-Heinz: Die Länge besteht aus 5 Bits, weil sonst keine
> 23 Bytes übertragen werden könnten.

Ja, ja, hast ja recht.

> die Länge ergibt sich aus den bites 0-4 1110

Ich setz mich jetzt hin und schreib Hundert mal:
0 bis 4, das sind 5 Bits, nicht 4!


#include <stdio.h>

int main()
{
  int i;
  for( i = 0; i < 100; ++i )
    printf( "0 bis 4, das sind 5 Bits, nicht 4!\n" );
  return 0;
}

:-)

von Oli K. (waldmeister)


Lesenswert?

>> die Länge ergibt sich aus den bites 0-4 1110
>
... ich hab die erste 0 vergessen, was allerdings doch noch unter 
Flüchtiggkeitsfehler gehen dürfte, da weiter oben:
>>0xCE = 11001110
steht.
;-)

von unsichtbarer WM-Rahul (Gast)


Lesenswert?

übrigens sieht dein Programm schöner aus. :-)

von Martin (Gast)


Lesenswert?

@ Rahul:
Jo danke für die Erklärung!


@ Rahul & Karl Heinz: Sagt mal ist das Zufall dass Ihr beide die gleiche 
Lösung gepostet habt? Oder gibts da nicht so viele Möglichkeiten das 
Problem zu lösen?

von unsichtbarer WM-Rahul (Gast)


Lesenswert?

>Oder gibts da nicht so viele Möglichkeiten das Problem zu lösen?

Karl-Heinz sitzt mir gegenüber....

Nee, Quatsch.
Das ist ja eben das Schöne am Programmieren: Es gibt ein paar 
Standard-Elemente, die man munter miteinander kombinieren kann. Da ist 
die Wahrscheinlichkeit recht hoch, dass zwei Leute zum gleichen Ergebnis 
kommen.
Man könnte die Sache vielleicht auch anders lösen. Mir (und Karl-Heinz) 
fiel aber scheinbar nichts besseres ein.

von Karl heinz B. (kbucheg)


Lesenswert?

Seh ich auch so.

Auch in der Programmierung gibt es Standardelemente, so wie
es im Maschinenbau auch Standardelemente gibt. Mit der Zeit
hat jeder Programmierer einen Haufen derartiger Bausteine
parat und abrufbereit im Kopf. Sowohl Dinge die sich bewährt
haben als auch Dinge die sich nicht bewährt haben.
Das ist meines Erachtens auch einer der wesentlichen Unterschiede
zwischen einem Frischling und einem alten Hasen (nicht abwertend
gemeint). Einem alten Hasen ist fast jede Situation schon mal
untergekommen und wenn schon nicht genau dieselbe Situation
dann doch etwas ähnliches. Ein alter Hase hat für so manche
Problemstellung 2, 3 Lösungsmöglichkeiten parat, während ein
Frischling noch darüber grübelt, was denn eigentlich das Problem
ist. Aber erzähl das mal den Firmen, wenn du über 40 bist. Die
sehen nur, dass sie um dein Gehalt 2 Frischlinge einstellen
können. Dass du dafür mindestens 3 mal so schnell arbeiten
kannst wie ein Frischling ignorieren sie.

von Oli K. (waldmeister)


Lesenswert?

Da muss ich dir zustimmen. Ich denke, dass ein erfahrener Progger schon 
längst viel weiter mit dem Projekt wäre, als ich das im Moment bin. Auf 
der anderen Seite muss ich auch froh sein, dass man mir die Chance 
überhaupt gibt, in diesem Bereich Erfahrungen zu sammeln, was heute auch 
nicht mehr selbstverständlich ist. Aber das ist nen anderes Thema für 
ein anderes Topic.

Mein Problem ist ein anderes:

void buffer_stop(void)
{
  unsigned int x;
  unsigned char y;
        int w = 5;
        int z = 10;


  if(pbuffer == 2)             //2 byte auswerten
  {
    y = buffer_stop;
    y = buffer[pbuffer] & 0x0F;     //bits die ausgewertet werden 
sollen, eingrenzen
  }

  x = y/w - z;
       // x=x - z;

//hier sprintf()
}

Leider wird meine Berechnung nicht durchgeführt und auf dem lcd 
ausgegeben.
Da ist doch bestimmt wieder nen ganz simpler Fehler drinnen.

von unsichtbarer WM-Rahul (Gast)


Lesenswert?

>Leider wird meine Berechnung nicht durchgeführt und auf dem lcd
>ausgegeben.

Die hier?
>x = y/w - z;

Dein Codefragment sollte so funktionieren (syntaktische scheint es 
richtig zu sein).
Vielleicht solltest du mal ein paar Worte zum Problem niederschreiben.
Und am besten auch mehr Code (das komplette Programm!) zur Verfügung 
stellen.

>Da ist doch bestimmt wieder nen ganz simpler Fehler drinnen.
versuch's mal mit "volatile" kann ich dazu nur sagen. ;-)

von Oli K. (waldmeister)


Lesenswert?

Beim compilieren bringt er mir folgende Meldung:
../uart.c: In function `buffer_stop':
../uart.c:120: warning: 'y' might be used uninitialized in this function

was für mich aber nicht verständlich ist, da initialisiert.

wenn ich die Formel umbaue, sprich:

void buffer_stop(void)
{
  unsigned int y;
  unsigned char x;
  int z = 50;


  if(pbuffer == 2)
  {
    //y = buffer_stop;
    x = buffer[pbuffer] & 0x0F;
  }

  y = 5*x+z;


  sprintf(x,"0x%02x %02i %02i ",buffer[2],buffer_stop, buffer[24], 
buffer);
  lcd_clrscr();
  lcd_puts(x);
}

bringt er mir für x komische Felder auf dem Display und für y wird das 
ganze Display ausgemahlt! Warnmeldung hier:
../uart.c: In function `buffer_stop':
../uart.c:120: warning: 'x' might be used uninitialized in this function

von unsichtbarer WM-Rahul (Gast)


Lesenswert?

Dass irgendwelche Variablen genauso heissen, wie einige Funktionen, 
stört dich nicht?

von Karl heinz B. (kbucheg)


Lesenswert?

> ../uart.c: In function `buffer_stop':
> ../uart.c:120: warning: 'y' might be used uninitialized in this function

Ich geh mal davon aus, dass sich das auf deine ursprüngliche
gepostete Version bezieht:
1
void buffer_stop(void)
2
{
3
  unsigned int x;
4
  unsigned char y;
5
        int w = 5;
6
        int z = 10;
7
8
9
  if(pbuffer == 2)             //2 byte auswerten
10
  {
11
    y = buffer_stop;
12
    y = buffer[pbuffer] & 0x0F;     //bits die ausgewertet werden
13
sollen, eingrenzen
14
  }
15
16
  x = y/w - z;
17
       // x=x - z;
18
19
//hier sprintf()
20
}

Beantworte doch mal schnell eine Frage:
Welchen Wert hat denn y, wenn pbuffer nicht den Wert 2 hat?

Selbiges hier
1
void buffer_stop(void)
2
{
3
  unsigned int y;
4
  unsigned char x;
5
  int z = 50;
6
7
8
  if(pbuffer == 2)
9
  {
10
    //y = buffer_stop;
11
    x = buffer[pbuffer] & 0x0F;
12
  }
13
14
  y = 5*x+z;
15
16
17
  sprintf(x,"0x%02x %02i %02i ",buffer[2],buffer_stop, buffer[24],
18
buffer);
19
  lcd_clrscr();
20
  lcd_puts(x);
21
}

> ../uart.c: In function `buffer_stop':
> ../uart.c:120: warning: 'x' might be used uninitialized in this function

Welchen Wert hat den x, wenn pbuffer nicht 2 ist?

> bringt er mir für x komische Felder auf dem Display und für y wird das
> ganze Display ausgemahlt!

Sorry. Aber dieser Satz ergibt keinen Sinn.

Ausserdem:
Die Funktion heisst 'buffer_stop.
D.h. du kannst hier

  sprintf(x,"0x%02x %02i %02i ",buffer[2],buffer_stop, buffer[24],
                                          ***********

keine Variable haben, die den gleichen Namen hat. Nun ja,
technisch gesehen kannst du schon, nur passiert hier was
völlig anderes als du glaubst.

Ausserdem:

  unsigned char x;

das heist: x hat Platz für genau 1 Zeichen! Nicht mehr!
Wie bitte soll die komplette Ausgabe von sprintf, die
ja sicherlich länger als 1 Zeichen ist, denn in x hineinpassen?

Was du brauchst ist ein char-Feld. Strings werden in C in char
Felder abgespeichert und es obliegt deiner Verantwortung als
Programmierer, dass dieses Array auch gross genug ist, sodass
der String auch hineinpasst.

 sprintf(x,"0x%02x %02i %02i ",

Das sind 2 Zeichen für die erste Hex Zahl, 1 für das erste
Leerzeichen, 2 Zeichen für die nächste Zahl, wieder 1 Leerzeichen,
nochmal 2 Zeichen und noch 1 Leerzeichen. Dazu kommt dann noch
1 Zeichen, das für Strings obligatorisch ist, nämlich das
abschliessende '\0' Zeichen, dass jeden String abschliesst.

Wir haben also:
    2 + 1 + 2 + 1 + 2 + 1 + 1 = 10 Zeichen.

Also muss x ein Array mit einer Mindestlänge von 10 sein:

   char x[10];

Bei solchen Sachen ist es aber gut, dass etwas größer zu machen.
Irgendwann veränderst du nämlich die Formatierung und mit der
neuen Formatierung passen die 10 dann nicht mehr -> du hast
wieder den gleichen Fehler. Also, die Devise heist: nicht
kleckern, klotzen!

   char x[20];

von Karl heinz B. (kbucheg)


Lesenswert?

Habs jetzt erst gesehen.
Du benutzt x für 2 verschiedene Sachen.
Einmal hier

    x = buffer[pbuffer] & 0x0F;
und
    y = 5*x+z;

Da wird x offensichtlich als Zwischenspeicher für
irgend eine Auswertung benutzt.

Und hier:

   sprintf( x,

Da wird x benutzt um das Stringergebnis vom sprintf
aufzunehmen. Die Ausführung oben bezieht sich nur
auf letztere Verwendung. Da aber eine Variable nicht
gleichzeitig in Array und kein Array sein kann, ist
es wohl am einfachsten, du nimmst für letztere Verwendung
eine neue Variable, die dann ein Array sein muss.

Sag mal: Hat dein Compiler da gar nichts dazu gesagt?
Einen unsigned char als erstes Argument an sprintf zu
verwenden, dass sollte eigentlich jeder Wald und Wiesen
C Compiler als Fehler markieren.

von Oli K. (waldmeister)


Lesenswert?

>Welchen Wert hat denn y, wenn pbuffer nicht den Wert 2 hat?

Ist das nicht so, dass wenn ich die Variable nicht deklariere, 
automatisch der Wert 0 zugeordnet wird?
nunja, wenn ich char x[20];  einbaue, was ich ja auch verstehe, dann 
möchte das mein compiler nicht machen:
../uart.c:127: error: incompatible types in assignment
../uart.c:130: error: invalid operands to binary *

von unsichtbarer WM-Rahul (Gast)


Lesenswert?

es muß auch unsigned char x[20] heissen

>Ist das nicht so, dass wenn ich die Variable nicht deklariere,
>automatisch der Wert 0 zugeordnet wird?

Du programmierst in C und nicht im Basic...(Nein, in der Variablen steht 
irgendwas drin!)

von Karl heinz B. (kbucheg)


Lesenswert?

>  sprintf(x,"0x%02x %02i %02i ",
>
> Das sind 2 Zeichen für die erste Hex Zahl, 1 für das erste

Siehst du:
Die ersten beiden Zeichen, nämlich das "0x" hab ich jetzt
auch übersehen. Also wäre 10 schon zuwenig gewesen, die
Minimallänge ist 12, nicht 10. Mit den 20 wäre ich auf der
sicheren Seite gewesen.
Das nennt man auch 'defensiv programmieren'. Sich selbst
Spielraum für kleine Fehler zu lassen, so dass sich die nicht
gleich verheerend auswirken.

von Karl heinz B. (kbucheg)


Lesenswert?

> es muß auch unsigned char x[20] heissen

Nein. Muss es nicht.

Das Problem hab ich zu spät gesehen.
Er hat 2 verschiedene Verwendungen für x. Einmal
um einen tatsächlichen Wert zwischenzuspeichern.
Einmal um einen String aufzunehmen.

Scroll nochmal ein bischen hoch. Um 11:56 hab
ich dazu was geschrieben.

von Karl heinz B. (kbucheg)


Lesenswert?

> Ist das nicht so, dass wenn ich die Variable nicht deklariere,
> automatisch der Wert 0 zugeordnet wird?

Denk logisch.
Dann würde der Compiler wohl kaum sagen, dass die Variable
uninitialisiert ist.

Lokale Variablen werden nicht automatisch auf 0 initialisert.
Globale Variablen schon.

Du solltest dir etwas Literatur zulegen.


von Karl heinz B. (kbucheg)


Lesenswert?

> ../uart.c: In function `buffer_stop':
> ../uart.c:120: warning: 'y' might be used uninitialized in this function

> was für mich aber nicht verständlich ist, da initialisiert.

Regel römisch Eins:

Ia  Der Compiler hat immer Recht!
Ib  Wenn er einmal nicht Recht hat (was vorkommt), tritt
    automatisch Regel Ia in Kraft

Regel Ib folgt sofort daraus, dass du nicht mit deinem Compiler
diskutieren kannst. Wenn er sagt, etwas ist so, dann ist es
so. Selbst wenn es falsch ist. Es gibt nichts was du kurzfristig
dagagen tun kannst. Langfristig kannst du natürlich auf ein
Update hoffen oder einen anderen Compiler nehmen.

von Oli K. (waldmeister)


Lesenswert?

ok, wieder was dazu gelernt! nun muss ich dieses neu erlangte Wissen nur 
noch umsetzen...!

von unsichtbarer WM-Rahul (Gast)


Lesenswert?

>nun muss ich dieses neu erlangte Wissen nur noch umsetzen...!
... und dir noch ein C-Buch kaufen.

von Oli K. (waldmeister)


Lesenswert?

nur mal langsam, das habe ich!

von unsichtbarer WM-Rahul (Gast)


Lesenswert?

>nur mal langsam, das habe ich!
auch gelesen (und verstanden)?

von Oli K. (waldmeister)


Lesenswert?

würde ich sonst hier fragen stellen, wenn ich alles verstanden hätte?!

von Karl heinz B. (kbucheg)


Lesenswert?

Dann kann dein Buch nicht gerade das gelbe vom Ei sein.
Das, worum es in diesem Thread geht, ist ausnahmslos
Grundlagenwissen.

von Oli K. (waldmeister)


Lesenswert?

ja, nun hab ich des auch gerafft! in diesem sinne merci mal!

von noname (Gast)


Lesenswert?

Also zum Thema serielle Protokolle:

Ich hab glaub ich die letzten 5 Jahre nix anderes gemacht...


Ein serielles Protokoll sollte eine Start- und ein Stopzeichen haben, 
z.B. 0x5a für Start und 0xFF für Stop.

Ein einfaches Protokoll zwischen nur 2 Teilnehmern könnte z.B. sein

Byte 0 Startzeichen 0x5A
Byte 1 Kommando (255 Kommandos möglich)
Byte 2 Anzahl Datenbytes
Byte 3...x Datenbytes
Byte x+1 Checksumme (z.B. Summation aller Bytes, um es einfach zu 
machen)
Byte x+2 Stopzeichen 0xFF

also z.B. 0x5A 0x01 0x00 0x23 0x7D 0xFF

--> Kommando 0x01 mit den Daten 0x00 0x23

empfangen wird das Protokoll über den Empfangsinterupt und in einem 
Ringbuffer gespeichert.

Im Main Loop wird eine State Machine aufgerufen, die das Protokoll 
abarbeitet:


state waitstartsign:
  if (neues zeichen im ringbuffer && zeichen=0x5a)
    timeoutstarten();
    state=waitcmdsign;

state waitcmd:
  if ( timeout )
    state = waitstartsign;

  if (neues zeichen im ringbuffer && gültiges Kommando)
    state = waitdatalen;

usw...

wenn das Stopzeichen empfangen wurde, wird die checksumme überprüft und 
das Protokoll der nächst höheren Softwareschicht übergeben (kopiert).


So mal ganz grob beschrieben wie es in der Industrie gemacht wird.

von Oli K. (waldmeister)


Lesenswert?

Hallo,
nun brauche ich doch noch mal eure Hilfe.
Ich möchte gerne Daten aus dem String speichern, damit ich die später 
weiter verarbeiten kann. Die länge vom String kann unterschiedlich sein.
Wie komme ich die bytes nun abgespeichert? Die die max. Länge der 
Variable kann 23 sein. So wie ich das in meinem Kode gemacht habe, ist 
das nicht richtig und ich habe auch das Problem, dass ich nicht weiss, 
wie ich das ganze einfach machen kann?! Die Bytes möchte ich ab der 
vierten Stelle des Strings speichern.


void kg_daten(void)     //kg daten empfangen
{

     unsigned int i;
     unsigned int a,b,c,d,e,f,g,h,u,j,t,l,m,n,o,p,q,r,s;

    for(i = 0; i <buffer_lengh; i++)
    {
        kgbuffer[i]=buffer[i+4];

        if(pbuffer>=3)
        {
            kgbuffer[4] = a;
            kgbuffer[5] = b;
            kgbuffer[6] = c;
            kgbuffer[7] = d;
            kgbuffer[8] = e;
            kgbuffer[9] = f;
            kgbuffer[10] = g;
            kgbuffer[11] = h;
            kgbuffer[12] = u;
            kgbuffer[13] = j;
            kgbuffer[14] = t;
            kgbuffer[15] = l;
            kgbuffer[16] = m;
            kgbuffer[17] = n;
            kgbuffer[18] = o;
            kgbuffer[19] = p;
            kgbuffer[20] = q;
            kgbuffer[21] = r;
            kgbuffer[22] = s;
            kgbuffer[23] = t;
        }
}

von Karl heinz B. (kbucheg)


Lesenswert?

Sorry.
Aber aus dem bisher Geschilderten werde ich nicht schlau.
Die Code-Analyse des geposteten Abschnitts bringt mich
auch nicht weiter.

von Oli K. (waldmeister)


Lesenswert?

Also ich hbae einen String der unterschiedlich lang ist. Ab dem vierten 
byte möchte ich die Daten byte für byte speichern, wenn vorhanden. In 
der for Schleife möchte ich i hochzählen lassen und vergleiche i mit der 
Stringlänge.
Bei kgbuffer[i] = buffer[i+4]; weise ich die Werte vom buffer, wo der 
String ist zu i+4 bedeutet, dass ich das vierte byte haben möchte. Mein 
Problem ist, dass ich nun die bytes von 5,6,....,22,23 abseichern 
möchte. Und wenn der string nur 7 byte gross ist, dann soll er nur bis 7 
speichern.
Ich habe  auch schon überlegt, ein dynamischen Speicher zu benutzen, was 
aber in meinen Augen keinen Sinn macht, da ich 23 Byte maximal brauche 
und diesen einfach festsetze. Somit möchte ich einfach die empfangenen 
bytes speichern.

von Rolf Magnus (Gast)


Lesenswert?

> Also ich hbae einen String der unterschiedlich lang ist.

Ein einzelnes Ding kann nicht "unterschiedlich" sein.

> Ab dem vierten byte möchte ich die Daten byte für byte speichern, wenn
> vorhanden. In der for Schleife möchte ich i hochzählen lassen und
> vergleiche i mit der Stringlänge.
> Bei kgbuffer[i] = buffer[i+4]; weise ich die Werte vom buffer, wo der
> String ist zu i+4 bedeutet, dass ich das vierte byte haben möchte. Mein
> Problem ist, dass ich nun die bytes von 5,6,....,22,23 abseichern
> möchte. Und wenn der string nur 7 byte gross ist, dann soll er nur bis
> 7 speichern.

Das machst du doch eigentlich schon mit der for-Schleife und dem 
kgbuffer[i] = buffer[i+4];. Wozu ist jetzt der Rest da? Was ist pbuffer? 
Warum versuchst du, die gerade aus buffer nach kgbuffer kopirten Werte 
danach gleich wieder zu überschreiben?

von Karl heinz B. (kbucheg)


Lesenswert?

Ich hab dich immer noch nicht.

Was ist kgbuffer? Welchen Zweck erfüllt der?

> Also ich hbae einen String der unterschiedlich lang ist.

OK. Ein String. Also '\0' terminiert?
In welchem Array ist dieser String gespeichert?
Ist der in buffer?

> Ab dem vierten byte möchte ich die Daten byte für byte speichern,
> wenn vorhanden

Wo möchtest du die speichern?
In kgbuffer?

Auf wen bezieht sich das 'vierte Byte'. Auf das
Original, also buffer, oder auf das Ziel, also kgbuffer?

In deinem Code da oben kommen viele variablen
a, b, c, d, etc vor. Was hat es mit denen auf sich?


Bis jetzt versteh ich eigentlich nur, dass
du möchtest:

   for( i = 0; i < buffer_length; ++i )
     kgbuffer[i] = buffer[i+4];

wenn der String in buffer tatsächlich 0-terminiert
ist, dann könnte man das einfacher schreiben als:

   strcpy( kgbuffer, buffer + 4 );

Aber ich komm ums Verrecken nicht drauf, was du mit
a, b, c, d, etc. vor hast.

Ev. würde ein kleines Schaubild weiterhelfen.

von Oli K. (waldmeister)


Lesenswert?

Die ganzen Variablen habe ich benutzt, um vom String byte für byte 
abzuspeichern. Von dort aus möchte ich dann jedes byte weiter 
verarbeiten. Aber wahrscheinlich geht das ganze eben viel einfacher. 
Leider komme ich im Moment nicht drauf, wie!
String --> ab Byte 4 speichern:
buffer[4] = a;
buffer[5] = b;
...
Mit diesen Variablen bezwecke ich, dass dann meine bytes drinnen sind.

Kgbuffer belege ich mit buffer[i+4],und dort möchte ich die daten dann 
speichern.
String is \o terminiert und wird in buffer abgespeichert.

von Karl heinz B. (kbucheg)


Lesenswert?

Ich würde dir ja gerne helfen. Aber ich kann einfach nicht
erraten, was dein Ziel sein soll und wie die Dinge
zusammenhängen.
Ich kann dir nur raten, mal dir ein Schaubild, aus dem
ersichtlich ist, wie die Teile zusammenhängen und in
welcher Reihenfolge welche Aktion gemacht werden soll.

Das hier:
> Die ganzen Variablen habe ich benutzt, um vom String byte für byte
> abzuspeichern. Von dort aus möchte ich dann jedes byte weiter
> verarbeiten.

klingt jetzt eher wieder danach, als ob deine Bytes aus
dem Buffer kommen und eigentlich auf die Variablen
verteilt werden sollen.


Das hier ist dein ursprünglicher Buffer


  buffer
  +---+---+---+---+---+---+---+- ... -+---+---+
  |   |   |   |   |   |   |   |       |   |   |
  +---+---+---+---+---+---+---+- ... -+---+---+

Wieviele bytes darin belegt sind, steht in buffer_length

 Jetzt hast du noch einen 2. ten Buffer, nämlich kgbuffer

  kgbuffer
  +---+---+---+---+---+---+---+---+---+- ... -+---+---+
  |   |   |   |   |   |   |   |   |   |       |   |   |
  +---+---+---+---+---+---+---+---+---+- ... -+---+---+

Und nu?
Wenn ich richtig rausgelesen habe, dann willst du
von buffer, ab dem 4.ten Element, alles was noch dahinter
im Buffer steht in kgbuffer ablegen.
Also so:

  buffer
  +---+---+---+---+---+---+---+- ... -+---+---+
  |   |   |   |   | o | o | o |       |   |   |
  +---+---+---+---+-|-+-|-+-|-+- ... -+---+---+
                    |   |   |   |
  kgbuffer          |   |   |   |
    +---------------+   |   |   |
    |   +---------------+   |   |
    |   |   +---------------+   |
    |   |   |   +---------------+
    |   |   |   |   ..........
  +-|-+-|-+-|-+-|-+---+---+---+---+---+- ... -+---+---+
  | v | v | v | v |   |   |   |   |   |       |   |   |
  +---+---+---+---+---+---+---+---+---+- ... -+---+---+

> Mit diesen Variablen bezwecke ich, dass dann meine bytes drinnen sind

Als gelernter Österreicher, sage ich da nur: No, na.
Dieser Satz ist extrem nichtssagend.

Dein Hauptproblem dürfte sein, dass du dir selbst nicht
wirklich erklären kannst, was du eigentlich erreichen möchtest.
Geschweige denn uns. Mal dir ein Bild. Füge Pfeile ein
welche Aktion in welcher Reihenfolge passieren soll, welcher
Wert wann wohin kopiert werden soll. Das hilft die Gedanken zu
ordnen.

von Oli K. (waldmeister)


Lesenswert?

Genau so wie du es mit dem buffern gezeichnet hast meine ich das auch. 
Und genau so möchte ich meine Variablen dann abspeichern. Byte für byte 
in die unterschiedlichen Variablen. Wobei kgbuffer nicht unbedingt nötig 
ist, da ich eigentlich auch über buffer direkt darauf zugreifen könnte.
meine überlegungen sind:


void kg_daten(void)
{
      unsigned int i = 0;
      unsigned char kg;

    for(i = 4; i <buffer_lengh; i++)
    {
      kg = buffer[i];

    }

    if(kg > pbuffer)
       {
        lcd_clrscr();
        lcd_puts("No Data");
    }
}

nun funktioniert es.

von Karl heinz B. (kbucheg)


Lesenswert?

> nun funktioniert es.

Wenn du das sagst.
Das Fragment das du gepostet hast, ist ziemlich
sinnfrei.

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.