"Zeiger" auf struct-Element

Gast #4559911
Hallo, ich hab da ein kleines Problem.
Für das auslesen mehrerer Motor-Sensoren habe ich mir folgende Struktur 
an Variablen angelegt:
1
typedef struct{
2
  uint16_t ui16_sensor_val;
3
  char description_string[20];
4
} SENSOR;
5

6
struct sensors {
7
  SENSOR oil_pressure;
8
  SENSOR oil_temp;
9
  SENSOR coolant_pressure;
10
  SENSOR coolant_temp;
11
  SENSOR ambient_temp;
12
} datafields;
13

14
uint8_t ui8_active_screen = 0;

Jetzt möchte ich diese Sensorwerte auf einem Display ausgeben, abhängig 
vom Wert der in ui8_active_screen  der gewählten Bildschirmseite soll 
der entsprechende Sensor angezeigt werden.
also statt so für einen einzelnen Wert:

1
char Buffer[5];
2
itoa(datafields.oil_pressure.ui16_sensor_val, Buffer, 10);
3
lcd_string(Buffer);

eher sowas in der art:

1
char Buffer[5];
2
itoa(datafields[ui8_active_screen].ui16_sensor_val, Buffer, 10);
3
lcd_string(Buffer);

das frisst der compiler natürlich nicht. Wie kann ich das 
bewerkstelligen ?
Vielen dank schonmal...
#4559928
Mit einem Array.
1
#define SENSOR_COUNT 3
2

3
struct sensors {
4
  SENSOR oil_pressure;
5
  SENSOR oil_temp;
6
  SENSOR coolant_pressure;
7
  SENSOR coolant_temp;
8
  SENSOR ambient_temp;
9
} datafields[SENSOR_COUNT];

Oder noch besser:
1
// Headerfile
2
#define SENSOR_COUNT 3
3

4
struct sensor { // nur declaration
5
  SENSOR oil_pressure;
6
  SENSOR oil_temp;
7
  SENSOR coolant_pressure;
8
  SENSOR coolant_temp;
9
  SENSOR ambient_temp;
10
};
...
1
// c file
2
struct sensor sensors[SENSOR_COUNT]; // definition
...
1
char Buffer[6]; // 6 statt fünf, weil das Nullbyte auchnoch Platz braucht
2
itoa(sensors[ui8_active_screen].ui16_sensor_val, Buffer, 10);
3
lcd_string(Buffer);
Gast #4559936
@mr.mo

danke, werde ich mal ansehen...

@Daniel

hätte ich dann aber nicht 3 mal das komplette struct ? Also 3 mal den 
Ölsensor, 3 mal den Kühlmittelsensor, usw ?
1
char Buffer[6]
stimmt, an die maximale 65535 muss ja als String noch ne '\0' ran... 
ganz vergessen, danke ^^
Gast #4559955
Marcel P. schrieb:
> typedef struct{
>   uint16_t ui16_sensor_val;
>   char description_string[20];
> } SENSOR;
>
> struct sensors {
>   SENSOR oil_pressure;
>   SENSOR oil_temp;
>   SENSOR coolant_pressure;
>   SENSOR coolant_temp;
>   SENSOR ambient_temp;
> } datafields;

Servus,
du willst ja mit Pointer arbeiten. Ein großes Thema ist es immer wieder, 
wenn es um dynamische Speicherverwaltung geht...

Hier ein hardcoded bsp.:
1
typedef struct{
2
   uint16_t ui16_sensor_val;
3
   char description_string[20];
4
} SENSOR_t;
5

6
typedef struct sensors {
7
   SENSOR_t oil_pressure;
8
   SENSOR_t oil_temp;
9
   SENSOR_t coolant_pressure;
10
   SENSOR_t coolant_temp;
11
   SENSOR_t ambient_temp;
12
 } DATAFIELD_t;
13

14
//gloabal var
15
DATAFIELD_t[] DATA
Gast #4559970
@aSma

irgendwie stehe ich gerade auf dem Schlauch was du mir genau sagen 
möchtest.
Liegt vielleicht aber auch daran, das ich gerade versuche den -> 
Operator zu verstehen o.O

Im Grunde möchte ich folgende Funktion erreichen, nur eben sehr viel 
einfacher, da die Sensoren mehr werden sollen und ich nicht für jeden 
Sensor ein extra case-Block schreiben möchte.
1
      char Buffer[5];
2
      
3
      switch(ui8_active_screen) {
4
        
5
        case 0:
6
        itoa(datafields.oil_temp.sensor_val, Buffer, 10);
7
        break;
8
        case 1:
9
        itoa(datafields.oil_pressure.sensor_val, Buffer, 10);
10
        break;
11
        case 2:
12
        itoa(datafields.coolant_temp.sensor_val, Buffer, 10);
13
        break;
14
        case 3:
15
        itoa(datafields.coolant_pressure.sensor_val, Buffer, 10);
16
        break;
17
        case 4:
18
        itoa(datafields.ambient_temp.sensor_val, Buffer, 10);
19
        break;
20
        default:
21
        
22
      }
23
      lcd_setcursor(0,0);
24
      lcd_string(Buffer);
Gast #4559987
Marcel P. schrieb:
> typedef struct{
>   uint16_t ui16_sensor_val;
>   char description_string[20];
> } SENSOR;
>
> struct sensors {
>   SENSOR oil_pressure;
>   SENSOR oil_temp;
>   SENSOR coolant_pressure;
>   SENSOR coolant_temp;
>   SENSOR ambient_temp;
> } datafields;

Servus,
du willst ja mit Pointer arbeiten. Ein großes Thema ist es immer wieder, 
wenn es um dynamische Speicherverwaltung geht...

Hier ein hardcoded bsp.:
1
//in header
2
#define      MAX_SENSOR   3    
3

4
typedef struct{
5
   uint16_t ui16_sensor_val;
6
   char description_string[20];
7
} SENSOR_t;
8

9
typedef struct{
10
   SENSOR_t oil_pressure;
11
   SENSOR_t oil_temp;
12
   SENSOR_t coolant_pressure;
13
   SENSOR_t coolant_temp;
14
   SENSOR_t ambient_temp;
15
 } DATAFIELD_t;
16

17
DATAFIELD_t* read_data(); //fkt in header
18

19

20
//gloabal var
21
DATAFIELD_t DATA[MAX_SENSOR];  
22

23
//fkt mit einen pointer als rückgabetyp
24
DATAFIELD_t* read_data(){
25

26
static uint8_t sensor_counter=0;  // No malloc use. Hard coded.
27

28
if (sensor_counter == MAX_SENSOR)  // Max sensor arrived. 
29
    return NULL;
30

31
//hier ist dein pointer
32
DATAFIELD_t* p = (DATAFIELD_t*)&DATA[sensor_counter++]; //pointer zeigt auf sensor i!
33

34
p->oil_pressure.ui16_sensor_val = xxx;
35

36
...
37
return p;
38
}
39

40
//main
41
extern DATAFIELD_t* read_data();
42
DATAFIELD_t *sensor1_p, *sensor2_p ,*sensor3_p;
43

44
int main(){
45

46
sensor1_p = read_data();
47
sensor2_p = read_data();
48
sensor3_p = read_data();
49
}

Wenn du
>   uint16_t ui16_sensor_val;
>   char description_string[20];
nicht gleichzeitig brauchst, dann kannst du daraus auch eine union 
machen.

mfg
Gast #4560019
Marcel P. schrieb:
> char Buffer[5];
>
>       switch(ui8_active_screen) {
>
>         case 0:
>         itoa(datafields.oil_temp.sensor_val, Buffer, 10);
>         break;
> ...

Dein case ist nicht ausgagekräftig. Du brauchst hier keinen Pointer, 
wenn du alles global hälst. Aber du kannst natürlich einen nutzen. Wie 
zuvor von mir gezeigt.
1
typedef enum{
2
   oil_temp = 0,
3
   cool_pres,
4
   cool_temp,
5
   amb_temp,
6
} SENSOR_SWITCH_t;
7

8
SENSOR_SWITCH_t sensor_e;
9

10
switch(sensor_e) {
11

12
      case oil_temp:
13
                        itoa(datafields.oil_temp.sensor_val, Buffer, 10);
14
                        break;
15
      case cool_pres:

usw
#4560024
Marcel P. schrieb:
> @Daniel
>
> hätte ich dann aber nicht 3 mal das komplette struct ? Also 3 mal den
> Ölsensor, 3 mal den Kühlmittelsensor, usw ?

Ups, ich hatte nicht nachgesehen, was im Struct drin steht. Neuer 
vorschlag: (c11)
1
typedef struct{
2
  uint16_t ui16_sensor_val;
3
  char description_string[20];
4
} SENSOR;
5

6
struct sensors {
7
  union {
8
    SENSOR sensor_list[1];
9
    struct {
10
      SENSOR oil_pressure; // Müssen alle vom typ SENSOR sein
11
      SENSOR oil_temp;
12
      SENSOR coolant_pressure;
13
      SENSOR coolant_temp;
14
      SENSOR ambient_temp;
15
    };
16
  };
17
} datafields;
18

19
uint8_t ui8_active_screen = 0;
20

21
...
22

23
char Buffer[6];
24
itoa(datafields.sensor_list[ui8_active_screen].ui16_sensor_val, Buffer, 10);
25
lcd_string(Buffer);
Gast #4560141
@aSma

ok, ich versuche mal zu verstehen, wie ich das dann anwende. Momentan 
stehe ich gerade immernoch auf den Schlauch, was aber eher an mir liegt 
^^ .

Ich hab mal kommentiert, wie ich das verstanden habe... und ab wo ich 
auf dem schlauch stehe...
1
//in header
2
#define      MAX_SENSOR   3                      // meine Anzahl an sensoren (eigentlich 5)...
3

4
typedef struct{
5
   uint16_t ui16_sensor_val;
6
   char description_string[20];
7
} SENSOR_t;
8

9
typedef struct{
10
   SENSOR_t oil_pressure;
11
   SENSOR_t oil_temp;
12
   SENSOR_t coolant_pressure;
13
   SENSOR_t coolant_temp;
14
   SENSOR_t ambient_temp;
15
 } DATAFIELD_t;
16

17
DATAFIELD_t* read_data(); //fkt in header        
18

19

20
//gloabal var
21
DATAFIELD_t DATA[MAX_SENSOR];                        // indiesem Array stehen meine jeweiligen Sensorwerte aus ui16_sensor_val
22

23
//fkt mit einen pointer als rückgabetyp
24
DATAFIELD_t* read_data(){
25

26
static uint8_t sensor_counter=0;  // No malloc use. Hard coded.                             //fängt bei 0 an, klar
27

28
if (sensor_counter == MAX_SENSOR)  // Max sensor arrived.                                  //wenn alle Sensoren durch, fertig
29
    return NULL;
30

31
//hier ist dein pointer
32
DATAFIELD_t* p = (DATAFIELD_t*)&DATA[sensor_counter++]; //pointer zeigt auf sensor i!        // Hier fängt es an für mich unverständlich zu werden
33

34
p->oil_pressure.ui16_sensor_val = xxx;                                                         // Hier steig ich ganz aus ? das ist ja nur der Öldruck-Sensor.. was ist mit den anderen ? Entsprechend so ?:
35

36
p->oil_temp.ui16_sensor_val = xxx;                       // =xxx wäre dann etwa mein = ADC_Read_avg(channel, samples); für jeden sensor ?
37

38
...
39
return p;
40
}
41

42
//main
43
extern DATAFIELD_t* read_data();
44
DATAFIELD_t *sensor1_p, *sensor2_p ,*sensor3_p;                  // verstehe ich nicht ganz genau, aber das sind dann 3 pointer für das struct DATAFIELD_t ?
45

46
int main(){
47

48
sensor1_p = read_data();
49
sensor2_p = read_data();
50
sensor3_p = read_data();
51
}

Sorry, das ich mich doof anstelle, aber pointer sind für mich irgendwie 
ein rotes Tuch....

@Daniel

mache ich mir durch deinen Vorschlag nicht den Vorteil des struct 
zunichte wenn alle vom Typ SENSOR sein müssen ? Weil dann könnte ich 
doch auch ein Array draus machen ? Also statt dem hier:
1
typedef struct{
2
  uint16_t sensor_val;
3
  char description_string[20];
4
} SENSOR;
5

6
struct sensors {
7
  union {
8
    SENSOR sensor_list[1];
9
    struct {
10
      SENSOR oil_pressure; // Müssen alle vom typ SENSOR sein
11
      SENSOR oil_temp;
12
      SENSOR coolant_pressure;
13
      SENSOR coolant_temp;
14
      SENSOR ambient_temp;
15
    };
16
  };
17
} datafields;

dann so:
1
enum sensors {
2
OIL_PRES_e = 0,
3
OIL_TEMP_e,
4
COL_TEMP_e,
5
EOL_PRES_e,
6
AMB_PRES_e
7
};
8

9
SENSOR sensors[5];
10

11
itoa(sensors[OIL_PRES].sensor_val, Buffer, 10);

oder ?

Ich habe das "Datafields" als struct angelegt, weil da in Zukunft noch 
andere sachen ausser SENSOR-typen dazu kommen sollen. Diese anderen 
enthalten zwar auch immer die Felder "sensor_val" und 
"sensor_descriptor" aber eben auch noch zusätzliche Felder.
#4560176
Marcel P. schrieb:
> mache ich mir durch deinen Vorschlag nicht den Vorteil des struct
> zunichte wenn alle vom Typ SENSOR sein müssen ? Weil dann könnte ich
> doch auch ein Array draus machen ? Also statt dem hier:

Ja. In solchen fällen nutze ich Basisklassen.
1
enum sensor_type {
2
  ST_PRESSURE,
3
  ST_TEMP
4
};
5

6
struct sensor {
7
  enum sensor_type type;
8
  uint16_t ui16_sensor_val;
9
  char description_string[20];
10
};
11

12
struct pressure_sensor {
13
  struct sensor super;
14
  bool other_value;
15
};
16

17
struct temp_sensor {
18
  struct sensor super;
19
  int bla;
20
};
21

22
struct pressure_sensor oil_pressure = {
23
  .type = ST_PRESSURE
24
};
25

26
struct temp_sensor oil_temp = {
27
  .type = ST_TEMP
28
};
29

30
struct pressure_sensor coolant_pressure = {
31
  .type = ST_PRESSURE
32
};
33

34
struct temp_sensor coolant_temp = {
35
  .type = ST_TEMP
36
};
37

38
struct temp_sensor ambient_temp = {
39
  .type = ST_TEMP
40
};
41

42
struct sensor* sensors[] = {
43
  &oil_pressure.super,
44
  &oil_temp.super,
45
  &coolant_pressure.super,
46
  &coolant_temp.super,
47
  &ambient_temp.super
48
};
49

50
...
51

52
char Buffer[6];
53
itoa(sensors[ui8_active_screen]->ui16_sensor_val, Buffer, 10);
54
lcd_string(Buffer);
Gast #4560190
Marcel P. schrieb:
> Sorry, das ich mich doof anstelle, aber pointer sind für mich irgendwie
> ein rotes Tuch....

Siehe Überschrift: "Zeiger" auf struct-Element

Dann lasse einfach die Zeiger und Unions weg.

Wichtig ist, dass man aussagekräftig programmiert, denn dann brauchst du 
auch kaum zu kommentieren (Stichwort: real programmer).

Schreibe jetzt ein header und .c Datei und poste hier.

mfg
Gast #4560229
Ich werde versuchen das sinnig in mein Code zu setzen und dann poste ich 
das ganze Ding mal hier sobald es passt.

Vielen vielen Dank aber schon mal. Die Codebeispiele haben mir aber auch 
noch viele andere Kleinigkeiten gezeigt, die den Programmierstil viel 
besser machen.

Grüße, Marcel

Antwort schreiben

Eine eigene Frage? Dieser Thread ist über 10 Jahre alt. Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.

Neuen Thread starten

Eine Lösung, Ergänzung oder Rückmeldung zu diesem Thread? Dann antworte hier.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.