Forum: Compiler & IDEs UART empangen


von Doran S. (utzer)


Angehängte Dateien:

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

von Karl H. (kbuchegg)


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.

von Doran S. (utzer)


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.

von Karl H. (kbuchegg)


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
1
int main()
2
{
3
  int a = 5;  // Platz für einen int wird geschaffen
4
5
  int* PtrA;  // Platz für den Pointer wird geschaffen
6
7
8
  PtrA = &a;  // und jetzt wird der Pointer eingerichtet. Der Inhalt des
9
              // Pointers ist die Speicheradresse von a
10
}

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.)
1
int main()
2
{
3
  int a = 5;  // Platz für einen int wird geschaffen
4
5
  int* PtrA;  // Platz für den Pointer wird geschaffen
6
7
8
  PtrA = &a;  // und jetzt wird der Pointer eingerichtet. Der Inhalt des
9
              // Pointers ist die Speicheradresse von a
10
11
  *PtrA = 7;  // lege die 7 dort ab, wohin der Pointer zeigt
12
}

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

oder umgekehrt:
1
int main()
2
{
3
  int a = 5;  // Platz für einen int wird geschaffen
4
  int b = 0;
5
6
  int* PtrA;  // Platz für den Pointer wird geschaffen
7
8
9
  PtrA = &a;  // und jetzt wird der Pointer eingerichtet. Der Inhalt des
10
              // Pointers ist die Speicheradresse von a
11
12
  *PtrA = 7;  // lege die 7 dort ab, wohin der Pointer zeigt
13
14
  b = *Ptra;  // hole den aktuellen Wert von dort, wohin der Pointer zeigt
15
              // und speichere ihn in b ab
16
}

   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.
1
int main()
2
{
3
  int Werte[5];
4
5
  Werte[0] = 1;
6
  Werte[2] = 8;
7
}

Dies generiert erst mal das Array

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

Versucht man nun dieses Array an eine Funktion zu übergeben
1
int main()
2
{
3
  int Werte[5];
4
5
  Werte[0] = 1;
6
  Werte[2] = 8;
7
8
  foo( Werte );
9
}

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)
1
void foo( int* Passed )
2
{
3
   ...
4
}
5
6
int main()
7
{
8
  int Werte[5];
9
10
  Werte[0] = 1;
11
  Werte[2] = 8;
12
13
  foo( Werte );
14
}

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

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

    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.
1
void foo( int* Passed )
2
{
3
  int k = *Passed;
4
5
  *( Passed + 2 ) = 4;
6
}

    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:
1
void foo( int* Passed )
2
{
3
  int k = *Passed;
4
5
  *( Passed + 2 ) = 4;
6
  Passed[ 3 ] = 2;
7
}

    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.

von Doran S. (utzer)


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....
1
void gets()
2
{
3
  char* Buffer;
4
  char Line[10];
5
  char NextChar;
6
  int StringLen = 0;
7
  Buffer = &Line;
8
  NextChar = getc();    // Warte auf und empfange das nächste Zeichen (in der getc-Funktion)
9
10
  while(StringLen<=4)
11
  {
12
      Buffer[StringLen] = NextChar;
13
      StringLen=StringLen+1;
14
      NextChar = getc();
15
  }
16
17
  StringLen=StringLen+1;
18
  Buffer[StringLen] = '\0';
19
                      // Noch ein '\0' anhängen um einen Standard
20
                      // C-String daraus zu machen
21
22
  return Line;  //Ich glaub hier liegt der Fehler.......:-( (Muss es "return *Buffer" heißen???)
23
}

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

mfg

utzer

von Jörg G. (joergderxte)


Lesenswert?

1
/* globaler Zeilenpuffer +/
2
char Line[10];
3
4
/* char *gets(), damit sowas:
5
  'int i = atoi(gets(Line, 4), 10);'
6
  spaeter mal geht */
7
char *gets(char *Buffer, int StringLen)
8
{
9
  /* static char Line[10];
10
     ginge auch, WENN du weisst wo der Unterschied liegt
11
  */
12
  int idx =0;
13
  while (idx < StringLen)
14
  {
15
    Buffer[idx] = getc();
16
    idx ++;
17
  }
18
  Buffer[idx] = 0; // Noch ein '\0' anhängen um einen
19
                   // C-String daraus zu machen
20
  return Buffer;
21
}
22
int main(void)
23
{
24
//...
25
  gets(Line, 4);
26
//  jetzt steht in 'Line' dein String
hth, Jörg

von Karl H. (kbuchegg)


Lesenswert?

Doran Strehnisch wrote:

>
1
> 
2
> void gets()
3
> {
4
>   char* Buffer;
5
>

Es gibt in dieser Funktion, so wie sie jetzt ist, absolut keinen Grund 
mit Pointern um sich zu schmeissen
1
>   char Line[10];
2
>
3
>   ....
4
>
5
6
>   return Line;  //Ich glaub hier liegt der Fehler.......:-( (Muss es
7
> "return *Buffer" heißen???)
8
> }
9
>

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.
1
char* gets()
2
{
3
  char Line[10];
4
  char NextChar;
5
  int StringLen = 0;
6
7
  NextChar = getc();    // Warte auf und empfange das nächste Zeichen (in der getc-Funktion)
8
9
  while(StringLen<=4)
10
  {
11
      Line[StringLen] = NextChar;
12
      StringLen=StringLen+1;
13
      NextChar = getc();
14
  }
15
16
  StringLen=StringLen+1;
17
  Line[StringLen] = '\0';
18
                      // Noch ein '\0' anhängen um einen Standard
19
                      // C-String daraus zu machen
20
21
  return Line;  //Ich glaub hier liegt der Fehler.......:-( (Muss es "return *Buffer" heißen???)
22
}

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.
1
void gets( char * Line )
2
{
3
  char NextChar;
4
  int StringLen = 0;
5
6
  NextChar = getc();    // Warte auf und empfange das nächste Zeichen (in der getc-Funktion)
7
8
  while(StringLen<=4)
9
  {
10
      Line[StringLen] = NextChar;
11
      StringLen=StringLen+1;
12
      NextChar = getc();
13
  }
14
15
  StringLen=StringLen+1;
16
  Line[StringLen] = '\0';
17
                      // Noch ein '\0' anhängen um einen Standard
18
                      // C-String daraus zu machen
19
20
}
21
22
int main()
23
{
24
  char Eingabezeile[10];
25
26
  gets( Eingabezeile );
27
28
  ...
29
}

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_funktioniert_String-Verarbeitung_in_C.3F

von Doran S. (utzer)


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

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.