Forum: Mikrocontroller und Digitale Elektronik in Funktion kann der Struct kein Wert zugewiesen werden


von Michael8164 (Gast)


Lesenswert?

Hallo,

ich habe das Problem, dass ich in einer Funktion der ein Struct als 
Parameter übergeben wird keinen Wert zuweisen kann. Mache ich den Umweg 
über die lokale Variable temp, so geht's und dann komischerweise auch 
für alle anderen Elemente.
Woran könnte das liegen?
Vielen Dank für Eure Hilfe.
1
In Prototype.h:
2
3
struct bitfield_error_flags            
4
{
5
    volatile  uint8_type temp_shutdown   : 1U;
6
  volatile  uint8_type icht_error      : 1U;
7
  volatile  uint8_type laser1_locked   : 1U;
8
  volatile  uint8_type laser1_error      : 1U;
9
  volatile    uint8_type laser1_overcurrent: 1U;
10
  volatile  uint8_type eeprom_error     : 1U;
11
  volatile    uint8_type i2c_error         : 1U;
12
};
13
14
struct bitfield_error_flags  g_error        = {0U, 0U, 0U, 0U, 0U, 0U, 0U};
15
struct bitfield_error_flags  g_error_post   = {0U, 0U, 0U, 0U, 0U, 0U, 0U};
16
struct bitfield_error_flags  g_error_bit    = {0U, 0U, 0U, 0U, 0U, 0U, 0U};                         
17
18
//****************************************************************
19
20
In Header.h:
21
#ifndef HEADER_H
22
#define    HEADER_H
23
24
#include   "Prototype.h"
25
26
//***************************************************************
27
28
29
In Functions.c:
30
31
#ifndef HEADER_H
32
#include "header.h"
33
#endif
34
35
uint8_type get_bit_result( struct bitfield_error_flags *error )
36
{
37
  .....
38
  
39
    error->temp_shutdown      = g_error.temp_shutdown;   //geht nicht 
40
//  temp = g_error.temp_shutdown; //geht
41
//  error->temp_shutdown = temp;  //geht
42
    error->icht_error         = g_error.icht_error;
43
    error->laser1_locked      = g_error.laser1_locked;
44
    error->laser1_error       = g_error.laser1_error;
45
    error->laser1_overcurrent = g_error.laser1_overcurrent;
46
    error->eeprom_error       = g_error.eeprom_error;
47
    error->i2c_error          = g_error.i2c_error;
48
49
  ......
50
}
51
52
//**************************************************************
53
54
In main.c:
55
56
#ifndef HEADER_H
57
#include "header.h"
58
#endif
59
60
void main (void)
61
{
62
  .....
63
  get_bit_result(&g_error_post);
64
  ....
65
}

von Oliver S. (oliverso)


Lesenswert?

Wie genau äussert sich das "geht nicht" ?

Und etwas Hintergrundinfo über den verwendeten Comiler und die 
Zielplattform würde auch nicht schaden.

Oliver

von Michael8164 (Gast)


Lesenswert?

Oh, na klar sorry,

ich verwende den XC8 Compiler und der uC ist ein PIC18F46K22.
Mit "geht nicht" meinte ich wenn in
1
g_error.temp_shutdown
das Bit gesetzt ist, kann ich den Wert nicht in
1
error->temp_shutdown
kopieren. Mache ich den Umweg über die Variable temp, so gibt es kein 
Problem.

von Rolf Magnus (Gast)


Lesenswert?

Michael8164 schrieb:
> Mit "geht nicht" meinte ich wenn ing_error.temp_shutdown
> das Bit gesetzt ist, kann ich den Wert nicht inerror->temp_shutdown
> kopieren.

Jetzt hast du immer noch nicht geschrieben, was das  bedeutet. Also 
nochmal gefragt: Wie äußert sich "kann nicht"? Was passiert denn, wenn 
du es trotzdem versuchst?

von Michael8164 (Gast)


Lesenswert?

Der Wert in
1
g_error.temp_shutdown
bleibt unverändert auf 0x00 und sollte aber 0x01 sein.

von Bernd (Gast)


Lesenswert?

Michael8164 schrieb:
> struct bitfield_error_flags
> {
>     volatile  uint8_type temp_shutdown   : 1U;
>   volatile  uint8_type icht_error      : 1U;
>   volatile  uint8_type laser1_locked   : 1U;
>   volatile  uint8_type laser1_error      : 1U;
>   volatile    uint8_type laser1_overcurrent: 1U;
>   volatile  uint8_type eeprom_error     : 1U;
>   volatile    uint8_type i2c_error         : 1U;
> };


Das Bitfield sieht komisch aus.

Wie wäre es mit:
volatile unsinged temp_shutdown     : 1U;

usw.

von Michael8164 (Gast)


Lesenswert?

Hm. Hab gerade rausgefunden, dass es wohl daran liegt dass ich die 
Elemente im Bitfield mit "volatile" definiert habe. Lasse ich das weg, 
ist alles ok. Ich brauche aber das volatile, da die Elemente des 
Bitfields auch im Interrupt geschrieben werden können.

Bei mir ist
1
typedef  unsigned  char uint8_type;
definiert

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Michael8164 schrieb:
> Ich brauche aber das volatile, da die Elemente des Bitfields auch im
> Interrupt geschrieben werden können.

Zum Beispiel auch das Shutdown-Flag wieder auf 0?

von Vancouver (Gast)


Lesenswert?

Kannst Du nicht die Bitfield-struct-Variablen insgesamt als volatile 
deklarieren, anstatt die einzelnen Bitfields?

von Michael8164 (Gast)


Lesenswert?

Also ich habe eine paar Tests gemacht und m.E. funktioniert es nur wenn 
die struct nicht als volatile definiert wird (weder insgesamt noch die 
einzelnen Elemente).

von Michael8164 (Gast)


Lesenswert?

Muss mich korrigieren...
Wenn ich die struct als Ganzes volatile definiere, funktioniert die 
Zuweisung. Allerdings gibt es dann eine Compilerwarnung wahrscheinlich 
weil im Prototyp ein "normales" struct verwendet wird:

warning: (359) illegal conversion between pointer types
pointer to volatile struct bitfield_error_flags -> pointer to struct 
bitfield_error_flags


1
struct bitfield_error_flags                                
2
{
3
    uint8_type temp_shutdown   : 1U;                                                  
4
    uint8_type icht_error      : 1U;                                                  
5
    uint8_type laser1_locked   : 1U;                                                  
6
    uint8_type laser1_error      : 1U;                                                           
7
    uint8_type laser1_overcurrent: 1U;                                                         
8
    uint8_type eeprom_error     : 1U;                                                         
9
    uint8_type i2c_error         : 1U;                                                        
10
};
11
volatile struct bitfield_error_flags  g_error        = {0U, 0U, 0U, 0U, 0U, 0U, 0U};    
12
volatile struct bitfield_error_flags  g_error_post   = {0U, 0U, 0U, 0U, 0U, 0U, 0U};      
13
volatile struct bitfield_error_flags  g_error_bit    = {0U, 0U, 0U, 0U, 0U, 0U, 0U};
14
15
16
uint8_type get_bit_result( struct bitfield_error_flags *error );

von C0S (Gast)


Lesenswert?

Man sieht zwar nicht wir du die temp-Variable deklariert hast, 
allerdings wäre an der Stelle mein Ansatzpunkte.
Der Unterschied zwischen geht und geht nicht ist ja laut deinem Beispiel 
der unterschiedliche Datentyp der rechten Seite deiner Zuweisung.
1
volatile uint8_type : 1 = volatile uint8_type : 1 //geht nicht
2
volatile uint8_type : 1 = uint8_type //geht

Versuch doch spaßeshalber mal die Attribute nicht als Bit-Felder zu 
deklarieren. Sollte es dann funktionieren, weißt du schon mal das dein 
Compiler damit Probleme hat.
1
struct bitfield_error_flags            
2
{
3
    volatile  uint8_type temp_shutdown;
4
  volatile  uint8_type icht_error;
5
  volatile  uint8_type laser1_locked;
6
  volatile  uint8_type laser1_error;
7
  volatile    uint8_type laser1_overcurrent;
8
  volatile  uint8_type eeprom_error;
9
  volatile    uint8_type i2c_error;
10
};

Und solltest du das Struct nicht als Teil eines Protokolls verwenden ist 
die Speicherplatzersparnis mittels Bit-Felder meist eh zu 
vernachlässigen.

von FrickelFranz (Gast)


Lesenswert?

Hab's noch nie versucht: kann man auch einen Funktionsparameter volatile 
deklarieren?

Eigentlich kam mir die Idee volatile schon in einer Typendeklaration zu 
verwenden dirket komisch vor. Der Typ sollte ja nur die Struktur 
definieren, und nicht unnötig Eigenschaften der Instanzen davon 
erzwingen.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Michael8164 schrieb:
> struct bitfield_error_flags  g_error        = {0U, 0U, 0U, 0U, 0U, 0U,
> 0U};

Das ist eine Definition und Initialisierung - die hat in einer 
Headerdatei (*.h) absolut gar nichts verloren.

von C0S (Gast)


Lesenswert?

Der Typ soll allerdings auch so unnötige Eigenschaften der Instanz wie 
die Attribute festlegen. Wie, Attribute sind nicht unnötig? Volatile 
aber auch nicht. Wenn du das volatile, Aufgrund von "Multithreading", 
brauchst dann muss es angegeben werden. Ansonsten bekommst du nur 
undefiniertes Verhalten.
Man kann einen Zugriff war nachträglich noch als volatile über einen 
Pointer festlegen, allerdings ist das nur ein überschüssiges Konstrukt.

von C0S (Gast)


Lesenswert?

Rufus Τ. F. schrieb:
> Michael8164 schrieb:
>> struct bitfield_error_flags  g_error        = {0U, 0U, 0U, 0U, 0U, 0U,
>> 0U};
>
> Das ist eine Definition und Initialisierung - die hat in einer
> Headerdatei (*.h) absolut gar nichts verloren.

Man müsste sogar mit extern arbeiten
1
In Prototype.h:
2
3
...
4
5
extern struct bitfield_error_flags g_error;
6
7
In Functions.c:
8
9
struct bitfield_error_flags  g_error        = {0U, 0U, 0U, 0U, 0U, 0U, 0U};

von FrickelFranz (Gast)


Lesenswert?

C0S schrieb:
> Man kann einen Zugriff war nachträglich noch als volatile über einen
> Pointer festlegen, allerdings ist das nur ein überschüssiges Konstrukt.

Hat man nun aber einen Mischmasch, einige Felder müssen volatile sein, 
andere nicht. Wäre es überhaupt syntaktisch möglich zu definieren OHNE 
das direkt im Struct zu tun?

von C0S (Gast)


Lesenswert?

FrickelFranz schrieb:
> Hat man nun aber einen Mischmasch, einige Felder müssen volatile sein,
> andere nicht. Wäre es überhaupt syntaktisch möglich zu definieren OHNE
> das direkt im Struct zu tun?

Gegenfrage. Ist deine Anwendung so Leistungsorientiert das du es nicht 
verschmerzen kannst wenn mehr Variablen als unbedingt nötig nicht 
gecacht werden?
Um deine Frage aber zu beantworten: Nein (geht mit Aufwand schon, macht 
aber faktisch nie Sinn).
Außerdem spricht ja theoretisch nichts dagegen, volatile in der 
Deklaration zu verwenden.

von Stefan K. (stefan64)


Lesenswert?

Michael8164 schrieb:
> struct bitfield_error_flags  g_error        = {0U, 0U, 0U, 0U, 0U, 0U,
> 0U};
> struct bitfield_error_flags  g_error_post   = {0U, 0U, 0U, 0U, 0U, 0U,
> 0U};
> struct bitfield_error_flags  g_error_bit    = {0U, 0U, 0U, 0U, 0U, 0U,
> 0U};

Du definierst Variablen im Prototype.h file.

Sobald Du Prototype.h (oder Header.h, in dem Prototype.h includiert 
wird) in einem weiteren File includierst, bekommst Du eine 
Fehlermeldung, weil die Variablen dann mehrfach definiert werden.

Besser schreibst Du im Prototype.h File
1
extern bitfield_error_flags  g_error;
und in EINEM c-File (main.c oder wo immer das am besten hinpasst)
1
struct bitfield_error_flags  g_error        = {0U, 0U, 0U, 0U, 0U, 0U, 0U};

Viele Grüße, Stefan

von Torben K. (torbenk)


Lesenswert?

Michael8164 schrieb:
> Ich brauche aber das volatile, da die Elemente des Bitfields auch im
> Interrupt geschrieben werden können.

Wie Frank M. gleich danach schon sagte: Könnte es nicht sein, dass der 
Interrupt dir die Werte mit 0 überschreibt?

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Stefan K. schrieb:
> bekommst Du eine Fehlermeldung, weil die Variablen dann mehrfach
> definiert werden.

Es gibt leider Compiler (genauer: Linker), die diese 
Mehrfachdefinitionen kommentarlos übereinanderlegen, und so tatsächlich 
das gewünschte Ergebnis liefern.

von Markus F. (mfro)


Lesenswert?

Rufus Τ. F. schrieb:
> Es gibt leider Compiler (genauer: Linker), die diese
> Mehrfachdefinitionen kommentarlos übereinanderlegen, und so tatsächlich
> das gewünschte Ergebnis liefern.

Der hier verwendete hat (dank seiner gcc-Abstammung) Optionen, um das 
Verhalten zu steuern: -f(no)common . Es liegt also am Anwender ...

von Markus F. (mfro)


Lesenswert?

FrickelFranz schrieb:
> Hat man nun aber einen Mischmasch, einige Felder müssen volatile sein,
> andere nicht. Wäre es überhaupt syntaktisch möglich zu definieren OHNE
> das direkt im Struct zu tun?

wenn Du mir noch erklärst, was ein Compiler denn wohl Verrücktes 
optimieren könnte, wenn nur ein einzelnes Bit eines Bitfeldes volatile 
wäre, anstatt alle, dann beschäftige ich mich vielleich mit der Frage 
;).

von Michael8164 (Gast)


Lesenswert?

Torben K. schrieb:
> Wie Frank M. gleich danach schon sagte: Könnte es nicht sein, dass der
> Interrupt dir die Werte mit 0 überschreibt?

Leider nein, denn ich habe den Test im Debugmodus gemacht, direkt Werte 
zugewiesen und mit Singlestep geschaut was passiert ohne das da 
irgendein Interrupt mitspielt.

Ich hab momentan diese Version, damit habe ich das Problem nicht mehr:
1
volatile  struct bitfield_error_flags                                
2
{
3
    uint8_type temp_shutdown   : 1U;                                                  
4
    uint8_type icht_error      : 1U;                                                  
5
    uint8_type laser1_locked   : 1U;                                                  
6
    uint8_type laser1_error      : 1U;                                                           
7
    uint8_type laser1_overcurrent: 1U;                                                         
8
    uint8_type eeprom_error     : 1U;                                                         
9
    uint8_type i2c_error         : 1U;                                                        
10
};
11
struct bitfield_error_flags  g_error        = {0U, 0U, 0U, 0U, 0U, 0U, 0U};    
12
struct bitfield_error_flags  g_error_post   = {0U, 0U, 0U, 0U, 0U, 0U, 0U};      
13
struct bitfield_error_flags  g_error_bit    = {0U, 0U, 0U, 0U, 0U, 0U, 0U};
Allerdings bin ich mir da nicht so sicher ob die drei Variablen vom Typ 
struct dann auch volatile sind...

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Michael8164 schrieb:
> Leider nein, denn ich habe den Test im Debugmodus gemacht,

Wenn Du debuggst, gehe ich davon aus, dass dann auch jegliche 
Optimizer-Flags abgeschaltet sind und es damit ziemlich schnuppe ist, ob 
Du die Variablen volatile definierst oder nicht.

Was ist denn so geheim an Deiner ISR, dass Du die hier nicht zeigst?

> Ich hab momentan diese Version, damit habe ich das Problem nicht mehr:

Hast Du schon mal drüber nachgedacht, auf diese Bitfields zu verzichten 
und auf die klassische Methode mit Bitmasken setzen zurückzugreifen?

Wenn ich das hier sehe:
1
    error->temp_shutdown      = g_error.temp_shutdown;   //geht nicht 
2
    error->icht_error         = g_error.icht_error;
3
    error->laser1_locked      = g_error.laser1_locked;
4
    error->laser1_error       = g_error.laser1_error;
5
    error->laser1_overcurrent = g_error.laser1_overcurrent;
6
    error->eeprom_error       = g_error.eeprom_error;
7
    error->i2c_error          = g_error.i2c_error;

dann wird das in einer Bit-Kopier-Shift-Lesen-Shift-Schreiben-Orgie 
ausarten. Den vom Compiler erzeugten Code möchte ich hier gar nicht 
sehen wollen.

Wo es doch so einfach wäre:
1
volatile uint8_t g_error;
2
3
uint8_type get_bit_result( uint8_t *error )
4
{
5
   *error = g_error;
6
}

Aber manche mögen es ja, sich und den Compiler zu quälen ;-)

: Bearbeitet durch Moderator
von Michael8164 (Gast)


Lesenswert?

Frank M. schrieb:
> Aber manche mögen es ja, sich und den Compiler zu quälen ;-)

Da haben wir's wenigstens nie langweilig, mein Compiler und ich ;-)


> Was ist denn so geheim an Deiner ISR, dass Du die hier nicht zeigst?

Nein an der ISR ist nichts Geheimes, nur ist es hier für das Problem 
nicht relevant und ich wollte es deswegen weglassen.

> dann wird das in einer Bit-Kopier-Shift-Lesen-Shift-Schreiben-Orgie
ausarten. Den vom Compiler erzeugten Code möchte ich hier gar nicht
sehen wollen.

Da hast Du sicher recht, aber für mich gestaltet sich der Code 
übersichtlicher und besser lesbar und ich habe mich für diesen Weg 
entschieden. Die Flags werden im Programm an verschiedenen Stellen 
gesetzt und an der beschriebenen Stelle lediglich zentral zur Anzeige 
verwendet.

Aber Ihr habt mir trotzdem sehr geholfen und mir ein paar Denkanstösse 
mit auf den Weg gegeben. Vielen Dank dafür und weiter so in diesem 
Forum.

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.