mikrocontroller.net

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


Autor: Michael8164 (Gast)
Datum:

Bewertung
-1 lesenswert
nicht 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.
In Prototype.h:

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;
};

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};                         

//****************************************************************

In Header.h:
#ifndef HEADER_H
#define    HEADER_H

#include   "Prototype.h"

//***************************************************************


In Functions.c:

#ifndef HEADER_H
#include "header.h"
#endif

uint8_type get_bit_result( struct bitfield_error_flags *error )
{
  .....
  
    error->temp_shutdown      = g_error.temp_shutdown;   //geht nicht 
//  temp = g_error.temp_shutdown; //geht
//  error->temp_shutdown = temp;  //geht
    error->icht_error         = g_error.icht_error;
    error->laser1_locked      = g_error.laser1_locked;
    error->laser1_error       = g_error.laser1_error;
    error->laser1_overcurrent = g_error.laser1_overcurrent;
    error->eeprom_error       = g_error.eeprom_error;
    error->i2c_error          = g_error.i2c_error;

  ......
}

//**************************************************************

In main.c:

#ifndef HEADER_H
#include "header.h"
#endif

void main (void)
{
  .....
  get_bit_result(&g_error_post);
  ....
}


Autor: Oliver S. (oliverso)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wie genau äussert sich das "geht nicht" ?

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

Oliver

Autor: Michael8164 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Oh, na klar sorry,

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

Autor: Rolf Magnus (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: Michael8164 (Gast)
Datum:

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

Autor: Bernd (Gast)
Datum:

Bewertung
-1 lesenswert
nicht 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.

Autor: Michael8164 (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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
typedef  unsigned  char uint8_type;              
definiert

Autor: Frank M. (ukw) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: Vancouver (Gast)
Datum:

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

Autor: Michael8164 (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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).

Autor: Michael8164 (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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


struct bitfield_error_flags                                
{
    uint8_type temp_shutdown   : 1U;                                                  
    uint8_type icht_error      : 1U;                                                  
    uint8_type laser1_locked   : 1U;                                                  
    uint8_type laser1_error      : 1U;                                                           
    uint8_type laser1_overcurrent: 1U;                                                         
    uint8_type eeprom_error     : 1U;                                                         
    uint8_type i2c_error         : 1U;                                                        
};
volatile struct bitfield_error_flags  g_error        = {0U, 0U, 0U, 0U, 0U, 0U, 0U};    
volatile struct bitfield_error_flags  g_error_post   = {0U, 0U, 0U, 0U, 0U, 0U, 0U};      
volatile struct bitfield_error_flags  g_error_bit    = {0U, 0U, 0U, 0U, 0U, 0U, 0U};


uint8_type get_bit_result( struct bitfield_error_flags *error );

Autor: C0S (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.
volatile uint8_type : 1 = volatile uint8_type : 1 //geht nicht
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.
struct bitfield_error_flags            
{
    volatile  uint8_type temp_shutdown;
  volatile  uint8_type icht_error;
  volatile  uint8_type laser1_locked;
  volatile  uint8_type laser1_error;
  volatile    uint8_type laser1_overcurrent;
  volatile  uint8_type eeprom_error;
  volatile    uint8_type i2c_error;
};

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

Autor: FrickelFranz (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Rufus Τ. F. (rufus) (Moderator) Benutzerseite
Datum:

Bewertung
1 lesenswert
nicht 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.

Autor: C0S (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: C0S (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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
In Prototype.h:

...

extern struct bitfield_error_flags g_error;

In Functions.c:

struct bitfield_error_flags  g_error        = {0U, 0U, 0U, 0U, 0U, 0U, 0U};

Autor: FrickelFranz (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: C0S (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Stefan K. (stefan64)
Datum:

Bewertung
0 lesenswert
nicht 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
extern bitfield_error_flags  g_error;
und in EINEM c-File (main.c oder wo immer das am besten hinpasst)
struct bitfield_error_flags  g_error        = {0U, 0U, 0U, 0U, 0U, 0U, 0U};

Viele Grüße, Stefan

Autor: Torben K. (torbenk)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: Rufus Τ. F. (rufus) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Markus F. (mfro)
Datum:

Bewertung
0 lesenswert
nicht 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 ...

Autor: Markus F. (mfro)
Datum:

Bewertung
0 lesenswert
nicht 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 
;).

Autor: Michael8164 (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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:
volatile  struct bitfield_error_flags                                
{
    uint8_type temp_shutdown   : 1U;                                                  
    uint8_type icht_error      : 1U;                                                  
    uint8_type laser1_locked   : 1U;                                                  
    uint8_type laser1_error      : 1U;                                                           
    uint8_type laser1_overcurrent: 1U;                                                         
    uint8_type eeprom_error     : 1U;                                                         
    uint8_type i2c_error         : 1U;                                                        
};
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};      
Allerdings bin ich mir da nicht so sicher ob die drei Variablen vom Typ 
struct dann auch volatile sind...

Autor: Frank M. (ukw) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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:
    error->temp_shutdown      = g_error.temp_shutdown;   //geht nicht 
    error->icht_error         = g_error.icht_error;
    error->laser1_locked      = g_error.laser1_locked;
    error->laser1_error       = g_error.laser1_error;
    error->laser1_overcurrent = g_error.laser1_overcurrent;
    error->eeprom_error       = g_error.eeprom_error;
    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:
volatile uint8_t g_error;

uint8_type get_bit_result( uint8_t *error )
{
   *error = g_error;
}

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

: Bearbeitet durch Moderator
Autor: Michael8164 (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.