www.mikrocontroller.net

Forum: Compiler & IDEs UART empangen


Autor: Doran S. (utzer)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

ich bin neu hier und das ist mein erster Beitrag.
Ich habe ein Problem mit dem UART, ich habe auch die Suchfunktion 
benutz, habe allerdings keine Lösung gefunden. Es geht un UART.
Das Senden funktioniert schon ganz gut, allerdings klappt das Empfangen 
nicht. Ich habe auch schon in Tutorial nachgeschaut, allerdings half mir 
das auch nicht weiter.
Ich verwende den Mega32.
Ich habe nun schon alles durchsucht, allerdings ist mir mein Fehler 
nicht aufgefallen.
Ziel dieses Programms ist es, zu erst "Test" auszugeben und da nach 4, 
von Benutzer eingegebenen, Zeichen gleich darauf auch auszugeben. Es 
handelt sich natürlich nur um einen Test, denn dies ist mein erstes 
UART-Projekt.

Über Antworten würde ichmich sehr freuen.

Mit Bestem Dank

utzer

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

Bewertung
0 lesenswert
nicht lesenswert
In deinem Programm sind ein paar klassische Fehler enthalten.
Bitte besorg dir Literatur zum Thema C-Programmierung.
So wie du dir das vorstellst, funktioniert
* Stringverarbeitung in C nicht
* das Handling von lokalen Variablen / Funktionsparametern nicht

Kurz:
Du brauchst ein Array um Zeichen speichern zu können. Eine 
Speicherfläche!
Ein Zeiger kann auf so eine Speicherfläche verweisen, aber er ist es 
selber nicht.

Fang erst mal mit kleineren Brötchen an.
1 Zeichen empfangen und zurückschicken. Und erst dann gehst du daran 
einen kompletten String zu empfangen, den du in einem Array 
zwischenspeicherst.

Autor: Doran S. (utzer)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

danke für Deine Antwort. Ich habe es nun auch geschaft, einzelne Zeichen 
zu senden. Was eine Array ist habe ich nun auch verstanden, allerdings 
verstehe ich das mit dem Zeiger(Pointer) noch nicht. Könnte mir das 
vielleicht jemand in "einfachen Worten" erklären?

mfg

utzer

PS: Bitte entschuldigt die späte Antwort, aber ich bin Schüler(15) und 
hab viel um die Ohren.

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

Bewertung
0 lesenswert
nicht lesenswert
Ein Pointer (Zeiger) ist eine Variable wie jede andere auch. Ihr Inhalt 
ist eine Speicheradresse.

Ein int ist eine Variable, welche eine ganze Zahl enthält
Ein double ist eine Variable, welche eine Gleitkommazahl enthält
EIn Pointer ist eine Variable, welche eine Speicheradresse enthält.

Das ist im Grunde schon fast alles :-)

Allerdings muss man in C immer auch dazu sagen: Wenn ein Pointer eine 
Speicheradresse enthält, was finde ich dann genau an dieser Stelle im 
Speicher vor.
Wenn ich also einen int-Pointer habe

  int* PtrA;

dann enthält PtrA eine Adresse im Speicher. Schau ich genau an dieser 
Stelle im Speicher nach, dann finde ich dort einen int vor. Ein double 
Pointer

  double* PtrX;

enthält dann folgerichtig eine Speicherstelle unter der ein double im 
Speicher abgelegt wurde, etc. etc.

Nun zeigt so ein Pointer nicht von alleine auf irgendeine Speicherzelle, 
sondern das muss der Programmierer erst mal festlegen. Auch wird der 
int, auf den der Pointer zeigt, nicht einfach aus dem Nichts generiert, 
sondern irgendjemand muss im Speicher erst mal Platz für so einen int 
reservieren. Auch das macht so ein Pointer nicht eigenständig.

zb so
int main()
{
  int a = 5;  // Platz für einen int wird geschaffen

  int* PtrA;  // Platz für den Pointer wird geschaffen


  PtrA = &a;  // und jetzt wird der Pointer eingerichtet. Der Inhalt des
              // Pointers ist die Speicheradresse von a
}

Oder als Grafik ausgedrückt


   PtrA                             a
   +---------+                      +----+
   |    o-------------------------->| 5  |
   +---------+                      +----+

So wie a als Inhalt den Zahlenwert 5 hat, so hat PtrA als Inhalt die 
Speicheradresse von a. Ausgedrückt durch einen Pfeil von PtrA nach a.

So ist das natürlich ein wenig witzlos, wenn man nicht mit dem Pointer 
auch arbeiten könnte. Wird der Pointer 'dereferenziert', so wird 
gedanklich dem Pfeil gefolgt und der angegebene Wert von der 
entsprechenden Speicherstelle geladen/geschrieben. Deshalb ist es auch 
notwendig, dass der verwiesene Datentyp Teil des Datentyps des Pointers 
ist ( ein int-Pointer zeigt auf einen int, ein double Pointer zeigt auf 
einen double etc.)
int main()
{
  int a = 5;  // Platz für einen int wird geschaffen

  int* PtrA;  // Platz für den Pointer wird geschaffen


  PtrA = &a;  // und jetzt wird der Pointer eingerichtet. Der Inhalt des
              // Pointers ist die Speicheradresse von a

  *PtrA = 7;  // lege die 7 dort ab, wohin der Pointer zeigt
}

   PtrA                             a
   +---------+                      +----+
   |    o-------------------------->| 7  |
   +---------+                      +----+

oder umgekehrt:
int main()
{
  int a = 5;  // Platz für einen int wird geschaffen
  int b = 0;

  int* PtrA;  // Platz für den Pointer wird geschaffen


  PtrA = &a;  // und jetzt wird der Pointer eingerichtet. Der Inhalt des
              // Pointers ist die Speicheradresse von a

  *PtrA = 7;  // lege die 7 dort ab, wohin der Pointer zeigt

  b = *Ptra;  // hole den aktuellen Wert von dort, wohin der Pointer zeigt
              // und speichere ihn in b ab
}

   PtrA                             a
   +---------+                      +----+
   |    o-------------------------->| 7  |
   +---------+                      +----+

                                    b
                                    +----+
                                    | 7  |
                                    +----+

Und jetzt kommen Arrays ins Spiel.
Arrays sind in C so halbe Datentypen. Man kann ein Array zwar definieren 
und kann auch auf einzelne Elemente eines Arrays zugreifen, aber man 
kann zb nicht ein Array an eine Funktion übergeben. Allgemeiner kann man 
sagen: Immer dann, wenn der Name eines Arrays ohne Indizierung vorkommt 
(also nur der Name alleine), dann wird anstelle des Arrays an sich, die 
Adresse des ersten Arrayelements genommen. Und diese Adresse kann man 
wiederrum an eine Funktion übergeben, wobei sie innerhalb der Funktion 
in einer Pointervariablen aufgefangen wird und zur Verfügung steht.
int main()
{
  int Werte[5];

  Werte[0] = 1;
  Werte[2] = 8;
}

Dies generiert erst mal das Array

    Werte
    +---+---+---+---+---+
    | 1 | 8 |   |   |   |
    +---+---+---+---+---+

Versucht man nun dieses Array an eine Funktion zu übergeben
int main()
{
  int Werte[5];

  Werte[0] = 1;
  Werte[2] = 8;

  foo( Werte );
}

so wird anstelle des Arrays, die Adresse des ersten Array Elements 
übergeben

    Werte
    +---+---+---+---+---+
    | 1 | 8 |   |   |   |
    +---+---+---+---+---+
      ^
      |
      |
      |

und diese Adresse wiederrum, wird von der aufgerufenen Funktion in einer 
Pointer-Variablen empfangen, die der Funktion während ihrer Ausführung 
zur Verfügung steht (und nach Beendigung der Funktion wieder 
verschwindet)
void foo( int* Passed )
{
   ...
}

int main()
{
  int Werte[5];

  Werte[0] = 1;
  Werte[2] = 8;

  foo( Werte );
}

    Werte
    +---+---+---+---+---+
    | 1 | 8 |   |   |   |
    +---+---+---+---+---+
      ^
      |               Passed
      |               +--------+
      +-------------------o    |
                      +--------+

Die Funktion kann über diesen Pointer, auf den Inhalt des Arrays 
zugreifen und auch verändern
void foo( int* Passed )
{
  int k = *Passed;
}

    Werte
    +---+---+---+---+---+
    | 1 | 8 |   |   |   |
    +---+---+---+---+---+
      ^
      |               Passed             k
      |               +--------+         +---+
      +-------------------o    |         | 1 |
                      +--------+         +---+

Oder aber auch auf irgendein anderes Arrayelement, indem sie den 
übergebenen Pointer als Anfang benutzt und einfach angibt, auf das 
wievielte Element zugegriffen werden soll.
void foo( int* Passed )
{
  int k = *Passed;

  *( Passed + 2 ) = 4;
}

    Werte
    +---+---+---+---+---+
    | 1 | 8 | 4 |   |   |
    +---+---+---+---+---+
      ^
      |               Passed             k
      |               +--------+         +---+
      +-------------------o    |         | 1 |
                      +--------+         +---+

Nun ist aber die Syntax *( Pointer + Offset ) eine ekelhafte. In C hat 
man dem Abhilfe geschaffen, indem man den Arrayzugriff mittels Index so 
definiert hat, dass

     *( Pointer + Offset )  identisch ist zu
     Pointer[ Offset ]

anstelle von *( Pointer + 3 ) = 2 kann und wird man auch oft schreiben:
void foo( int* Passed )
{
  int k = *Passed;

  *( Passed + 2 ) = 4;
  Passed[ 3 ] = 2;
}

    Werte
    +---+---+---+---+---+
    | 1 | 8 | 4 | 2 |   |
    +---+---+---+---+---+
      ^
      |               Passed             k
      |               +--------+         +---+
      +-------------------o    |         | 1 |
                      +--------+         +---+


Es gibt noch mehr über Pointer zu sagen und vor allen Dingen zu 
entdecken. Aber im Grunde folgt alles andere aus dem bisher Gesagten, 
auch wenn einem das so nicht bewusst ist. Daher: Literatur, Literatur, 
Literatur. Denn ich hab ehrlich gesagt auch keine Lust, dir hier all das 
was in einem vernünftigen Buch auf 30 oder mehr Seiten erklärt ist, in 
ein paar Positings nahezubringen.

Autor: Doran S. (utzer)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

vielen Dank für Deine Antwort, jetzt wird mir so einiges klar.....:-)
allerdings habe ich versucht, dies jetzt auf den Code zu übertragen, 
allerdings funktioniert es nicht....

void gets()
{
  char* Buffer;
  char Line[10];
  char NextChar;
  int StringLen = 0;
  Buffer = &Line;
  NextChar = getc();    // Warte auf und empfange das nächste Zeichen (in der getc-Funktion)

  while(StringLen<=4)
  {
      Buffer[StringLen] = NextChar;
      StringLen=StringLen+1;
      NextChar = getc();
  }

  StringLen=StringLen+1;
  Buffer[StringLen] = '\0';
                      // Noch ein '\0' anhängen um einen Standard
                      // C-String daraus zu machen

  return Line;  //Ich glaub hier liegt der Fehler.......:-( (Muss es "return *Buffer" heißen???)
}


Was mache ich falsch?
Ich komme einfach nicht weiter.....

mfg

utzer

Autor: Jörg G. (joergderxte)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
/* globaler Zeilenpuffer +/
char Line[10];

/* char *gets(), damit sowas:
  'int i = atoi(gets(Line, 4), 10);'
  spaeter mal geht */
char *gets(char *Buffer, int StringLen)
{
  /* static char Line[10];
     ginge auch, WENN du weisst wo der Unterschied liegt
  */
  int idx =0;
  while (idx < StringLen)
  {
    Buffer[idx] = getc();
    idx ++;
  }
  Buffer[idx] = 0; // Noch ein '\0' anhängen um einen
                   // C-String daraus zu machen
  return Buffer;
}
int main(void)
{
//...
  gets(Line, 4);
//  jetzt steht in 'Line' dein String
hth, Jörg

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

Bewertung
0 lesenswert
nicht lesenswert
Doran Strehnisch wrote:

>
> 
> void gets()
> {
>   char* Buffer;
>

Es gibt in dieser Funktion, so wie sie jetzt ist, absolut keinen Grund 
mit Pointern um sich zu schmeissen
>   char Line[10];
>
>   ....
>

>   return Line;  //Ich glaub hier liegt der Fehler.......:-( (Muss es
> "return *Buffer" heißen???)
> }
> 

Wie kann diese Funktion etwas retournieren, wenn im Funktionskopf steht, 
dass diese Funktion void ist, also nichts zurückliefern wird?

Achtung: Das ist jetzt eine falsche Lösung, komme nach dem Code gleich 
drauf zu sprechen.
char* gets()
{
  char Line[10];
  char NextChar;
  int StringLen = 0;

  NextChar = getc();    // Warte auf und empfange das nächste Zeichen (in der getc-Funktion)

  while(StringLen<=4)
  {
      Line[StringLen] = NextChar;
      StringLen=StringLen+1;
      NextChar = getc();
  }

  StringLen=StringLen+1;
  Line[StringLen] = '\0';
                      // Noch ein '\0' anhängen um einen Standard
                      // C-String daraus zu machen

  return Line;  //Ich glaub hier liegt der Fehler.......:-( (Muss es "return *Buffer" heißen???)
}

Das würde jetzt erst mal logisch aussehen.
Ds Problem. Du kannst Line nicht returnen.
Erinnere dich: lokale Variablen werden zerstört, wenn eine Funktion zu 
Ende geht. Also wird Line mit Beendigung der Funktion gets zerstört. 
Gleichzeitig können Arrays aber auch nicht kopiert werden, es wird 
lediglich die Startadresse des Arrays an den Aufrufer übergeben.
Damit hat aber der Aufrufer dann die Startadresse eines Arrays, welches 
nicht mehr existiert.

In so einem Fall, muss der Aufrufer der Funktion das Arrays 
bereitstellen und es in die Funktion hinein übergeben. Die Funktion 
befüllt es dann mit Werten.
void gets( char * Line )
{
  char NextChar;
  int StringLen = 0;

  NextChar = getc();    // Warte auf und empfange das nächste Zeichen (in der getc-Funktion)

  while(StringLen<=4)
  {
      Line[StringLen] = NextChar;
      StringLen=StringLen+1;
      NextChar = getc();
  }

  StringLen=StringLen+1;
  Line[StringLen] = '\0';
                      // Noch ein '\0' anhängen um einen Standard
                      // C-String daraus zu machen

}

int main()
{
  char Eingabezeile[10];

  gets( Eingabezeile );

  ...
}

Aufpassen muss man nur, dass das Array beim Aufrufer gross genug 
allokiert wird, damit gets nicht auf Elemente des Arrays zugreift, die 
nicht existieren.

http://www.mikrocontroller.net/articles/FAQ#Wie_fu...

Autor: Doran S. (utzer)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

vielen, vielen Dank, dass ihr euch die Mühe gemacht habt, mir das so 
genau und ausführlich zu erklären..... Es hat funktioniert - Danke :-)

über glücklich

-utzer

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.