-         

Seite 1 von 2 12 LetzteLetzte
Ergebnis 1 bis 10 von 13

Thema: globale Variable und Interrupt

  1. #1
    Neuer Benutzer Öfters hier
    Registriert seit
    03.01.2006
    Beiträge
    6

    globale Variable und Interrupt

    Anzeige

    Hi,

    mein Interrupt muss auf ein Statusflag zugreifen, dass als globale Variable im Hauptprogramm definiert wurde. Die Interrupt-Routine soll in einer extra Datei ausgelagert werden.
    Wie teile ich jetzt dem Interrupt mit, dass die Variable existiert? Beim Kompilieren beschwert sich der Compiler, dass die Var undefiniert ist. Ich kann die Variable ja schlecht in eine Headerdatei schreiben, wie ich das bei Funktionen machen würde, dann wird die Var ja gleich mehrmals definiert.

    OK, ist irgendwie eher eine Frage zu C-Softwaredesign als zum AVR. Vielleicht hat trotzdem jemand einen Tipp für mich.

    Gruß
    Arne

  2. #2
    Erfahrener Benutzer Robotik Einstein Avatar von SprinterSB
    Registriert seit
    09.06.2005
    Ort
    An der Saar
    Beiträge
    2.801
    Doch

    Die Definition der Vatiablen kommt in eine C-Datei (Modul)

    type_t name1;
    type_t name2 = initializer;

    Die Deklaration kommt in den Header:

    extern type_t name1;
    extern type_t name2;
    Disclaimer: none. Sue me.

  3. #3
    Erfahrener Benutzer Roboter Experte
    Registriert seit
    13.11.2004
    Ort
    München
    Alter
    30
    Beiträge
    447
    Hi,
    Sollte da nicht noch volatile hin?

    MfG Alex

  4. #4
    Erfahrener Benutzer Robotik Einstein Avatar von SprinterSB
    Registriert seit
    09.06.2005
    Ort
    An der Saar
    Beiträge
    2.801
    Nicht unbedingt. Kommt drauf an, was dein type_t ist:


    typedef char volatile type_t;



    Und das volatile ist schon in type_t!
    Disclaimer: none. Sue me.

  5. #5
    Erfahrener Benutzer Roboter Genie
    Registriert seit
    29.05.2005
    Beiträge
    1.018
    Hallo,
    etwas umständlicher mache ich es immer. Dadurch erreiche ich aber, dass ich den Header in allen Sourcen includen kann (Auch im Source, in dem ich die Variable definieren will).
    Das geht bei mir so:
    Im Code mit der main-Funktion steht folgendes:
    Code:
    #define MAIN
    #include "header.h"
    #undef  MAIN
    In allen anderen Sourcen lasse ich "define" und "undef" IMMER weg.

    In der Datei header.h steht dann für alle global zu vereinbarenden Variablen dies hier:
    Code:
    #ifdef MAIN
    #define EXTERN
    #else
    #define EXTERN extern
    #endif
    
    EXTERN int  g_variable_1;
    EXTERN char g_variable_2
    Der Vorteil ist, dass ich die Variable niemals mit verschiedenen Type schreiben kann, da sie ja nur einmal in header.h aufgeführt ist. Somit bekommen ich nie einen Warning wegen falscher typangaben im Source bzw. im Header.

    Für die 'Interruptfesten' Variablen füge ich dann natürlich auch das 'volatile' hinzu.
    Lieber Asuro programieren als arbeiten gehen.

  6. #6
    Erfahrener Benutzer Robotik Einstein Avatar von SprinterSB
    Registriert seit
    09.06.2005
    Ort
    An der Saar
    Beiträge
    2.801
    Mit extern ist es kein Problem, wenn es mehrfach auftauch für die gleiche Variable. Es ist ja eine Deklaration (Bekanntmachung) und keine Definition (Oblekt anlegen)!

    Bewährt hat sich in C/C++ folgendes:
    source.h
    Code:
    #ifndef _SOURCE_H_
    #define _SOURCE_H_
    
    extern int var1;
    extern int volatile var2;
    extern void mache (int volatile * arg);
    
    #define MAKRO(x) ((x)+1)
    
    #endif /* _SOURCE_H_ */
    source.c
    Code:
    #include "source.h"
    
    int var1;
    int volatile var2 = 42;
    
    void mache (int volatile * arg)
    {
       *arg = MACHE (*arg);
    
       var1 = var2;
    }
    Damit sind Makros und globale Variablen unf Funktionen überall benutzbar, wo der Header inkludiert wird.

    Es ist dann auch kein Thema, wenn über verschlungene Umwege ein Header 2 mal inkludiert wird.

    Beispiele sind im Wiki bei den C-Quellen zur genüge.
    Disclaimer: none. Sue me.

  7. #7
    Erfahrener Benutzer Roboter Genie
    Registriert seit
    29.05.2005
    Beiträge
    1.018
    @SprinterSB
    ich denke, dass du in deinem Muster in source.h von den Zeilen
    #ifndef _SOURCE_H_
    #define _SOURCE_H_
    .
    #endif /* _SOURCE_H_ */
    sprichst/schreibst.

    Nicht das wir uns falsch verstehen.
    Ich meinte nicht ein doppeltes includen, auch nicht über verschlungen Pfade (kommt ja doch manchmal vor), sondern das Problem der DEFINITION und DEKLARATION.
    Ich stelle mit meinem #define MAIN (Immer NUR im Source mit der main-Funktion!) nur sicher, dass die globalen Variablen nur GENAU EINMAL dann definiert werden wenn der Source mit der main-Funktion diese Headerdatei includet.

    Das #ifndef ... , welches du beschreibst, ist natürlich ebenso wichtig. Allerdings nur um keine Warnings wegen doppelten defines zu bekommen. Diese Warnings könnten aber auf alle Fälle ignoriert werden, da ja das selbe aus der gleichen Datei defined wird.

    Ich wollte mit meinem Zeug zeigen, dass ich den nicht zu ignorierenden Warning vermeiden kann, wenn ich eben NICHT an 2 Stellen Variablen und deren Datentypen (mal als Definition bzw. als Deklaration) schreiben muss.

    Frage an @SprinterSB: In deinem Beispiel Source.c hast du auch die Funktion mache () mit extern void angegeben.
    Jetzt kommen ich in's schleudern. Ist das OK, oder ist es nicht sogar falsch hier ein extern anzugeben?

    @a//b
    Kleines Muster in einfacher Variante:
    Datei mit main() und deiner Verarbeitung. (z.B.: test.c)
    Code:
    char volatile g_flag; // Hier DEFINIERT
    
    void main ()
    {
       Init ();
       g_flag = 0;
    
       while (1)
       {
          if (g_flag == 1)
          {
             // Tu das was nötig ist, da der Interrupt das Flag gesetzt hat.
             g_flag = 0;
          }
       }
    }
    In deiner Datei mit der Interruptfunktion ist folgendes:
    Code:
    extern char volatile g_flag;  // Nur DEKLARIERT
    
    SIGNAL (????)
    {
       // Nun ist etwas passiert
       g_flag = 1;
    }
    Lieber Asuro programieren als arbeiten gehen.

  8. #8
    Erfahrener Benutzer Robotik Einstein Avatar von SprinterSB
    Registriert seit
    09.06.2005
    Ort
    An der Saar
    Beiträge
    2.801
    Zitat Zitat von Sternthaler
    ich denke, dass du in deinem Muster in source.h von den Zeilen
    #ifndef _SOURCE_H_
    #define _SOURCE_H_
    .
    #endif /* _SOURCE_H_ */
    sprichst/schreibst.

    [...]

    Das #ifndef ... , welches du beschreibst, ist natürlich ebenso wichtig. Allerdings nur um keine Warnings wegen doppelten defines zu bekommen. Diese Warnings könnten aber auf alle Fälle ignoriert werden, da ja das selbe aus der gleichen Datei defined wird.
    ...und bei typedef fliegen wir aus der Kurve, nämlich wenn eine Struktur in mehreren Modulen verwendet werden soll. Ebenso bei inline-Funktionen. Drittens hakt es aus, wenn du einer Variablen einen Initializer geben willst:
    Code:
    extern int foo = 42;
    gibt einen Fehler! Da eine Zeile Code sparen zu wollen ist IMHO an der falschen Stelle gespart.

    Zitat Zitat von Sternthaler
    In deinem Beispiel Source.c hast du auch die Funktion mache () mit extern void angegeben.
    Jetzt kommen ich in's schleudern. Ist das OK, oder ist es nicht sogar falsch hier ein extern anzugeben?
    Nein. Wenn die Funktion static (aufs Modul begrenzt) sein sollte, würde sie nicht im Header stehen, sondern als
    static void mache();
    nur in dem Modul, wo sie gebraucht wird. Für globale (über mehrere Module hinweg) verwendbare Funktionen, gehören Prototypen in die jeweiligen Header. Und zwar im Header zur Quelle, welche die Funktion implementiert.
    Disclaimer: none. Sue me.

  9. #9
    Erfahrener Benutzer Roboter Genie
    Registriert seit
    21.10.2005
    Ort
    Erde
    Alter
    50
    Beiträge
    1.195
    sternthaler, Das Problem kommt doch nur daher, weil Du die Definition der Variablen in einem Header-File machst.

    Common Sense bei C-Programmierung ist aber, die Definition von Variablen (und Funktionen) in einer C-Source, deren Deklaration (einschliesslich der Deklarationsspezifizierer z.B. extern) im Header zu machen.

    Das spart die #ifdefs (mal ganz abgesehen von den Problemen, die Sprinter schon beschrieben hat).

  10. #10
    Erfahrener Benutzer Roboter Genie
    Registriert seit
    29.05.2005
    Beiträge
    1.018
    Zitat Zitat von SprinterSB
    ...und bei typedef fliegen wir aus der Kurve, nämlich wenn eine Struktur in mehreren Modulen verwendet werden soll.
    Kann ich nicht nachvollziehen. Bei mir funktioniert folgendes ohne Probleme in einer in allen Sourcen includeten Headerdatei:
    Code:
    /******************************************************************************
       Typendefinition fuer die Sensoren
    */
    typedef struct {
             unsigned char  aktiv;            // Startet/Stoppt die Sensoren
             unsigned char  taster;           // Tasterwert mit PollSwitch() geholt
             unsigned int   batterie;         // Batteriewert wie Batterie()
             unsigned int   linie [4];        // 0:Links-Dunkel  1:Rechts-Dunkel
                                              // 2:Links-Hell    3:Rechts-Hell
             unsigned int   rad [2];          // Zaehlerwerte der Radencoder
    } sens_t;
    
    #ifdef  MAIN
    #define EXTERN
    #else
    #define EXTERN extern
    #endif
    
    /* Je nach Definition von EXTERN, werden die aufgefuehrten Variablen
       declariert oder definiert.
       Somit kann GENAU EIN SOURCE (Source mit der Main()-Funktion macht Sinn)
       die Variablen 'erstellen', aber alle anderen Sourcen koennen wegen der
       extern-Angabe auch auf die Variable zugreifen.
    */
    EXTERN volatile sens_t   sens;
    EXTERN          int      g_kp;
    EXTERN          int      g_ki;
    EXTERN          int      g_kd;
    Zitat Zitat von SprinterSB
    Ebenso bei inline-Funktionen.
    Da kann ich nicht mitreden, da ich bis jetzt noch nie inline-Code benutzt habe.

    Zitat Zitat von SprinterSB
    Drittens hakt es aus, wenn du einer Variablen einen Initializer geben willst:
    Das ist richtig, hier muss das Programm selbst initialisieren.

    Zitat Zitat von SprinterSB
    Da eine Zeile Code sparen zu wollen ist IMHO an der falschen Stelle gespart.
    Es geht mir nicht um die Zeile Code. Ich will nur sicherstellen, dass die Typen der ZWEI Zeilen Code IMMER identisch sind. Das erhalte ich über mein Konstrukt, da ich ja nur die eine Zeile habe.
    Hier ist das Potenzial für Differenzen, und wenn es nur nachträglich geschieht, dass der Typ der Variablen nur in einem Source geändert wird. Vergisst man, dass es noch den Header gibt, dann bekommt man zwar ein Warning beim Compilieren, aber es ist trotzdem möglich 2 verschiedene Datentypen zu nutzen. OK, wer die Warnings nicht beachtet hat selber Schuld, und wer vergisst, dass es 2 Source-Stellen gibt, ist gut beraten mal Urlaub zu machen. Aber genau dies ist schon immer eine extreme Gefahr bei uns in der Firma gewesen. (Bei dem Krempel von uns handelt es sich so ca. um 4500 Sourcen.)


    Zitat Zitat von SprinterSB
    Nein. Wenn die Funktion static (aufs Modul begrenzt) sein sollte, würde sie nicht im Header stehen, sondern als
    static void mache();
    nur in dem Modul, wo sie gebraucht wird. Für globale (über mehrere Module hinweg) verwendbare Funktionen, gehören Prototypen in die jeweiligen Header. Und zwar im Header zur Quelle, welche die Funktion implementiert.
    Ja, bei static ist mir das schon klar, aber in deinem Beispiel zum source.c hast du als arbeitende Funktion (keine deklaration) diese als extern angelegt. Da wollte ich mal nachfragen, ob bzw. was ich da nicht verstehe.


    @ongni42
    Ne, ne, ich unterscheide ja genau, dass ich nur einmal die Definition mache. Regeln tut das der Code mit dem #define EXTERN. Entweder hat EXTERN keinen 'Inhalt' oder es steht dann zur Deklaration eben doch das 'extern' dahinter.


    OK, ich denke das nun jeder genug hat über dieses Thema zu debatieren. Ich hoffe hier niemandem auf die Füße getreten zu haben und wünsche euch (und mir) weiterhin schönen, fehlerfreien Code.
    Lieber Asuro programieren als arbeiten gehen.

Seite 1 von 2 12 LetzteLetzte

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •