Forum: Mikrocontroller und Digitale Elektronik Probleme mit Pointerübergabe und CC2500


von C. H. (hedie)


Lesenswert?

Hallo zusammen

Erstmals, ich weiss etwas merkwürdiger Titel, aber ich wusste nicht was 
ich da schreiben könnte.

Folgendes Szenario.

Ich habe hier zwei Funkmodule vom Typ CC2500
Angesprochen werden diese von einem Atmega48
Den Treiber dafür habe ich selbst geschrieben mit Codestücken aus den Ti 
Simpiciti sourcen.

Was funktioniert:
- Initialisierung, problemlos
- Register ein und auslesen, problemlos
- Übertragen undefinierter Daten, problemlos reproduzierbar (dazu komme 
ich später)

Was nicht funktioniert:
- Übertragung definierter Daten


Also, meine Transmit Funktion erwartet einen Pointer auf ein Struct mit 
den zu sendenden Daten.
Das erste Byte im Frame gibt an, wie lange das Frame selbst ist.

Hier das Struct:
1
typedef struct
2
{
3
  unsigned char frame[MRFD_MAX_FRAME_SIZE]; // MAX Wert ist 20
4
  unsigned char crc[MRFD_ADDITION_SIZE];    //CRC Byte
5
} mrfdPacket_t;


Hier mein Code-schnippsel zum senden:
1
mrfdPacket_t *myPacket;
2
3
  myPacket->frame[0] = 10;  //Testbefüllung
4
  myPacket->frame[1] = 0xBB;
5
  myPacket->frame[2] = 0xCC;
6
7
  LED3_1; //Power LED
8
  while(1)
9
  {
10
11
    if(Taster)
12
    {
13
      LED1_1;
14
      MRFD_TransmitPacket(&myPacket[0]); //Hier weiss ich nicht wie man es korrekt übergibt
15
      LED1_0;
16
      while(Taster);
17
    }
18
}

Wenn ich nun folgendes schreibe,

1
MRFD_TransmitPacket(&myPacket);
Kommen wirre Zeichen an, genauergesagt diese folge:
1
0x19,0xC5,0xFF,0x02,0x02,0x00,0x18,0x34,0x57,0x69,0x6C,0x6C,0x6B,0x6F,0x6D,0x6D,0x65,0x6E,0x20,0x62,0x65,0x69,0x6D,0x20,0x4D,0x52,
Dies habe ich in der Transmit funktion also nach der Übergabe 
abgefangen.

Diese Bytes werden sofort übertragen und kommen Fehlerfrei beim 
Empfangsmodul an.
Haben jedoch nichts mit meinem eigentlichen Frame zu tun.


Wenn ich jedoch folgendes Programmiere
1
MRFD_TransmitPacket(&myPacket[0]);
Kommen wirklich meine Bytes an die Funktion.
1
 0x19,0xBB,0xCC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00

Jedoch kommt nun nichts mehr an der gegenseite an.
Pin GDO0 des CC2500 Moduls bleibt high (high->low = Präambel erkannt = 
neues Paket)

Ich verstehe das ganze nicht.

Was ist hier der unterschied?

Die von mir gposteten Daten sind wirklich 1:1 jene welche in den TX FIFO 
des Modules geschrieben werden.

Hoffe jemand hat eine IDEE

von Karl H. (kbuchegg)


Lesenswert?

Claudio Hediger schrieb:

> Hier mein Code-schnippsel zum senden:
>
> mrfdPacket_t *myPacket;
>
>   myPacket->frame[0] = 10;  //Testbefüllung
>   myPacket->frame[1] = 0xBB;
>   myPacket->frame[2] = 0xCC;

Das ist zu wenig.

Wenn du einen Pointer hast, musst du dich IMMER sofort fragen: Wo ist 
der Speicher, auf den der Pointer zeigt.

Und bei dir zeigt er, ähm, nirgendwohin.
D.h. du hast gar keinen Speicher, in dem du Werte ablegen könntest.
(d.h. natürlich hast du Speicher. Der Speicher liegt immer nur einfach 
so rum. Aber er gehört nicht zu einem mrfdPacket_t Objekt. De Fakto 
bügelst du mit deinen Zuweisungen irgendwas anderes im Speicher nieder, 
was halt zufällig dort im Speicher stand, wo der Pointer hinzeigte. Denn 
natürlich hat auch der einen Wert. Keinen definierten, aber er hat 
einen)


Du bist da auf etwas hineingefallen:
Nur weil eine Funktion einen Pointer haben will, bedeutet das nicht 
automatisch, dass der Aufrufer auch einen Pointer haben muss.

Gedacht ist die Verwendung dieser Funktion so:
1
   mrfdPacket_t   dasPacket;    // ein tatsächliches Objekt.
2
                                // nicht nur ein Pointer auf so eines!
3
4
   dasPacket.frame[0] = 10;     // geht natürlich. Denn dasPacket ist
5
   ....                         // ja ein Objekt. Da liegt auch  wirklich
6
   ....                         // Speicher dahinter.
7
8
9
   MRFD_TransmitPacket( &dasPacket );
d.h. die Funktion erwartet einen Pointer, weil du die Adresse eines 
tatsächlichen Objektes übergeben musst!

Adresse deshalb, weil ansonsten eine Kopie des Objektes gemacht werden 
würde und das zeit und resourcenaufwändig ist. Daher werden 
Strukturobjekte oft so übergeben, dass man die Adresse des Objektes 
übergibt.


Also: Bei Pointern in Funktionsargumentlisten immer ein bischen 
vorsichtig sein. Oft bedeutet das nur, dass du die Adresse eines 
tatsächlichen Objektes übergeben musst.

von C. H. (hedie)


Lesenswert?

Vielen Dank für deine Ausführliche Antwort Heinz

Karl Heinz Buchegger schrieb:
> mrfdPacket_t   dasPacket;    // ein tatsächliches Objekt.

Doch wenn ich da das Pointer Asterisk wegmache, kommt folgendes
1
../main.c:107: error: invalid type argument of '->' (have 'mrfdPacket_t')

Bei diesem hier:
1
myPacket->frame[0] = 2;
2
  myPacket->frame[1] = 0xBB;
3
  myPacket->frame[2] = 0xCC;

Ich habe mir schon gedacht, dass ich da mit dem Asterisk was falsch 
mache, aber da er ansonsten motzt, hab ichs dummerweise gelassen.

Hab das Problem grad gefunden.

Ich muss anstelle von '->' einfach einen '.' machen...

Kannst du mir noch den unterschied zwischen dem -> und dem . erklären 
bitte?

Weshalb brauche ich hier einen ->
1
 txBufLen = pPacket->frame[0]+1;
und kann nicht mit einem punkt zugreifen?


Juhuuuu mein Treiber läuft :) Danke vielmaaals :)

von Karl H. (kbuchegg)


Lesenswert?

Claudio Hediger schrieb:

> Kannst du mir noch den unterschied zwischen dem -> und dem . erklären
> bitte?

Ist ganz einfach.

Der . ist der Operator mit dem man auf einen Member eines 
Strukturobjektes zugreift.

struct time
{
  int day;
  int month;
};

struct time birthDay;

  birthDay.day = 8;
  birthDay.month = 4;


das ist der Normalfall.

So. Jetzt hast du einen Pointer und dieser Pointer zeige auf so ein 
Objekt

  struct time * userDate = &birthDay;


  userDate                birthDay
  +----------+            +--------------+
  |   o------------------>| day:   8     |
  +----------+            | month: 4     |
                          +--------------+

wie geht jetzt der Zugriff?

Zunächst mal muss der Pointer dereferenziert werden, also

   *userDate

damit ist man beim struct time Objekt (dem Kasten rechts) und von diesem 
Komplettobjekt hätte man zb gerne den day Member

   *userDate.day

das hat jetzt nur ein Problem. Die Operatoren-Reihenfolge ist falsch. 
Der Compiler würde das als

  *(userDate.day)

lesen. Nur: userDate ist ein Pointer! Der hat keine Member. Das Objekt 
auf das er zeigt, das hat den Member. Aber als Pointer hat er nichts. 
Den Pointer kann man nur dereferenzieren oder mit eiem anderen Pointer 
vergleichen und ein bischen Offset-rechnen. Aber Member, also einen 
inneren Aufbau, hat der keine.

D.h. das müsste man so schreiben

   (*userDate).day

jetzt passt alles. Jetzt ist die Dereferenzierung an den Pointer 
gebunden und erst von diesem Ergebnis (dem Objekt) nimmt man den day 
Member.


Da man aber in C in einem durchschnittlichen Programm viele tausend 
derartige Operationen hat, und die (*xx).yy Notation ziemlich 
besch...eiden zu tippen ist, gibt es dafür eine Kurzform

    userDate->day

Die Notation

    xx->yy

ist also nichts anderes als eine kürzere Schreibweise für

    (*xx).yy

die man benötigt, wenn xx ein Pointer ist und man auf einen Member 
zugreifen möchte, der in einem Objekt steckt auf das der Pointer zeigt.



genauso wie i++ eine kürzere Schreibweise für i = i+1 ist

von C. H. (hedie)


Lesenswert?

Vielen Vielen Dank Karl Heinz :)

Nun hab ich es verstanden.

Hoffentlich hilft es auch noch ein paar anderen weiter.


Gruss
aus der Schweiz
Claudio

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.