mikrocontroller.net

Forum: Compiler & IDEs Compiler-Error xy-ungelöst


Autor: Markus B. (rusticus)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

ich sitze nun schon 2 Tage über meinen Code und probiere und probiere 
aber ich bekomm einfach den Compiler-Error nicht gelöst, nun suche ich 
hier um Hilfe

//UART definieren
#ifndef F_CPU
#define F_CPU 16000000UL
#endif
#define UART_BAUD_RATE 38400

//Includes
#include <stdlib.h>
#include <avr/io.h>
#include <avr/interrupt.h>

#include <util/delay.h>

#include "uart.h"
#include <avr/pgmspace.h>

//PORTS definieren
#define LED1  (1 << PE3)
#define LED2  (1 << PE4)
#define LED3  (1 << PE5)

#define OUT1  (1 << PC7)
#define OUT2  (1 << PC6)
#define OUT3  (1 << PC5)
#define OUT4  (1 << PC4)
#define OUT5  (1 << PC3)
#define OUT6  (1 << PC2)
#define OUT7  (1 << PC1)
#define OUT8  (1 << PC0)

#define OUT9  (1 << PD7)
#define OUT10 (1 << PD6)
#define OUT11 (1 << PD5)
#define OUT12 (1 << PD4)

//Zeichen empfangen
unsigned char uart_get(void)
{
int c;
int i = 0;
unsigned char string[10];

  do
  {
        c = uart_getc();
        if ( c & UART_NO_DATA )
        {
            /* 
             * no data available from UART 
             */
        }
        else
        {
            /*
             * new data available from UART
             * check for Frame or Overrun error
             */
            if ( c & UART_FRAME_ERROR )
            {
                /* Framing Error detected, i.e no stop bit detected */
                uart_puts_P("UART Frame Error: ");
            }
            if ( c & UART_OVERRUN_ERROR )
            {
                /* 
                 * Overrun, a character already present in the UART UDR register was 
                 * not read by the interrupt handler before the next character arrived,
                 * one or more received characters have been dropped
                 */
                uart_puts_P("UART Overrun Error: ");
            }
            if ( c & UART_BUFFER_OVERFLOW )
            {
                /* 
                 * We are not reading the receive buffer fast enough,
                 * one or more received character have been dropped 
                 */
                uart_puts_P("Buffer overflow error: ");
            }


          string[i] = c;
          i++;
          _delay_ms(5);

        } //Else-Ende
  } while ( c != '\n' && i < 10 );  //While-Ende
string[i] = '\0';
return *string;

}


//MAIN
int main (void) {

//Register setzen
DDRA = 0x00;
DDRC = 0xFF;
DDRD = 0x0F;
DDRE = 0xC1;

//Variablen deklariern
int IN = 0;
int PC_READY = 0;
unsigned char EING[10];

//UART aktivieren
uart_init ( UART_BAUD_SELECT (UART_BAUD_RATE, F_CPU) );
sei();


while(1)//Endlosschleife
{

  while (PC_READY == 0)
  {
    uart_puts("READY");
    _delay_ms(10);
    EING = uart_get();
    
  }
  //Eingänge abfragen
  IN = PINA;
  
  
  
}//While-Ende

}


Und das ist der Compiler-Error:
Build started 31.8.2010 at 15:54:20
avr-gcc  -mmcu=at90can128 -Wall -gdwarf-2 -Os -std=gnu99 -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -MD -MP -MT Visuschni_v2.o -MF dep/Visuschni_v2.o.d  -c  ../Visuschni_v2.c
../Visuschni_v2.c: In function 'main':
../Visuschni_v2.c:129: error: incompatible types in assignment
make: *** [Visuschni_v2.o] Error 1
Build failed with 1 errors and 0 warnings...

Alles unter AVRStudio4, somit AVR GCC

Ich hoffe ihr könnt mir helfen und vlt noch ein paar Programmiertipps 
geben, ich arbeite mich erst wieder so richtig ein, nach längerer 
Abstinenz

Für mich heißt der Fehler das mir die Funktion einen Wert bringt, den 
die Variable EING nicht aufnehmen kann. Ich versteh es aber nicht da es 
überall ein "unsigned char" ist.

mfg

Autor: g457 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Es wäre zweckmäßig den ganzen Code zu posten (vorzugsweise als Anhang), 
dann würde auch die Zeilenangabe in der Fehlermeldung passen..

Hier ist ein Auszug wo der Compiler einen error wirft (Zeile 120..):

106> unsigned char EING[10];
..
120> EING = uart_get();

..wundert micht nicht dass ihm das nicht gefällt. Mach mal einen Index 
dran an das EING :-)

Autor: Andreas Ferber (aferber)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Markus B. schrieb:
> Für mich heißt der Fehler das mir die Funktion einen Wert bringt, den
> die Variable EING nicht aufnehmen kann. Ich versteh es aber nicht da es
> überall ein "unsigned char" ist.

Nein, EING ist ein Array von "unsigned char". Kein Wunder, dass der 
Compiler sich da beschwert, Arrays können in C nicht zugewiesen werden, 
und schon garnicht mit einem Typ der einem einzelnen Element entspricht. 
Folgendes würde gehen:
EING[0] = uart_get();

Kleine Anmerkung am Rande: üblicherweise werden in C nur Makros komplett 
in Großbuchstaben benannt. Für Variablen ist es genauso wie bei 
Funktionen üblich, diese in Kleinbuchstaben zu benennen, oder ggf. auch 
in Mixed Case ("Eingabe"). Künstliche Abkürzungen wie "EING" sollte man 
auch eher vermeiden.

Andreas

Autor: Markus B. (rusticus)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich wollte ja eben in der Funktion den ganzen String wieder zurückgeben, 
aber als C-String?

Und OK wusste da war was mit den Großschreiben, werd ich dann wohl 
wieder ändern

Autor: Klaus Wachtler (mfgkw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ansonsten macht mir das immer noch einen etwas unausgegorenen Eindruck.
Du hast in uart_get(void) ein lokales Feld string[10].

Erstens ist das nur ein lokales Feld, und nach dem Ende der
Funktion verloren. Trotzdem speicherst du munter mehrere Werte drin,
und lieferst den untersten an den Aufrufer zurück.
Willst du wirklich den Rest wegwerfen?

Zweitens spicherst du bis zu 10 Zeichen darin, und hängst dann noch eine 
abschließende 0 an.
Das wird etweas knapp so rein platzmäßig; Reise nach Jerusalem.

Wolltest du vielleicht stattdessen den ganzen String liefern?
Das geht aber anders, und schon gar nicht mit einem lokalen Feld.

Autor: Markus B. (rusticus)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ja genau das wollte ich eben
Hatte es davor immer in der Main direkt eingebaut und wollte es nun eben 
extrahieren als einzelne Funktion, daran scheitere ich aber und verstehe 
nicht wieso

Autor: Klaus Wachtler (mfgkw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Standardtip: erstmal C auf einem PC lernen? Da ist das viel einfacher
(wg. Debuggen etc.).

Autor: Markus B. (rusticus)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Es ist ja nicht so das ich das nicht schon könnte, nur hab nun seit fast 
1,5 Jahren nicht mehr geproggt...

Autor: Klaus Wachtler (mfgkw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Markus B. schrieb:
> Es ist ja nicht so das ich das nicht schon könnte...

Hm.

Einen String als lokale (automatische) Variable zusammen zu
schrauben und zurückgeben zu wollen, deutet nicht allzu
stringent darauf hin :-)

Eine klare Vorstellung von Zeigern und der Lebensdauer von
Variablen sollte man in C schon haben, sonst kommt man nicht weit.

Autor: Markus B. (rusticus)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Naja ein bischen Hilfe wär trotzdem nett, Links reichen ja schon mal 
vorerst, ist ja nicht so das ich eine fertige Lösung haben will

Autor: Rufus Τ. Firefly (rufus) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Literaturhinweis:
Brian Kernighan & Dennis Ritchie, "Programmieren in C", 2. Auflage, 
Hanser-Verlag.

Auch wenn dieses Buch mittlerweile 20 Jahre alt ist, ist es immer noch 
verdammt lesenswert.

Autor: Klaus Wachtler (mfgkw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ok, jetzt bin ich satt und gut gelaunt.
Dann fangen wir mal an..

Schon aus der Entfernung: Du bist dir nicht ganz im Klaren, was du
willst.
Was soll die Funktion uart_get() denn liefern?
Einen String? Oder ein Zeichen?
Das kann man erstens mit einem vernünftigen Namen klarmachen, und
zweitens natürlich entsprechend programmieren.
Ich vermute, die Funktion soll mehrere Zeichen lesen, und einen
kompletten String liefern. Dann ist der Name uart_get() zu
schlapp. Besser wäre gleich zu sagen, was sie liefert. Da du bei einem
\n abbrichst zu lesen, geht es um Zeilen.
Dann würde ich uart_get_line() oder sowas ähnliches als Name
vorschlagen.

Als Kommentar steht bei dir drüber: //Zeichen empfangen
Das passt natürlich nicht zu dem, was die Funktion macht.

Vorschlag:
// liest eine Zeile (maximal ... Zeichen) und liefert sie als
// nullterminierten String zurück:
char * uart_get_line()
{
  ...
}
Für einen nullterminierten C-String ist char* der passende
Rückgabetyp.
char wäre der passende Typ, wenn nur ein Zeichen zurück kommen
sollte.

Das unsigned sollte man weglassen, wenn es nicht einen guten Grund
dafür gibt. Du willst mit den Zeichen wohl nicht rechnen; warum
sollten sie also signed oder unsigned sein? Nur char ohne etwas
davor ist letztlich signed char oder unsigned char, aber es sollte dir
egal sein - also nicht festlegen.

Das void in der Parameterliste einer Funktion, die keine Parameter
bekommt, ist veraltet und inzwischen überflüssig.

Nächstes Problem: ein String benötigt Platz.
Als Programmierer muß man sich in C Gedanken machen, wo dieser Platz
herkommen soll.
Bisher würde das bei dir so aussehen:
// liest eine Zeile (maximal 9 Zeichen) und liefert sie als
// nullterminierten String zurück:
char * uart_get_line()
{
  char  string[10];
  for( ... )
  {
    ...
    string[i] = ...;
    ...
  }
  string[i] = '\0';
  return string;  // nicht *string
}
Das ist jetzt schon etwas besser, aber immer noch falsch.

Gebessert hat sich ja schon der Rückgabetyp; dazu passt das return
string statt return *string.

Mit *string würdest ja ein char liefern, und zwar das unterste in
string, mithin string[0].
Du willst ja aber nicht das eine Zeichen liefern, sondern den ganzen
String. Und das geschieht in C, indem man einen Zeiger auf das erste
Zeichen nimmt. Das ist string.

Falsch (und zwar richtig falsch!) ist es aus folgendem Grund:
string ist eine automatische Variable (alle lokalen Variablen in einer
Funktion oder in einem Block sind automatisch, wenn nicht static davor
steht).
Eine automatische Variable existiert aber nur, solange der umgebende
Block (hier die Funktion) abgearbeitet wird.
Sofort danach kann der Speicherplatz für etwas anderes genutzt werden,
meist für Parameter einer aufgerufenen Funktion, oder deren lokale
Variablen, oder Rücksprungadressen, temporäre Zwischenwerte oder was
auch immer.
Normalerweise ist das in Ordnung, weil man ja auf eine Variable mit
ihrem Namen nur zugreifen kann, solange man in demselben Block ist.
    {
       int i = 12;
       i += 12;
    }
    printf( "%d", i ); // geht nicht
So etwas verhindert der Compiler aus gutem Grund: i ist eine Variable
in dem Block mit den geschweiften Klammern und existiert nur solange
der Block abgearbeitet wird.
Das printf() steht außerhalb, hier lässt der Compiler die Verwendung
von i nicht mehr zu - die Variable existiert dann auch gar nicht mehr.
Ändert man das etwas ab, hat man den Compiler überlistet:
    int   *zeiger_auf_i;
    {
       int i = 12;
       i += 12;
       zeiger_auf_i = &i;
    }
    printf( "%d", *zeiger_auf_i );
Jetzt macht man im Prinzp dasselbe wie eben, nur etwas umständlicher.
In *zeiger_auf_i merkt man sich die Adresse von i, und im printf()
benutzt man die Adresse um auf i zuzugreifen.
Jetzt verhindert Compiler das nicht.
Es ist aber noch genauso falsch: wenn das printf() läuft, wird über
den Zeiger auf i zugegriffen, obwohl i gar nicht mehr existiert
bzw. möglicherweise schon lange für etwas anderes benutzt wird.

Mit solchen Konstruktionen kann man sich in C schön selbst verarschen,
wenn man nicht weiß was man tut.

Im Prinzip etwas ähnliches macht man mit dem obigen falschen Beispiel:
// liest eine Zeile (maximal ... Zeichen) und liefert sie als
// nullterminierten String zurück:
char * uart_get_line()
{
  char  string[10];
  for( ... )
  {
    ...
    string[i] = ...;
    ...
  }
  string[i] = '\0';
  return string;  // nicht *string
}

   ...
   char *meinezeile;
   meinezeile = uart_get_line();
   printf( "gelesen: %s", meinezeile );
   ...
(Es soll jetzt mal egal sein, daß es ein printf() in dieser Form gar
nicht auf einem AVR gibt; es geht nur darum, den String irgendwie zu
verwenden.)

Was passiert bei diesem Beispiel?
in uart_get_line() gibt es eine lokale (automatische) Variable string;
das ist ein Feld mit 10 Zeichen.
Beim Rücksprung wird die Adresse des ersten Elements zurückgegeben und
beim Aufrufer in meinezeile gespeichert.
meinezeile ist also ein Zeiger auf das erste Zeichen von string,
obwohl die 10 Zeichen von string vielleicht schon für etwas anderes
verwendet werden.
Bei soetwas muß man in C ziemlich nervös werden!

So ist es jedenfalls Murks.

Es gibt mehrere Möglichkeiten, das zu verbessern,
Leider sind sie alle nicht richtig schick, jede Variante ist irgendwie
etwas doof.

Erste Möglichkeit: Den String static machen, dann ist es keine
automatische Variable mehr:
// liest eine Zeile (maximal ... Zeichen) und liefert sie als
// nullterminierten String zurück:
char * uart_get_line()
{
  static char  string[10];
  for( ... )
  {
    ...
    string[i] = ...;
    ...
  }
  string[i] = '\0';
  return string;  // nicht *string
}

   ...
   char *meinezeile;
   meinezeile = uart_get_line();
   printf( "gelesen: %s", meinezeile );
   ...

Damit klappt es auf einmal wundersamerweise.
Eine static-Variable wird nicht immer neu angelegt und wieder
wegegworfen, sondern existiert einmal von Programmstart bis
Programmende.

Aber wo ist dabei der Haken?
Daß sie eben nur einmal existiert.
   ...
   char *meinezeile1;
   char *meinezeile2;
   meinezeile1 = uart_get_line();
   printf( "gelesen1: %s", meinezeile1 ); // gibte erste Zeile aus
   meinezeile2 = uart_get_line();
   printf( "gelesen2: %s", meinezeile2 ); // gibte zweite Zeile aus

   printf( "gelesen1: %s", meinezeile1 ); // gibte zweite Zeile aus (!)
   printf( "gelesen2: %s", meinezeile2 ); // gibte zweite Zeile aus
   ...

In diesem Beispiel sieht es erst vernünftig aus: mit meinezeile1 wird
die erste gelesene Zeile ausgegeben, mit meinezeile2 dann die zweite.
Mit der folgenden Ausgabe wird sowohl für meinezeile1 als auch für
meinezeile2 nur noch die letzte gelesene Zeile (also die zweite)
ausgegeben, weil in der static-Variable string ja mit der zweiten
Zeile die erste überschrieben wurde.

Das wird der Aufrufer so wahrscheinlich nicht erwarten; das ist also
doch etwas problematisch.
Richtig krank werden static-Variablen bei Programmen, die mit mehreren
Threads arbeiten, ebenso wie bei rekursiven Funktionsaufrufen.
Leider sind mehrere Funktionen der Standard-Lib von C mit statischen
Variablen gebaut und deshalb nicht benutzbar in
multitasking-Programmen (strtok() z.B. fällt auf die Klappe).

Das wäre in deinem Beispiel aber kein Problem, also würde es mit
static erstmal gehen.

Eine andere Lösung wäre: in der Funktion wird für den gelesenen String
Speicher allokiert und der Zeiger darauf zurückgegeben:
// liest eine Zeile (maximal ... Zeichen) und liefert sie als
// nullterminierten String zurück:
char * uart_get_line()
{
  char  *string = malloc( genugzeichen.... );
  for( ... )
  {
    ...
    string[i] = ...;
    ...
  }
  string[i] = '\0';
  return string;
}

   ...
   char *meinezeile;
   meinezeile = uart_get_line();
   printf( "gelesen: %s", meinezeile );
   free( meinezeile ); // Speicher nach letzter Benutzung freigeben
   ...

Das würde jetzt auch bei Multitasking funktionieren ebenso wie bei
Rekursion.

Und wo ist hier der Haken?
In der Funktion wird Speicher allokiert, und erst der Aufrufer kann den
Speicher freigeben - wenn er es nicht vergisst.

Leider wird es mehr oder weniger häufig vergessen, weswegen es als
höchst unelegant gilt, in einer Funktion Speicher zu allokieren, der
vom Aufrufer wieder freigegeben werden muß.

Auf einem Controller wird man diese Lösung auch nicht gerne sehen,
weil es da wegen des knappen Speichers selten ratsam ist, dynamische
Speicherverwaltung mit malloc() zu nutzen.
Ich hatte hier ja auch die Fehlerbehandlung unterschlagen: Was soll
passieren, wenn gar kein Speicher allokiert werden kann? Auf einem
Controller kann man ja nicht einfach eine kurze Meldunbg ausgeben und
das Programm beenden. Ein Absturz wird auch nicht gern gesehen und
nicht so leicht akzeptiert wie unter Windows.

Nächste Möglichkeit: Der Aufrufer selbst beschafft den Platz, übergibt
ihn und die Funktion schreibt nur rein:
// liest eine Zeile (maximal ... Zeichen) und liefert sie als
// nullterminierten String zurück:
char * uart_get_line( char *puffer, size_t l_puffer )
{
  for( ... && i<l_puffer-1 )
  {
    ...
    string[i] = ...;
    ...
  }
  string[i] = '\0';
  return string;
}

   ...
   char meinezeile[10];
   uart_get_line( meinezeile, 10 );
   printf( "gelesen: %s", meinezeile );
   ...
Weil die Funktion nicht feststellen kann, wie groß der Puffer ist, muß
der Aufrufer auch gleich die Länge übergeben.

Das hat nebenbei den Vorteil, daß man in der Funktion nicht mehr
spekulieren muß, wieviel Platz nötig (wie kommst du gerade auf die 10?
Woher soll man das in der Funktion wissen?)
Die Funktion kann also je nach Situation mal mit einem großen oder mal
mit einem kleinen Puffer aufgerufen werden.

Nachteil dieser Lösung ist, daß der Aufruf etwas umständlich ist (2
Parameter mehr).

Man hat also mehrere Möglichkeiten, das zu lösen.

Eleganter geht es dann erst in C++, aber das geht jetzt zu weit.
Als "bisschen Hilfe" sollte das reichen.

Autor: Frank M. (ukw) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Klaus Wachtler schrieb:
> Als "bisschen Hilfe" sollte das reichen.

Erstklassig ausgeführt, Klaus! Genau dieselben Gedankengänge gehe ich 
durch, wenn ich versuche, jemandem C bzw. Stringverarbeitung in C 
beizubringen. Aber ich hätte mir niemals die Mühe gemacht, es in einem 
Forum so detailiert rüberzubringen, wo ich schon Hopfen und Malz 
aufgegeben habe. Kompliment!

> ok, jetzt bin ich satt und gut gelaunt.

Daran muss es gelegen haben ;-)

Frank

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

Bewertung
0 lesenswert
nicht lesenswert
Klaus Wachtler schrieb:

> Man hat also mehrere Möglichkeiten, das zu lösen.

Schöne Zusammenfassung.
Hast du etwas dagegen, wenn ich mir den größten Teil davon für die FAQ 
(direkt nach dem Kapitel Stringverarbeitung) klaue?

Autor: Markus B. (rusticus)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

ersteinmal danke für die erstklassige Erklärung, hat mir einiges näher 
gebracht vom Verständnis her, aber ein bischen was wusste ich auch schon 
;)
// liest eine Zeile (maximal ... Zeichen) und liefert sie als
// nullterminierten String zurück:
char * uart_get_line( char *puffer, size_t l_puffer )
{
  for( ... && i<l_puffer-1 )
  {
    ...
    string[i] = ...;  //Puffer?
    ...
  }
  string[i] = '\0';  //Puffer?
  return string;  //Puffer?
}

   ...
   char meinezeile[10];
   uart_get_line( meinezeile, 10 );
   printf( "gelesen: %s", meinezeile );
   ...

Müsste man dort nicht auch dann "puffer" schreiben? Sonst hab ich doch 
wieder die unbekannte Variable "string"#

Was ich aber nicht verstehe, warum muss ich den Rückgabewert der 
Funktion nicht auffangen? Wird die Variable durch den Zeiger im Aufruf 
direkt bearbeitet?

Habe aber schon einiges von der Form verbessert, wie das auskommentieren 
und die Namen der Variablen und Funktion


mfg Rusticus

Autor: Markus B. (rusticus)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Ich hab mich mit dem Thema Pointer jetzt nochmal befasst und habs nun 
verstanden, das ich da nichts mehr auffangen muss. Ich lieg jetzt 
richtig der Annahme das ich ja keine neue Variable erzeuge sondern meine 
Variable aus dem Main-Teil bearbeite und ich deshalb nichts mehr 
auffangen muss?

Mein Problem ist jetzt folgendes:
Build started 1.9.2010 at 11:39:56
avr-gcc  -mmcu=at90can128 -Wall -gdwarf-2 -Os -std=gnu99 -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -MD -MP -MT Visuschni_v2.o -MF dep/Visuschni_v2.o.d  -c  ../Visuschni_v2.c
avr-gcc  -mmcu=at90can128 -Wall -gdwarf-2 -Os -std=gnu99 -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -MD -MP -MT uart.o -MF dep/uart.o.d  -c  ../uart.c
../uart.c:216:3: error: #error "no UART definition for MCU available"
../uart.c:243: warning: 'UART0_RECEIVE_INTERRUPT' appears to be a misspelled signal handler
../uart.c: In function 'UART0_RECEIVE_INTERRUPT':
../uart.c:256: error: 'UART0_STATUS' undeclared (first use in this function)
../uart.c:256: error: (Each undeclared identifier is reported only once
../uart.c:256: error: for each function it appears in.)
../uart.c:257: error: 'UART0_DATA' undeclared (first use in this function)
../uart.c: At top level:
../uart.c:286: warning: 'UART0_TRANSMIT_INTERRUPT' appears to be a misspelled signal handler
../uart.c: In function 'UART0_TRANSMIT_INTERRUPT':
../uart.c:300: error: 'UART0_DATA' undeclared (first use in this function)
../uart.c:303: error: 'UART0_CONTROL' undeclared (first use in this function)
../uart.c:303: error: 'UART0_UDRIE' undeclared (first use in this function)
../uart.c: In function 'uart_putc':
../uart.c:435: error: 'UART0_CONTROL' undeclared (first use in this function)
../uart.c:435: error: 'UART0_UDRIE' undeclared (first use in this function)
make: *** [uart.o] Error 1
Build failed with 10 errors and 2 warnings...

Ich nutze die normale UART-Libary von Peter Fleury und so was in der 
Richtung hatte ich noch nicht damit


Danke schon mal

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

Bewertung
0 lesenswert
nicht lesenswert
Markus B. schrieb:

> Müsste man dort nicht auch dann "puffer" schreiben? Sonst hab ich doch
> wieder die unbekannte Variable "string"#

Ja.
Nimms als Tippfehler, der bei direktem Eintippen von Code in einem Forum 
schon mal passiert.

> Was ich aber nicht verstehe, warum muss ich den Rückgabewert der
> Funktion nicht auffangen?

Weil die Funktion ja sowieso einen Pointer bekommt und damit das Array 
des Aufrufers direkt manipuliert.

> Wird die Variable durch den Zeiger im Aufruf
> direkt bearbeitet?

Ja.
Sagtest du nicht, du hättest schon mal C programmiert?

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

Bewertung
0 lesenswert
nicht lesenswert
Markus B. schrieb:

> Ich nutze die normale UART-Libary von Peter Fleury und so was in der
> Richtung hatte ich noch nicht damit

Dann sieh dir die erste Meldung an


../uart.c:216:3: error: #error "no UART definition for MCU available"


Peter war so freundlich und hat den COmpiler eine Fehlermeldung ausgeben 
lassen, wenn du eine MCU (also einen Prozessor) benutzt, den er nicht 
kennt und von dem er daher auch nicht weiß, welche Bits in welchem 
Register zu setzen sind, etc.

Autor: Klaus Wachtler (mfgkw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Karl heinz Buchegger schrieb:
>> Müsste man dort nicht auch dann "puffer" schreiben? Sonst hab ich doch
>> wieder die unbekannte Variable "string"#
>
> Ja.

Sorry, war natürlich mein Fehler.

Denkt euch davor noch ein #define puffer string, dann klappt es :-)

Autor: Klaus Wachtler (mfgkw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Karl heinz Buchegger schrieb:
> Hast du etwas dagegen, wenn ich mir den größten Teil davon für die FAQ
> (direkt nach dem Kapitel Stringverarbeitung) klaue?

nee, natürlich nicht.
Auch wenn ich vermute, daß es die meisten eh nicht lesen, sondern gleich 
wieder fragen :-(

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

Bewertung
0 lesenswert
nicht lesenswert
Klaus Wachtler schrieb:
> Karl heinz Buchegger schrieb:
>> Hast du etwas dagegen, wenn ich mir den größten Teil davon für die FAQ
>> (direkt nach dem Kapitel Stringverarbeitung) klaue?
>
> nee, natürlich nicht.
> Auch wenn ich vermute, daß es die meisten eh nicht lesen, sondern gleich
> wieder fragen :-(


LOL
Aber zumindest hat man dann mit einem Link eine erschöpfende Auskunft 
gegeben.

Autor: Frank M. (ukw) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Markus B. schrieb:

> char * uart_get_line( char *puffer, size_t l_puffer )
> ...
>   for( ... && i<l_puffer-1 )
>   {
>     ...
>     string[i] = ...;  //Puffer?
>     ...
>   }
>   string[i] = '\0';  //Puffer?
>   return string;  //Puffer?
> }


> Müsste man dort nicht auch dann "puffer" schreiben? Sonst hab ich doch
> wieder die unbekannte Variable "string"#

Ich würde das Interface der Funktion noch etwas ändern, nämlich dass 
uart_get_line nicht den string/puffer zusätzlich als return zurückgibt, 
sondern besser die Anzahl der eingelesenen Zeichen. Dann ist das 
Interface weitgehend kompatibel mit der 
UNIX/Linux-Standard-System-Funktion read() - bis auf den Filedescriptor 
fd, den man hier nicht braucht.

Gruß,

Frank

Autor: Klaus Wachtler (mfgkw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Kann durchaus auch sinnvoll sein.
So wie von mir ist die Funktion halt kompatibel zu strcpy()/strcat()
und man kann sie direkt zum Weiterverwenden des Strings nutzen.
Je nachdem, was man braucht.

Genau genommen hast du recht, weil man sonst nie erfährt, ob der
der String gereicht hat.
Die Weiterverwendung des String könnte man auch mit einem
Kommaoperator erreichen, also gebe ich klein bei.

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

Bewertung
0 lesenswert
nicht lesenswert
Karl heinz Buchegger schrieb:
> Klaus Wachtler schrieb:
>> Karl heinz Buchegger schrieb:
>>> Hast du etwas dagegen, wenn ich mir den größten Teil davon für die FAQ
>>> (direkt nach dem Kapitel Stringverarbeitung) klaue?
>>
>> nee, natürlich nicht.
>> Auch wenn ich vermute, daß es die meisten eh nicht lesen, sondern gleich
>> wieder fragen :-(
>
>
> LOL
> Aber zumindest hat man dann mit einem Link eine erschöpfende Auskunft
> gegeben.

Hab mir mal eine erste Version davon für die FAQ geklaut
http://www.mikrocontroller.net/articles/FAQ#wie_sc...

Autor: Klaus Wachtler (mfgkw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Kann man nicht neben dem Textfeld zum Antworten gleich
eine Auswahlbox installieren mit den Top-Ten-Antworten:
- K&R lesen
- K&R nochmal lesen
- AVR-Tutorial lesen
- AVR-gcc-Tutorial lesen
- Strings zurückgeben
- für LCD mit 44780 gibt es fertigen Quelltext
- google
- Hausaufgaben selber machen
- nur verständlichen Quelltext posten, Formatierung nutzen ...
- ...

Jeweils mit einem kleinen Link.

Autor: Markus B. (rusticus)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Dankeschön für die Hilfe, muss ich mich halt im Internet umsehen oder 
versuchen selbst zu portieren, um es auf meinen µC zum laufen zu 
bekommen


Und zum Pointer muss ich gestehen, das ich mich da nach wie vor sehr 
schwer tue das zu verstehen, obwohl ich glaub ich jetzt ein gutes Stück 
weiter bin!


Noch ne Frage zur Stringlänge, wenn ich zu wenig Buffer übergebe, also 
zu wenig Zeichen, erfahre ich dann überhaupt effektiv wie lang es war? 
Weil ein übergelaufenes Array gibt mir doch sicher nicht die richtige 
Anzahl der Zeichen zurück oder?

Und wie sollte man die Länge am besten auslesen? Mit der strlen-Funktion 
( http://www.cplusplus.com/reference/clibrary/cstring/strlen/) ?

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

Bewertung
0 lesenswert
nicht lesenswert
Markus B. schrieb:

> Noch ne Frage zur Stringlänge, wenn ich zu wenig Buffer übergebe, also
> zu wenig Zeichen, erfahre ich dann überhaupt effektiv wie lang es war?

Nein.
Deshalb übergibt man die Länge ja mit, eben weil die Funktion keine 
Chance hat das selber rauszufinden

> Weil ein übergelaufenes Array gibt mir doch sicher nicht die richtige
> Anzahl der Zeichen zurück oder?

Wenn dir das Array überläuft, dann ist das schlecht. Sehr schlecht
http://www.mikrocontroller.net/articles/FAQ#Beispiele_2

> Und wie sollte man die Länge am besten auslesen? Mit der strlen-Funktion
> ( http://www.cplusplus.com/reference/clibrary/cstring/strlen/) ?

entweder so oder die Funktion liefert anstelle des Pointers die Länge 
des eingelesenen Strings. Die Funktion kennt die ja, wenn sie den String 
aufbaut. Also kann sie den Wert auch zurückgeben anstelle eines 
Pointers, den im Prinzip kein Mensch braucht, weil er ihn schon hat :-)

Autor: Markus B. (rusticus)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
OK dann versteh ich den Sinn nicht ganz

Was bringt es mir zu wissen wie viele Zeichen übertragen wurden, wenn 
das nur dann klappt, wenn alles gut läuft, wäre es nicht interesanter zu 
sehen das er überläuft? Und dann dementsprechend was dagegen zu machen?

Autor: Klaus Wachtler (mfgkw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
In der Funktion sollte man sicherstellen, daß es keinen Überlauf gibt.
In deiner Originalversion hattest du ja schon vorgesehen. höchstens 10
Zeichen abzuspeichern. Das ist im Prinzip in Ordnung (außer, daß du dich
verzählt hattest und 10 Zeichen plus abschließender Null in einem
10 Zeichen großen Feld halt nicht passen, sondern nur 9 plus die Null).

So ähnlich würde man das in der Funktion wieder machen.

Die Funktion könnte jetzt die Anzahl der gelesenen Zeichen
zurückliefern. Wenn das 10 ist, könnte der Aufrufer (falls er es
kontrollieren will) an der letzten Stelle (vor der Null) nachsehen,
ob da der Zeilenvorschub steht; dann ist alles in Ordnung.
Wenn da etwas anderes steht, war der Puffer zu klein.

Einen Überlauf gab es trotzdem nicht, weil ja vorher mit dem
Übertragen abgebrochen wurde.

Es liegt jedenfalls dann am Aufrufer, entsprechend zu reagieren.
Zum Beispiel könnte er es mit einem größeren Feld nochmal versuchen,
oder erst den bisherigen Teil verarbeiten und sich anschließend das
nächste Stück holen, oder wie auch immer.

Die Idee ist wieder eine saubere Trennung der Zuständigkeiten:
Die Funktion soll maximal die angegebene Anzahl Zeichen holen,
mehr kann sie nicht tun.
Wenn der Platz nicht reicht, kann der Aufrufer (und nur er)
sinnvoll darauf reagieren.

Autor: Markus B. (rusticus)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Also wenn ich das mal so rekapitulieren darf

if (strlen(uart_get_line(...))==10 && Eing[9] != '\0')
{
==> Fehlermeldung ausgeben
==> Erneut senden
==> etwas anderes ähnliches tun
}


Was wären dann sinnvolle Optionen? Ich überlege so etwas einzubaun

Für mich macht im moment am meisten Sinn, der Gegenstelle mitzuteilen 
das der Buffer vollgelaufen ist und dieser die Option neu senden soll

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

Bewertung
0 lesenswert
nicht lesenswert
Markus B. schrieb:
> OK dann versteh ich den Sinn nicht ganz
>
> Was bringt es mir zu wissen wie viele Zeichen übertragen wurden,

nicht 'übertragen wurden'!
Die Frage ist: wieviele Zeichen kann deine Empfangsfunktion empfangen, 
ehe es zu einem Überlauf kommt!

Kein Mensch sagt, dass du den Buffer voll machen musst. Aber du darfst 
auf keinen Fall hinten rausschreiben!

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

Bewertung
0 lesenswert
nicht lesenswert
Markus B. schrieb:

> Was wären dann sinnvolle Optionen?

Mit der Gegenstelle einen Pakt schliessen.
Maximal 80 Zeichen pro Zeile und nicht mehr

Wenn du das nicht kannst, dann muss der Aufrufer der Funktion 
entsprechende Mechanismen einbauen, um zb 2 Teilergebnisse zu einem 
größeren zusammenzusetzen. Wobei sich dann allerdings die Frage erhebt, 
warum er nicht gleich der Funktion einen größeren BUffer gegeben hat.

Autor: Klaus Wachtler (mfgkw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Markus B. schrieb:
> Also wenn ich das mal so rekapitulieren darf
>
> if (strlen(uart_get_line(...))==10 && Eing[9] != '\0')
> {
> ==> Fehlermeldung ausgeben
> ==> Erneut senden
> ==> etwas anderes ähnliches tun
> }

so ähnlich, ja.

Allerdings kostet das strlen() schon wieder Rechenzeit, weil es
den String entlanglaufen muß.
Deshalb schon seit einiger Zeit der Vorschlag, daß die Funktion
(z.B. uart_get_line()) als Rückgabewert gleich diesen Wert liefert,
in der Funktion fällt er ja als Nebenprodukt an.
Dann braucht der Aufrufer nicht mehr zählen (lassen), sondern nimmt
gleich den Rückgabewert.

>
>
> Was wären dann sinnvolle Optionen? Ich überlege so etwas einzubaun

Da ist deine Phantasie gefragt, nur du kennst deine Aufgabenstellung.

>
> Für mich macht im moment am meisten Sinn, der Gegenstelle mitzuteilen
> das der Buffer vollgelaufen ist und dieser die Option neu senden soll

Hört sich plausibel an.
Auf jeden Fall sollte der Sender informiert werden, daß sein
Auftrag/Befehl/etc. nicht ausgeführt werden kann.

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

Bewertung
0 lesenswert
nicht lesenswert
Klaus Wachtler schrieb:

>> Für mich macht im moment am meisten Sinn, der Gegenstelle mitzuteilen
>> das der Buffer vollgelaufen ist und dieser die Option neu senden soll
>
> Hört sich plausibel an.
> Auf jeden Fall sollte der Sender informiert werden, daß sein
> Auftrag/Befehl/etc. nicht ausgeführt werden kann.

Wobei das auch nicht der Weisheit letzter Schluss ist.
Wenn die Gegenstelle ein Mensch ist, dann geht das ja noch an.
Aber wenn das ein Programm ist, was soll denn dieses Programm dann tun?
Es will/muss etwas übertragen und kann es aufgrund Platz-Beschränkungen 
des Empfängers nicht machen. Bei so ziemlich jeder Strategie des Senders 
(ausser den Fehler an den Benutzer zu melden und die Arbeit 
einzustellen) kann ich sofort mit der Frage kontern: Warum hast du es 
nicht gleich so gemacht anstatt es auf einen Fehler ankommen zu lassen?

"Fehler melden und Arbeit einstellen" ist zwar aus theoretischer Sicht 
die einzig sinnvolle Möglichkeit. Aus Benutzersicht, der das System 
eigenständig ohne ständige Überwachung laufen lassen will, ist das aber 
völlig inakzeptabel.

Autor: Klaus Wachtler (mfgkw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Kann sein, muß nicht.

Wenn ich auf dem PC ein Programm habe, muß ich sehr wohl
irgendwie mit Fehlern umgehen können (Gerät nicht an? Kabel
fehlt? Schnittstelle nicht ansprechbar?)
Es gibt nun mal Situationen, wo man die Funktion nicht mehr
erzwingen kann.
Dazu kann auch gehören, daß man ein Kommando schickt, das eine
Gegenseite mit einem aktuellen SW-Stand verstehen würde, es hängt
aber ein altes Gerät ohne Update dran. Mit solchen Fehlern muß
man irgendwie umgehen.

Eigentlich ist alles Spekulation, solange keiner weiß, um was
es hier wirklich geht.

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

Bewertung
0 lesenswert
nicht lesenswert
Klaus Wachtler schrieb:

> Eigentlich ist alles Spekulation,

Yep.
Ich hab mich jetzt nur auf den Fall konzentriert, dass der PC eine Zeile 
mit 80 Zeichen schickt, der der µC nicht annehmen kann, weil der 
Zeilenbuffer nur 40 Zeilen lang ist.
Was soll der PC denn dann machen? Selbst wenn er eine Fehlermeldung 
zurückbekommt: Seine Daten sind nun  mal 80 Zeichen lang und die müssen 
übertragen werden, da hilft auch keine Fehlermeldung (ausser in der 
Entwicklungsphase, dann weiß man das man hier ändern muss).
Wenn PC-seitig eine Strategie existiert, wie man im Fehlerfall diese 80 
Zeichen in mehrere Teile aufteilt, die einzeln übertragen werden, dann 
hätte man diese Strategie auch gleich von vorne herein benutzen können 
und es wäre gar nicht zum Buffer-Overflow Problem auf der Empfängerseite 
gekommen.

Das war die Überlegung. Und daher bin ich der Meinung, dass eine 
derartige Fehlermeldung, ausser während der Entwicklungszeit der 
Programme, nur von beschränktem Nutzen ist (*). Die Idee "Da meldet der 
Empfänger bei Bufferoverflow einen Fehler und dann muss der Sender das 
eben anders schicken" ist IMHO sehr zweifelhaft in ihrer 
Durchführbarkeit.

(*) was nicht heißen soll, dass ich dieses Problem nicht dem Benutzer 
melden würde. Würde ich schon. Nur würde ich keinen Gedanken an eine 
Lösung ala "Wie kann ich die Übertragung in diesem Fehlerfall dann doch 
machen?" verschwenden.

Das hier

> Für mich macht im moment am meisten Sinn, der Gegenstelle
> mitzuteilen das der Buffer vollgelaufen ist und dieser die
> Option neu senden soll

ist IMHO nicht machbar :-)

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nur zu melden, daß was schiefläuft, ist keine Lösung.
Man muß dem Sender schon irgendwie mitteilen, wie er das lösen kann.

Ich hab z.B. in meinem Bootloaderprotokoll ne Funktion, mit der der 
Sender die Puffergröße abfragt und dann kann er die Daten in 
entsprechende Pakete unterteilen.
Beim ATtiny13 ist der Puffer sehr klein und beim ATmega1284 riesengroß.


Peter

Autor: Markus B. (rusticus)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Karl heinz Buchegger schrieb:
> Das war die Überlegung. Und daher bin ich der Meinung, dass eine
>
> derartige Fehlermeldung, ausser während der Entwicklungszeit der
>
> Programme, nur von beschränktem Nutzen ist (*). Die Idee "Da meldet der
>
> Empfänger bei Bufferoverflow einen Fehler und dann muss der Sender das
>
> eben anders schicken" ist IMHO sehr zweifelhaft in ihrer
>
> Durchführbarkeit.

Das sehe ich genauso, deshalb war auch die Frage nach einer sinnvollen 
Option.


Aber mir ist noch was aufgefallen und hoffe mal es stimmt:
[...]

string[i] = c
i++

} while (c != 'n' && i < l-string - 1); //Ende von do-while-Schleife
string[i] = '\0'

So steht es bei mir im Code, nun folgendes:
Sieht mein String durch die do-while-Schleife am Schluss nicht so aus 
[..][x][y][z]['\n']['0'] ??

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

Bewertung
0 lesenswert
nicht lesenswert
Markus B. schrieb:

> Das sehe ich genauso, deshalb war auch die Frage nach einer sinnvollen
> Option.

sinnvolle Option (da du ja Textübertragung in Zeilenform machst) sind 
(ohne Anspruch auf Vollständigkeit):

* Beide Partner sind sich einig, dass eine Zeile nicht länger
  als x Zeichen sein darf. Alle Kommandos, jegliche Übertragung
  mussen in 1 Zeile passen.

* Bei der Protokollerstellung ist darauf Rücksicht genommen worden,
  indem man darauf achtet, dass längere Daten in mehreren Teilen
  übertragen werden, wobei jeder Teil kleiner als der Buffer ist
  (zb ein kompletter Zeitpunkt wird übertragen indem Datum und Uhrzeit
   getrennt übertragen werden)

* Im Empfänger Aufwand getrieben wird, dass der Empfänger auch
  bisher nur teilweise übertragene Datensätze zumindest teilweise
  auswerten kann, so dass die Operation empfängerseitig in
  mehreren Schüben erfolgen kann.
  Nachteilig: Das schöne Feature "man kann eine Übertragung als
  ganzes auf Fehler untersuchen und die Änderung wird erst dann
  durchgeführt, wenn gesichert ist, das die Übertragung korrekt war"
  geht dadurch verloren bzw. ist nicht mehr so einfach möglich.
  Ausserdem kann es dann passieren, dass plötzlich das Thema Handshake
  interessant wird.

>
> [...]
> 
> string[i] = c
> i++
> 
> } while (c != 'n' && i < l-string - 1); //Ende von do-while-Schleife
> string[i] = '\0'
> 
>
> So steht es bei mir im Code, nun folgendes:
> Sieht mein String durch die do-while-Schleife am Schluss nicht so aus
> [..][x][y][z]['\n']['0'] ??

Das kommt drauf an, was sonst noch in der Schleife enthalten ist :-)

  ....

    if( c != '\n' ) {
      string[i] = c;
      i++;
    }
  } while ( c != 'n' && i < l-string - 1 );
  string[i] = '\0';

jetzt ist der '\n' nicht mehr Teil des Strings :-)

Autor: AVR-Frickler (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Eine Lösung für das Problem, mit längeren Strings vom PC zum µC mit 
kleinerem Puffer, gibt es doch schon seid einigen Jahren!

Man benötigt lediglich 2 weitere Pins am µC die man dann mit RTS/CTS 
bezeichnet. Na klingelts?

RTS = REQUEST TO SEND (Hallo ich möchte was senden!)
CTS = CLEAR TO SEND (Jupp schick rüber!)

Manche Terminals unterbrechen das senden auch wenn plötzlich CTS auf LOW 
geht, ansonsten kann man sich ja selbst nen Terminal basteln.

Autor: Klaus Wachtler (mfgkw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Markus B. schrieb:
> So steht es bei mir im Code, nun folgendes:
> Sieht mein String durch die do-while-Schleife am Schluss nicht so aus
> [..][x][y][z]['\n']['0'] ??

Nein, nicht ganz.

Es ergibt sich:
[..]['x']['y']['z']['\n']['\0']

'0' ist ein darstellbares Zeichen, das auf dem Bildschirm wie eine 
Ziffer 0 aussieht (falls der Rechner ASCII verwendet, ist es das Byte 
mit dem Wert 48 dezimal).

'\0' ist ein Byte mit dem Wert 0 und nicht darstellbar.

Autor: Klaus Wachtler (mfgkw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
AVR-Frickler schrieb im Beitrag #1841723:
> RTS = REQUEST TO SEND (Hallo ich möchte was senden!)
> CTS = CLEAR TO SEND (Jupp schick rüber!)

Das hilft hier nicht weiter, weil dann halt keine Zeichen mehr kommen.
Der Puffer wird aber nie mehr frei werden, wenn der Empfänger liest bis 
zu einem \n.

Autor: Markus B. (rusticus)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Klaus Wachtler schrieb:
> '0' ist ein darstellbares Zeichen, das auf dem Bildschirm wie eine
> Ziffer 0 aussieht (falls der Rechner ASCII verwendet, ist es das Byte
> mit dem Wert 48 dezimal).
>
> '\0' ist ein Byte mit dem Wert 0 und nicht darstellbar.

Hab nur das "\" vergessen, meinte das schon ;)

Also muss ich bei mir noch alles umstellen damit mein String auch 
richtig ankommt, da mir ja sonst ein Zeichen verloren geht

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

Bewertung
0 lesenswert
nicht lesenswert
Markus B. schrieb:

> Also muss ich bei mir noch alles umstellen damit mein String auch
> richtig ankommt, da mir ja sonst ein Zeichen verloren geht


?

Wieso "ein Zeichen verloren geht"?


Ich denke wir nähern uns schön langsam dem Punkt, wo du uns von den 
Ratespielchen entbinden solltest und dein Projekt (samt Code) einfach 
mal vorstellst.
Es ist ja nicht so, dass eine Funktion die eine Zeile über UART empfängt 
(String welcher mit einem '\n' abgeschlossen wird. Das '\n' zeigt das 
Ende der Zeile an) jetzt irgendwie komplizierte Raketentechnik wäre oder 
das noch nie jemand so etwas gemacht hätte. Dafür, dass so etwas 
eigentlich eine eher triviale Fleißaufgabe für einen engagierten Amateur 
ist, dauert das nämlich jetzt schon zu lange.

Autor: Markus B. (rusticus)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
MIr gehts ein Zeichen verloren weil ich es nicht für die eigentlich 
Nachricht nutzen kann?! So war das gemeint, ich habe ein Zeichen im 
String das ich gar nicht will

Und mal so zur Vorstellung

Ich will eigentlich nur ein VB.net-Programm (nicht meine Idee) mit 
meinen µC kommunzieren lassen und mithilfe des Programms Ports ein und 
ausschalten und die Eingänge auslesen

Und jetzt bin ich in Version 2 meiner Hardware (nun gelayoutet, vorher 
nur Lochraster) und wollte wegen des neuen Prozessers (AT90CAN128 statt 
ATMega16) einfach ein paa Sachen besser machen und stoße halt jetzt 
wieder an meine Grenzen, da ich wie gesagt schon ewig nicht mehr hab und 
wohl auch noch nie der Guru war. Ich arbeite mich aber gern in ein Thema 
ein und such mir immer alles was ich brauch anstatt das ich mal 
prinzipiell ein Buch les wo ich dann schon 80% kenn. Davon mag jeder 
halten was er will, hatte halt nie einen "lehrer".


Und vorgestellt hab ich deshalb einfach nichts, weils nicht relevant war 
für mich, ich halte das für keine große Errungenschaft wenn ich mir die 
anderen Sachen hier so anschaue

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

Bewertung
0 lesenswert
nicht lesenswert
Markus B. schrieb:
> MIr gehts ein Zeichen verloren weil ich es nicht für die eigentlich
> Nachricht nutzen kann?! So war das gemeint, ich habe ein Zeichen im
> String das ich gar nicht will

Na ja.
Bleiben ja noch jede Menge andere aus denen man den Text zusammensetzen 
kann.
Das <Return> zur Kennzeichnung eines Zeilenendes benutzt wird, ist 
eigentlich seit was weiß ich wievielen Jahren üblich auch wenn es 
natrülich nicht unbedingt so sein muss.

Hmm.
Wenn du von einem Programm aus wegschickst, wäre es unter Umständen 
tatsächlichj sogar geschickter ein anderes Zeichen zu benutzen. ; wird 
auch ganz gerne genommen.
Das Problem mit \n ist immer das man aufpassen muss, ob ein Return jetzt 
nur ein Return ist oder ob da auch noch ein LineFeed mit dazukommt.

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

Bewertung
0 lesenswert
nicht lesenswert
Markus B. schrieb:

> wohl auch noch nie der Guru war. Ich arbeite mich aber gern in ein Thema
> ein und such mir immer alles was ich brauch anstatt das ich mal
> prinzipiell ein Buch les wo ich dann schon 80% kenn.

Schwerer Fehler.
Du wirst ewig auf Halbwissen sitzen bleiben und dich über seltsame Dinge 
wundern, weil dir der Blick fürs Ganze fehlt.

Und die 80% :-)
Über die reden wir ein anderes mal. zb wenn du ein Buch zur Hand nimmst 
und feststellst, dass es neben den 5 Kapiteln die du so leidlich intus 
hats, noch 15 andere gibt, von denen du noch nicht einmal gehört hast, 
das es sie gibt :-)

Autor: Markus B. (rusticus)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Karl heinz Buchegger schrieb:
> Schwerer Fehler.
> Du wirst ewig auf Halbwissen sitzen bleiben und dich über seltsame Dinge
> wundern, weil dir der Blick fürs Ganze fehlt.
>
> Und die 80% :-)
> Über die reden wir ein anderes mal. zb wenn du ein Buch zur Hand nimmst
> und feststellst, dass es neben den 5 Kapiteln die du so leidlich intus
> hats, noch 15 andere gibt, von denen du noch nicht einmal gehört hast,
> das es sie gibt :-)

Da muss ich dir schon recht geben, aber im moment mache ich das in der 
Arbeit (bin Lehrling) und zwar selbstständig. Dort kann ich mich nicht 
reinhocken und ein Buch lesen ;) Somit les ich was ich lesen kann. 
Privat hab ich mehrere C-Bücher und auch BÜcher für Elektronik wie zB 
"Das große 51er Anwendungsbuch". Wie gesagt ich erarbeite mir im moment 
vieles selbst und da kann schon mal ein Denkfehler reinkommen, dann bin 
ich froh wenn es so Leute wie dich gibt, die hier fleisig antworten!

Danke mal so am Rande ;)

Von daher lass ich mir gern weiterhelfen, kann aber nicht alles so 
preisgeben weil ich nicht weiß wie meine Firma darüber denkt. Aber ich 
denke der C-Code und die Tatsache das ich mit einem VB.net-Programm 
kommunziere ist keine Kunst.
Ich nutze übrigens das NewLine weil es in VB eine nette Funktion gibt 
die sich "WriteLine" nennt und ich somit nur noch meine Daten eingeben 
muss und der Rest zuverlässigt erledigt wird.




So und nun zum Abschluss ein neues Problem


Als ich heute getestet habe, ging alles Einwandfrei bis zu eine 
Stringlänge von 7 Zeichen (dazu kommt dann noch das \n)

Meine uart_get_line-Funktion ist noch die selbe wie in der angehängten 
Datei. Aufrufparameter war "uart_get_line(Eing, 10)", übergeben wird 
"char Eing[10]". Für mich wären 8 Zeichen logisch, da ja das \n noch mit 
in den String übernohmen wird, aber 7 versteh ich im moment nicht
Ich glaub ich hab leider im moment nicht den aktuellen Quellcode bei 
mir, wie gesagt, Arbeitsprojekt

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

Bewertung
0 lesenswert
nicht lesenswert
Markus B. schrieb:

> Von daher lass ich mir gern weiterhelfen, kann aber nicht alles so
> preisgeben weil ich nicht weiß wie meine Firma darüber denkt. Aber ich
> denke der C-Code und die Tatsache das ich mit einem VB.net-Programm
> kommunziere ist keine Kunst.

:-)

> Ich nutze übrigens das NewLine weil es in VB eine nette Funktion gibt
> die sich "WriteLine" nennt und ich somit nur noch meine Daten eingeben
> muss und der Rest zuverlässigt erledigt wird.

OK. Kein Problem


> Meine uart_get_line-Funktion ist noch die selbe wie in der angehängten
> Datei. Aufrufparameter war "uart_get_line(Eing, 10)", übergeben wird
> "char Eing[10]".

Schreibs besser so
  uart_get_line( Eing, sizeof( Eing ) );

dann brauchst du nicht zählen, bzw. kannst nicht vergessen die Zahl 
höher zu setzen, wenn Eing mal länger wird. Solche wichtige magischen 
Zahlen überlässt man besser dem Compiler. Der übersieht nichts und macht 
keine Fehler.

> Für mich wären 8 Zeichen logisch, da ja das \n noch mit
> in den String übernohmen wird, aber 7 versteh ich im moment nicht

Ohne aktuellen Quellcode schwer zu sagen
Die Frage ist zb auch, ob sich da irgendwo ein versteckter Newline 
('\r') eingeschlichen hat.

Du kannst aber auch mal das hier machen:
int main (void) {

  DDRA = 0x00;
  DDRC = 0xFF;
  DDRD = 0x0F;
  DDRE = 0xC1;

  int input = 0;
  int Pc_ready = 0;
  char Eing[10];
  char dummy[20];

  uart_init ( UART_BAUD_SELECT (UART_BAUD_RATE, F_CPU) );
  sei();

  while( 1 )
  {

    while( Pc_ready == 0 )
    {
      uart_puts( "READY" );
      _delay_ms( 10 );
      uart_get_line( Eing, sizeof(Eing) );

      uart_puts( "Anzahl Zeichen: " );
      itoa( strlen( Eing ), dummy, 10 );
      uart_puts( dummy );
      uart_puts( "\r\nGelesen wurde: #" );
      uart_puts( Eing );
      uart_puts( "#\r\n" );
    }

    input = PINA;
  }
} 

mit anderen Worten:
Du hast eine UART zur Verfügung. Benutze sie, damit dir das Programm 
mitteilt, was es gelesen hat, wieviele Buchstaben etc.
Den Text in Eing lass ich mir bei der Ausgabe in # einschliessen. Damit 
kann ich an der Ausgabe im Terminal sehen, ob sich irgendwo ein 
Leerzeichen zuviel oder ein '\n' eingeschlichen hat, der nicht da sein 
sollte.

Edit:
Ach ja.
Du benutzt doch für erste Teste ein Terminalprogramm und schickst 
händisch Zeichen rüber und machst das nicht gleich von einem VB Programm 
aus?

Autor: Klaus Wachtler (mfgkw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Markus B. schrieb:
> Meine uart_get_line-Funktion ist noch die selbe
...

Bestimmt nicht.
Quellcode, oder Schläge!

Ach ja: KHB hat zu 99.7% recht, aber laß dich nicht verunsichern.
Natürlich musst du viel lesen, aber selber machen hilft auch weiter.
Beides muß sein.

Autor: Klaus Wachtler (mfgkw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Übergehe doch einfach das Eintragen von \n in deinen String beim
Empfangen, wenn es dich stört.

Ein kleines if, und fertig.

Autor: Markus B. (rusticus)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Karl heinz Buchegger schrieb:
> Edit:
> Ach ja.
> Du benutzt doch für erste Teste ein Terminalprogramm und schickst
> händisch Zeichen rüber und machst das nicht gleich von einem VB Programm
> aus?

Ich benutze im moment bereits ein eigenes VB-Programm zum testen da ich 
so eben meine 7 Zeichen gleichzeitig rüber bekomm und sicher weiß was 
dort gesendet wird, wie gesagt, ist ja meine 2te Version und Version 1 
geht nach wie vor tadellos ;)

Und ich lass mir dort eben sofort das gesendete "Eing[10]" sofort wieder 
zurückschicken, von daher hab ich das eben rausbekommen das ab 8 Zeichen 
der Spuck beginnt, da bis 7 alles genau so zurückkommt wie es soll

Klaus Wachtler schrieb:
> Übergehe doch einfach das Eintragen von \n in deinen String beim
> Empfangen, wenn es dich stört.
>
> Ein kleines if, und fertig.

Naja ich wollte jetzt meine Funktion umschreiben da ich persönlich mit 
dem do-while nicht so zufrieden bin, da ich zB bei einem nicht-empfangen 
ein "break" einbaun musste damit meine Funktion nicht blockt. Ich denke 
im moment sehr über eine rekursive Funktion nach, hab aber ein bischen 
Angst mich total zu überfordern^^ Von daher erst mal nochmal mit ner 
For-Schleife oder einer normalen while probieren, wär mir fast lieber

Autor: Klaus Wachtler (mfgkw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Rekursief gehts meistens schief... :-)

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

Bewertung
0 lesenswert
nicht lesenswert
Karl heinz Buchegger schrieb:

>> Weil ein übergelaufenes Array gibt mir doch sicher nicht die richtige
>> Anzahl der Zeichen zurück oder?
>
> Wenn dir das Array überläuft, dann ist das schlecht. Sehr schlecht
> http://www.mikrocontroller.net/articles/FAQ#Beispiele_2
>

Weil es so schön reinpasst, was Pufferüberläufe alles bewirken können:

http://www.heise.de/newsticker/meldung/Source-Code...
Im Descriptor signalisiert ein USB-Gerät beispielsweise, wieviele
Anschlüsse es besitzt und ob es eine externe Stromversorgung enthält.
Auf sehr lange Descriptoren reagiert die PS3 allerdings mit 
Pufferüberläufen, womit sich Code auf den Stack der PS3 schleusen und
starten lässt. 

Um das Kopierschutzsystem zu überwinden, geht der simulierte USB-Hub in
mehreren Schritten vor und gaukelt der PS3 den Anschluss verschiedener
Geräte in einer bestimmten Reihenfolge vor – wobei er mehrere
Pufferüberläufe provoziert, um unterschiedliche Daten und Code auf den
Stack zu schreiben. Im letzten Schritt wird der gesamte Code ausgeführt.

(Das es sowas noch gibt. Mitlerweile sollte doch nun wirklich jeder 
C-Entwickler wissen, dass man externe Kanäle, über die Daten reinkommen 
grundsätzlich immer auf potentiellen Pufferüberlauf überwacht)

Autor: Klaus Wachtler (mfgkw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@KHB: Du malst wieder in den leuchtendsten Farben schwarz!!

So einfach geht es auf einem AVR doch gar nicht, dank 
Harvard-Architektur.
Auch wenn ich sie sonst hasse wie die Pest, hier ist sie im Vorteil.

Autor: Rufus Τ. Firefly (rufus) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
AVR-Frickler schrieb im Beitrag #1841723:
> RTS = REQUEST TO SEND (Hallo ich möchte was senden!)
> CTS = CLEAR TO SEND (Jupp schick rüber!)

Das ist zwar schön wörtlich übersetzt, aber nicht korrekt.

RTS ist ein Eingang am sendenden Controller, an den wird der 
CTS-Ausgang des empfangenden Controllers angeschlossen.

Eine Anfrage à la "Hallo ich möchte was senden" gibt es nicht, es gibt 
nur als Signalausgang die Freigabe für die sendende Gegenstelle.

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

Bewertung
0 lesenswert
nicht lesenswert
Klaus Wachtler schrieb:
> @KHB: Du malst wieder in den leuchtendsten Farben schwarz!!

LOL
Ich mal überhaupt nicht schwarz.
Das wird tatsächlich gemacht. Damit wird die Sony PSP3 geknackt :-)

> So einfach geht es auf einem AVR doch gar nicht, dank
> Harvard-Architektur.
> Auch wenn ich sie sonst hasse wie die Pest, hier ist sie im Vorteil.

Du sprichst mir aus der Seele.

OK. Du hast natürlich recht, so einfach ist es auf einem AVR dann auch 
wieder nicht. Aber auch auf einem AVR ist ein zerschossener Stack immer 
wieder für Überraschungen gut.

Und ich will auch gar nicht wissen, wie lange diese Typen gebraucht 
haben um den USB-Descriptor so hinzutricksen, dass sie über den Stack 
Code injezieren konnten. Und das über 6 Stufen - mir wird schwindlig :-)

Autor: Klaus Wachtler (mfgkw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Du hast natürlich Recht damit, daß es ein ernstes Problem ist - das will 
ich gar nicht absprechen.
Mit Schwarzmalen hast du hier zumindest auf jeden Fall recht, keine 
Frage.

Nur das Beispiel, so Code unterzuschieben, passt nicht zum AVR.

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Karl heinz Buchegger schrieb:
> wobei er mehrere
> Pufferüberläufe provoziert, um unterschiedliche Daten und Code auf den
> Stack zu schreiben. Im letzten Schritt wird der gesamte Code ausgeführt.

Ich hätte jetzt eigentlich erwartet, daß moderne CPU ne Memory 
Protection Unit haben und dann das OS die Rechte klar vorgibt:
- hier ist Code, den darfst Du nur ausführen, aber nicht lesen oder 
schreiben
- hier sind konstante Daten, die sind nur lesbar
- hier sind Daten, die sind lesbar und schreibbar, aber nicht 
ausführbar.

Der Ausführungsversuch im Stack sollte also nur ne Exception 
verursachen.


Peter

Autor: Klaus Wachtler (mfgkw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
naja, sollte.

Du solltest in der Ortschaft auch nur 50 fahren.

Autor: Rolf Magnus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Peter Dannegger schrieb:

> Ich hätte jetzt eigentlich erwartet, daß moderne CPU ne Memory
> Protection Unit haben und dann das OS die Rechte klar vorgibt:
> - hier ist Code, den darfst Du nur ausführen, aber nicht lesen oder
> schreiben
> - hier sind konstante Daten, die sind nur lesbar
> - hier sind Daten, die sind lesbar und schreibbar, aber nicht
> ausführbar.

Das gab es eigentlich schon beim 286er. Man definiert dort für Code, 
Daten und Stack separate Segmente, und dann gibt es entsprechende 
Berechtigungen. Aber alle modernen Betriebssysteme legen diese 3 
Segmente deckungsgleich übereinander, so daß dieses Berechtigungssystem 
nicht funktioniert. Das ist der Preis, den man gezahlt hat, um jedem 
Prozess einen einzelnen linearen Adressraum zur Verfügung stellen zu 
können.
Auf modernen Prozessoren gibt's deshalb noch eine weitere Möglichkeit 
auf Basis einzelner Speicherseiten. Siehe:
http://de.wikipedia.org/wiki/NX-Bit

> Der Ausführungsversuch im Stack sollte also nur ne Exception
> verursachen.

Das ist nicht ganz so einfach. Teilweise wird von Compilern Code 
generiert, der zur Laufzeit auf den Stack gelegt und dort ausgeführt 
werden soll, ganz legitim.

Autor: Markus B. (rusticus)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich hab an dem Code mal weitergearbeitet und mich dann auch mal 
zwangsläufg mit dem "sizeof" bechäftigt und bin dann auf folgendes 
gestoßen:
http://www.imb-jena.de/~gmueller/kurse/c_c++/c_sizeof.html

Somit habe ich ja beim aufruf meiner Funktion:
uart_get_line(string, sizeof(string));
die doppelte Anzahl an Zeichen für die länge des Strings übergeben wie 
ich brauche, sehe ich das richtig?
Ich wollte mir nämlich die sizeof meines strings IN der Funktion 
zurückgeben lassen und habe mich gewundert warum ich immer eine "2" 
erhalten habe.

Das wär meine ganze Funktion, ich habe versucht den Fehlerfall eines 
überlaufs zu erkennen indem ich überprüfe ob noch Zeichen vorhanden 
wären, wenn der String die maximale Länge erreicht hat. Das wird mit 
Fehlermeldungen quittiert, die weit jenseits normaler String-Längen 
liegen.
Der String gibt mir dann zusätzlich noch die richtige Länge des Strings 
an, zumindest theoretisch, denn das funktioniert noch nicht richtig.


Vlt kann mal wer drüber schaun ob er den Fehler findet oder was man 
C-Technisch noch verbessern kann/sollte.


mfg Rusticus

int uart_get_line ( char *string, size_t l_string )
{
//Variablen deklariern
int c;
int i = 0;

        c = uart_getc();
    
        if ( c & UART_NO_DATA )
        {
            /* 
             * no data available from UART 
             */
        }
        else
        {
            /*
             * new data available from UART
             * check for Frame or Overrun error
             */
            if ( c & UART_FRAME_ERROR )
            {
                /* Framing Error detected, i.e no stop bit detected */
                uart_puts_P("UART Frame Error: 300");
        return 300;
            }
            if ( c & UART_OVERRUN_ERROR )
            {
                /* 
                 * Overrun, a character already present in the UART UDR register was 
                 * not read by the interrupt handler before the next character arrived,
                 * one or more received characters have been dropped
                 */
                uart_puts_P("UART Overrun Error: 400");
        return 400;
            }
            if ( c & UART_BUFFER_OVERFLOW )
            {
                /* 
                 * We are not reading the receive buffer fast enough,
                 * one or more received character have been dropped 
                 */
                uart_puts_P("Buffer overflow error: 500");
        return 500;
            }
      
      while ( c != '\n' && i < (l_string - 1) )
      {
        string[i] = c;
        i++;
        c = uart_getc();
        
        if ( c & UART_FRAME_ERROR )
        {
          /* Framing Error detected, i.e no stop bit detected */
          uart_puts_P("UART Frame Error: 300");
          return 300;
        }
        if ( c & UART_OVERRUN_ERROR )
        {
          /* 
          * Overrun, a character already present in the UART UDR register was 
          * not read by the interrupt handler before the next character arrived,
          * one or more received characters have been dropped
          */
          uart_puts_P("UART Overrun Error: 400");
          return 400;
        }
        if ( c & UART_BUFFER_OVERFLOW )
        {
          /* 
          * We are not reading the receive buffer fast enough,
          * one or more received character have been dropped 
          */
          uart_puts_P("Buffer overflow error: 500");
          return 500;
        }
        
      }    //while-Ende

        } //Else-Ende

  string[i] = '\0';  //Terminierung
  
  if (sizeof(string) == l_string)
  {
  c = uart_getc();
    if( c & UART_NO_DATA )
    {
    return 800;
    }
  
  }
  
  return sizeof(string);

}  //Funktion-Ende

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

Bewertung
0 lesenswert
nicht lesenswert
Markus B. schrieb:
> Ich hab an dem Code mal weitergearbeitet und mich dann auch mal
> zwangsläufg mit dem "sizeof" bechäftigt und bin dann auf folgendes
> gestoßen:
> http://www.imb-jena.de/~gmueller/kurse/c_c++/c_sizeof.html
>
> Somit habe ich ja beim aufruf meiner Funktion:
> uart_get_line(string, sizeof(string));
> die doppelte Anzahl an Zeichen für die länge des Strings übergeben wie
> ich brauche, sehe ich das richtig?

Das siehst du falsch.

Mittels sizeof weist man den Compiler an, den Speicherbedarf einer 
Variablen zu ermitteln.

Ein int wird in 2 Bytes abgelegt. Daher ist sizeof(int) gleich 2.
Eine char Variable benötigt nur 1 Byte im Speicher. Daher ist 
sizeof(char) gleich 1.

> Ich wollte mir nämlich die sizeof meines strings IN der Funktion
> zurückgeben lassen und habe mich gewundert warum ich immer eine "2"
> erhalten habe.

weil auf deinem System eine Adresse (also ein Pointer) 2 Bytes belegt, 
also ist der sizeof eines Pointers gleich 2.

sizeof ist etwas was vom Compiler ausgewertet wird und nicht zur 
Laufzeit! Wenn du zur Laufzeit wissen willst, wie lange ein String 
tatsächlich ist, dann musst du strlen benutzen.

Oder aber bei dir: da du in i ja sowieso mitzählst, wieviele Zeichen du 
bereits in den String gepackt hast, steht in i schon die Information die 
du haben willst. Möglicherweise musst du sie noch um 1 korrigieren, weil 
i um 1 zu weit gezählt hat, aber dem Prinzip nach hast du die Länge des 
tatsächlichen Strings (also die Anzahl der Zeichen im Array) in i 
vorliegen. Du musst da nichts künsteln.

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

Bewertung
0 lesenswert
nicht lesenswert
PS: Deine Funktion ist Müll

Lass fürs erste mal die ganze Fehlerbehandlung mit UART_FRAME_ERROR, 
UART_OVERRUN_ERROR und UART_BUFFER_OVERFLOW weg. Das zieht dir momentan 
den Code noch zu sehr in die Länge, so dass du den Überblick verlierst.

Rück den Code sauber an, sieh zu, dass du den Fall UART_NO_DATA korrekt 
behandelst und bring das erst mal zum laufen.

Autor: Hc Zimmerer (mizch)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Der Code ist auch ein Musterbeispiel dafür, dass man statt
tuwas;
while (Bedingung) {
  tuwas;
}
besser
do {
  tuwas;
} while (Bedingung)
schreibt.

Das bedingte Schleifenkonstrukt, das seinen Körper mindestens einmal 
ausführt, ist erfunden.  Es gibt keinen Grund, den Körper zweimal 
hinzuschreiben und beim zweiten Mal die Schleife 0- oder mehrmals 
auszuführen.

Autor: Markus B. (rusticus)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich versteh nicht ganz warum meine Funktion Müll ist, wenn ich den 
Returnwert mal außer Acht lasse, funktioniert die Funktion, ich empfange 
einwandfrei meine Zeichen und den String

Ich hab doch dafür die Else anweisung? Ok der Schluss ist nicht optimal 
und manche Leute mögen die "do-while-Schleife" bevorzugen, von der ich 
extra weg bin, aber funktionieren tuts trotzdem!

Also wieso ist das Müll? Ein bischen detailiertere Angaben würden mir 
mehr helfen :)

mfg

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

Bewertung
0 lesenswert
nicht lesenswert
weil du zb innerhalb der while Schleife den Fall UART_NO_DATA gar nicht 
mehr behandelst. Wenn deien UART nicht mehr mitgekommen ist und auf 
Zeichen warten muss, bis dann endlich der erlösende '\n' kommt, hast du 
dir den Buffer schon längst mit ungültigen Daten vollgemüllt.

Wie gesagt: Wirf alle Fehlerbehandlungen ausser UART_NO_DATA raus und 
sieh erst mal zu, dass du in diesem Fall eine saubere Behandlung 
bekommst. Dann wirst du auch solche Unlogikeiten sehen. Die Funktion ist 
noch zu lang als dass du sie überblicken könntest. Du hast dich zu 
schnell auf Details wie Fehlerbehandlung geworfen.
Eine gute Strategie ist es bei mir immer:
Zuerst mach ich die Funktion ohne mich groß um Fehlerfälle zu kümmern. 
Das hat den Vorteil, dass ich mich nur auf den zugrundeliegenden 
Algorithmus konzentrieren kann und mich nicht mit Nebenschauplätzen 
aufhalten muss.
Wenn ich das fertig habe, dann geh ich den Code durch und schau mir an: 
Was kann mir wo an Fehlerfällen auftauchen. Und dann bau ich diese 
Behandlung noch zusätzlich ein.
Aber zuerst steht das nackte Verfahren, bei dem angenommen wird: es gibt 
keine gravierenden Fehler.

Beim uart_getc musst du immer damit rechnen, dass es UART_NO_DATA 
liefert. Das ist in diesem Sinne nicht wirklich ein Fehler. Den Fall 
berücksichtige ich daher sofort in der Erstversion. Die anderen 
Returncodes sind aber echte Fehler. Die lass ich in der Erstversion erst 
mal links liegen.

Autor: Markus B. (rusticus)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
OK dann bau ich mal meine funktion um und versuche das so zu machen

Die Variante ohne Fehlerbehanldung und co hatte ich bereits schon und 
ging ja, deshalb hab ich diese Version probiert

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

Bewertung
0 lesenswert
nicht lesenswert
Markus B. schrieb:
> OK dann bau ich mal meine funktion um und versuche das so zu machen

Lösch einfach die Benannten Fehlerbehandlungsteile raus. Dann müsste man 
schon sehen, wovon ich spreche.
Nicht einfach auskommentieren. Ziel ist es den Code der ganzen Funktion 
auf eine Bildschirmseite zu bringen.

Sauber einrücken!

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.