Forum: Compiler & IDEs Funktionszeiger in struct, ich verstehe es nicht.


von Sascha W. (bucky2k)


Lesenswert?

Ich habe schon einmal im µC Forum gepostet, aber leider habe ich mich 
nicht genau ausgedrückt und es kam zu Missverständnissen. Da ich denke 
das Ganze ist hier eh etwas besser aufgehoben ist, nochmal der zweite 
Versuch. Ich hoffe jemand kann mir einen Tipp geben, wie ich den von 
Bosch gelieferten undvollständigen Code mit meinen I²C Funktionen 
verheiraten kann. Zur Vereinfachung habe ich nur die Read Funktion 
angeben und alles drumherum rausgelöscht. In den Kommetaren habe ich 
durch "Bosch" Zeilen bezeichnet, die eben fertig waren und mit "Bucky" 
die meinen.

PS: Ihr seit meine letzte Hoffnung, sitze schon seit vielen Stunden 
dran. Wenn es nicht klappt muss ich alles neu schreiben ohne 
Funktionszeiger... :-(

Beschreibung:
Die Init Funktion in der bmp085.c Datei soll meine Read Funktion beutzen 
um auf den Chip per TWI zuzugreifen. Dies geschieht über Pointer und 
Funktionspointer. Wie verbinde ich meine bus_read funktion mit dem 
Bosch-Code der diese in der bmp085_init() aufrufen möchte? Hier der Code 
so kurz wie es eben ging:
1
main.c:
2
3
#include "RS232.h"
4
#include "TWI_Master.h"
5
#include "bmp085.h"
6
7
int main (void)
8
  {
9
  TWIM_Init (368000);
10
  RS232_Init ();
11
  //hier würde ich das Struct aus der bmp085.h generieren
12
  bmp085_t mybmp;
13
  bmp085_init(&mymbp);  //structpointer übergeben
14
  }
15
16
17
bmp085.h:
18
19
//Prototyp Bus-Lesefunktion Bucky
20
char bus_read(unsigned char device_addr, unsigned char register_addr, unsigned char *register_data, unsigned char read_length);
21
22
//Returnparameter Bosch
23
#define BMP085_BUS_RD_RETURN_TYPE char
24
25
//Übergabeparameter Bosch
26
#define BMP085_BUS_RD_PARAM_TYPES unsigned char,unsigned char,unsigned char *,unsigned char
27
28
//Makro Bosch
29
#define BMP085_BUS_READ_FUNC(device_addr, register_addr, register_data, write_length)\
30
           bus_write( device_addr, register_addr, register_data, write_length )
31
32
// BMP085 image registers data structure Bosch
33
34
typedef struct  {  
35
  .
36
  .
37
  .
38
  BMP085_BUS_WR_RETURN_TYPE (*bus_write)( BMP085_BUS_WR_PARAM_TYPES ); 
39
  BMP085_BUS_RD_RETURN_TYPE (*bus_read)( BMP085_BUS_RD_PARAM_TYPES );  //hier der relevante Funktionspointer
40
  BMP085_MDELAY_RETURN_TYPE (*delay_msec)( BMP085_MDELAY_DATA_TYPE );
41
} bmp085_t;
42
43
bmp085.c:
44
45
#include "bmp085.h"
46
47
bmp085_t *p_bmp085 = 0; /Pointer to BMP085 device area Bosch
48
49
int bmp085_init(bmp085_t *bmp085) 
50
{
51
  unsigned char data;
52
 
53
  p_bmp085 = bmp085;                                // assign BMP085 ptr
54
  p_bmp085->dev_addr = BMP085_I2C_ADDR;             // preset BMP085 I2C_addr 
55
//hierin dem kommenden Aufruf springt der µC an den Programmanfang statt in meine bus_read Funktion:
56
  comres += p_bmp085->BMP085_BUS_READ_FUNC(p_bmp085->dev_addr, BMP085_CHIP_ID__REG, &data, 1);  
57
}
58
59
read_write.c:
60
61
#include "bmp085.h"
62
#include <stdio.h>
63
#include "TWI_Master.h"
64
65
66
//Meine Bus-Read Funktion
67
68
69
char bus_read(unsigned char device_addr, unsigned char register_addr, unsigned char *register_data, unsigned char read_length )
70
{
71
72
uint8_t i;
73
 
74
    //I2C Starten mit device_adresse und WRITE, etc pp.  
75
  return 0;
76
}

von Klaus W. (mfgkw)


Lesenswert?

hm, man sieht ja nur die Hälfte.

Deshalb mal die Vermutung: bmp085_init benötigt nicht nur
eine struct mit irgendwas drin, sondern eine vernünftig vorbelegte
struct.
Du hast ja bereits eine Funktion bus_read.
Je eine ähnliche Funktion wirst du noch zum Schreiben und
für delay_msec brauchen.
Alle drei müssen dann mit einer Zuweisung oder beim Initialisieren
der struct eingetragen werden, und dann mit dieser gefüllten struct
wird bmp085_init aufgerufen.

Also etwa in der Art:
1
int main (void)
2
{
3
  TWIM_Init (368000);
4
  RS232_Init ();
5
  //hier würde ich das Struct aus der bmp085.h generieren
6
  bmp085_t mybmp;
7
8
  mybmp.bus_read = bus_read;
9
  // analog für bus_write und delay_msec...
10
11
  bmp085_init(&mymbp);  //structpointer übergeben
12
}

Ist jetzt so meine Vermutung....

In der Doku zu bmp085_init sollte vielleicht mehr dazu stehen,
was sie wirklich braucht und was die Funktionen machen müssen;
da habe ich keine Ahnung.

von G a s t (Gast)


Lesenswert?

Die Parameter der Funktionszeiger im Struct und die deiner Funktion 
sollten auch uebereinstimmen.

von Sascha W. (bucky2k)


Lesenswert?

Eine Doku ist nicht vorhanden und der ganze Programmcode ist natürlich 
viel länger, es gibt bereits eine Funktion fürs bus_write, etc. Aber er 
steigt halt schon beim ersten bus_read aus. Das eine leere Struct 
übergeben wird ist korrekt, über die bmp_init wird diese dann gefüllt 
mit parametern aus dem chip.

Wenn ich in "comres += 
p_bmp085->BMP085_BUS_READ_FUNC(p_bmp085->dev_addr, BMP085_CHIP_ID__REG, 
&data, 1); " das "p_bmp085->" raus nehme geht es auch, er greift auf 
meine bus_read direkt zu. Wenn es aber über den Struct und den darin 
erstellten  Funktionszeiger gehen soll steigt er aus. Ich stelle mir es 
wie folgt vor:

-ich erstelle ein Struct des Typs bmp085_t: bmp085_t mybmp;

-es existiet nun neben den ganzen Calibrierparameter-Variablen auch ein
Funktionspointer für die bus_read funktion mit genau meinen Parametern:
"BMP085_BUS_RD_RETURN_TYPE (*bus_read)( BMP085_BUS_RD_PARAM_TYPES );"

-ich rufe bmp085_init auf und es wird irgendwann vom Bus gelesen:
"comres += p_bmp085->BMP085_BUS_READ_FUNC(p_bmp085->dev_addr, 
BMP085_CHIP_ID__REG, &data, 1); "

-wegen p_bmp085-> wird in das struct mybmp geschaut, hier sollte der 
Funktionspointer bus_read hinterlegt sein

- hier steigt das Programm nun aus, da die Verbindung zwischen dem 
Funktionspointer und meiner bus_read Funktion fehlt. Diese Verbindung 
will mir trotz intensiver Literaturrecherche nicht gelingen.

Verständlich? Oder habe ich zu viel Code herausgelöscht (Urheberrecht)? 
Evtl. könnte ich es per mail an einzelne geben für eine bessere 
Übersicht...

von g457 (Gast)


Lesenswert?

p_bmp085->BMP085_BUS_READ_FUNC ist NULL, zumindest wurde es in obigem 
Codefragment nicht initialisiert. D.h. er springt an den Reset-Interrupt 
(der liegt i.d.R. bei 0x00).

HTH

von Stefan E. (sternst)


Lesenswert?

Bucky 2k schrieb:
> Das eine leere Struct
> übergeben wird ist korrekt, über die bmp_init wird diese dann gefüllt
> mit parametern aus dem chip.

Aber damit die Funktion auf den Chip zugreifen kann, muss der 
Funktionszeiger vorher eingetragen worden sein. So wie Klaus es schon 
geschrieben hat:
1
  bmp085_t mybmp;
2
  mybmp.bus_read = bus_read;
3
  bmp085_init(&mymbp);


> Wenn ich in "comres +=
> p_bmp085->BMP085_BUS_READ_FUNC(p_bmp085->dev_addr, BMP085_CHIP_ID__REG,
> &data, 1); " das "p_bmp085->" raus nehme geht es auch, er greift auf
> meine bus_read direkt zu. Wenn es aber über den Struct und den darin
> erstellten  Funktionszeiger gehen soll steigt er aus.

Eben weil der Funktionszeiger nicht initialisiert ist.

> Ich stelle mir es wie folgt vor:
>
> -ich erstelle ein Struct des Typs bmp085_t: bmp085_t mybmp;
>
> -es existiet nun neben den ganzen Calibrierparameter-Variablen auch ein
> Funktionspointer für die bus_read funktion mit genau meinen Parametern:
> "BMP085_BUS_RD_RETURN_TYPE (*bus_read)( BMP085_BUS_RD_PARAM_TYPES );"

Aber er existiert nicht "irgendwie automatisch", du musst ihn da schon 
reinschreiben.

> - hier steigt das Programm nun aus, da die Verbindung zwischen dem
> Funktionspointer und meiner bus_read Funktion fehlt. Diese Verbindung
> will mir trotz intensiver Literaturrecherche nicht gelingen.

Ernsthaft? Nirgendwo in deiner Literatur steht, wie man einem 
Funktionszeiger einen Wert zuweist?
Siehe oben.

von Klaus W. (mfgkw)


Lesenswert?

g457 schrieb:
> p_bmp085->BMP085_BUS_READ_FUNC ist NULL, zumindest wurde es in obigem
> Codefragment nicht initialisiert. D.h. er springt an den Reset-Interrupt
> (der liegt i.d.R. bei 0x00).
>
> HTH

Das wäre ja noch schön.
In Wirklichkeit ist es noch schlimmer: der Inhaöt ist zufällig!
Ebenso wie die beiden anderen Zeiger.

Wäre die struct global, dann wäre alles mit 0 initialisiert.
Hier ist es dagegen eine automatische Variable, daher nicht
mit einem definierten Wert vorbelegt.

von Klaus W. (mfgkw)


Lesenswert?

Bucky 2k schrieb:
> ...
> - hier steigt das Programm nun aus, da die Verbindung zwischen dem
> Funktionspointer und meiner bus_read Funktion fehlt. Diese Verbindung
> will mir trotz intensiver Literaturrecherche nicht gelingen.

Ich habe netterweise bereits recherchiert.
Die Verbindung ist die Zeile, die ich oben hingeschrieben hatte:
1
  mybmp.bus_read = bus_read;

Das bedeutet: an das Element bus_read der Struktur mybmp
(also an mybmp.bus_read) wirde die Adresse deiner Funktion
bus_read zugewiesen.

Das Gleiche musst du noch für die anderen beiden Funktionen
machen.

Mit dem Aufruf der init-Funktion machst du den
bmp085-Funktionen deine Funktionen bekannt.

Ich gehe schwer davon aus, daß es nicht reicht,
nur die read-Funktion einzutragen.

Dringende Empfehlung: Alle drei Funktionen definieren und
in der struct eintragen, und dafür sorgen, daß sich die
Funktionen bemerkbar machen, wenn sie aufgerufen werden
(für jede der Funktionen eine eigene LED, oder Logausgabe
o.s.ä.).

Ansonsten ist es nötig, mehr Infos zu bekommen.
Was zum Beispiel heißt "... steigt er aus"?

Wie soll man mit Quelltextfragmenten und solchen
Beschreibungen etwas erraten?

Weitere Empfehlung: erstmal unabhängig vom konkreten
Problem mit Funktionszeigern warm werden!
Z.B. mit den Funktionen bsearch und qsort aus der
Standardbibliothek kann man schön spielen.


> ...

von Karl H. (kbuchegg)


Lesenswert?

Bucky 2k schrieb:

> bmp085.h:
>
> //Prototyp Bus-Lesefunktion Bucky
> char bus_read(unsigned char device_addr, unsigned char register_addr,
> unsigned char *register_data, unsigned char read_length);
>

Dieser Prototyp gehört da nicht rein!
Die bmp085.h geht dich nichts an (die ist von Bosch). Also lass sie in 
Ruhe.
Deine Funktion bus_read residiert in read_write.c
Ergo mach ein Header File read_write.h dafür. Dort kommt dann der 
Prototyp rein.

von Er (Gast)


Lesenswert?

Keine Sorge, wenn Du das geschafft hast, kommen noch CAN-Treiber von 
Vektor. Da schlackern Dir erst die Ohren.

von Sascha W. (bucky2k)


Lesenswert?

Klaus Wachtler schrieb:
> Ich habe netterweise bereits recherchiert.
> Die Verbindung ist die Zeile, die ich oben hingeschrieben hatte:
>
1
>   mybmp.bus_read = bus_read;
2
>
>
>

Entschuldige, ich habe gestern nach dem Heimkommen noch schnell die 
Fragen beantworten wollen und die entsprchende Zeile überlesen.

Auch habe ich versucht den Funktionszeiger zu initialisieren, das etwas 
fehlte war mir ja bewusst (und das er deshalb an den Anfang des 
Programms sprang). Nur habe ich es aus der FAQ und aus dem C von A bis Z 
Buch nicht umsetzen können, es kamen immer Compilerfehler. DIe FAQ 
schlägt ja z.B. dies vor, oder habe ich da ganz falsch geschaut:

typedef void (*VoidFnct)( void );
mit
VoidFnct MeineFunktionen[] = { Funct1, Funct2 };
und den Aufruf
MeineFunktionen[0]();

Dies konnte ich nicht adaptieren und ist ja auch abweichend vom 
gemachten Vorschlag hier...


Vielen Dank jedenfalls für die Hilfe in diesem Thread, es hat mir viel 
weitere Arbeit erspart wenn es heute Abend dann hoffentlich 
funktioniert...

Bucky

von Sascha W. (bucky2k)


Lesenswert?

Klaus Wachtler schrieb:
> Ich habe netterweise bereits recherchiert.
> Die Verbindung ist die Zeile, die ich oben hingeschrieben hatte:
>
1
>   mybmp.bus_read = bus_read;
2
>
>
> Ich gehe schwer davon aus, daß es nicht reicht,
> nur die read-Funktion einzutragen.
>
> Dringende Empfehlung: Alle drei Funktionen definieren und
> in der struct eintragen, und dafür sorgen, daß sich die
> Funktionen bemerkbar machen, wenn sie aufgerufen werden
> (für jede der Funktionen eine eigene LED, oder Logausgabe
> o.s.ä.).
>
> Wie soll man mit Quelltextfragmenten und solchen
> Beschreibungen etwas erraten?
>
> Weitere Empfehlung: erstmal unabhängig vom konkreten
> Problem mit Funktionszeigern warm werden!
> Z.B. mit den Funktionen bsearch und qsort aus der
> Standardbibliothek kann man schön spielen.
>
>
> ...

Das Erraten hat aber ja super geklappt, denn es funktioniert wunderbar! 
Mein Problem war, dass ich zwar wusste wie Funktionszeiger 
funktionieren, auch wusste wie ich ein Element im Struct adressiere, 
aber beides zusammen nicht erkannt habe. Mit mybmp.bus_read = bus_read; 
klappt es ich habe irgendwie immer versucht den Zeiger dem Struct als 
ganzes zu übergeben und nicht bedacht, dass ich selbstverständlich auch 
die Stelle im Struct angeben muss. Tatsächlich muss ich nur bus_read und 
bus_write implementieren, der Rest ist bereits im Bosch Code.


Karl heinz Buchegger schrieb:
> Bucky 2k schrieb:
>
>> bmp085.h:
>>
>> //Prototyp Bus-Lesefunktion Bucky
>> char bus_read(unsigned char device_addr, unsigned char register_addr,
>> unsigned char *register_data, unsigned char read_length);
>>
>
> Dieser Prototyp gehört da nicht rein!
> Die bmp085.h geht dich nichts an (die ist von Bosch). Also lass sie in
> Ruhe.
> Deine Funktion bus_read residiert in read_write.c
> Ergo mach ein Header File read_write.h dafür. Dort kommt dann der
> Prototyp rein.

Ich stimme zu, dass es eigentlich eine neue Headerdatei geben sollte. 
Aber Bosch hat direkt einen Platzhalter in der Header vorgesehen, daher 
habe ich die Prototypen da rein gepackt:

/**
   define for used read and write macros
*/
/** Define the calling convention of YOUR bus communication routine.
  \note This includes types of parameters. This example shows the 
configuration for an SPI bus link.
*/




Vielen Dank nochmal an alle Helfenden für Ihre Gedult mit jemandem der 
C-Programmierung und µC (noch) nicht regelmäßig benutzt und daher nicht 
alle Zusammenhänge direkt erkennt, auch wenn die Funktionen für sich 
nachgeschlagen und verstanden wurden!!!

Bucky

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.