Forum: Compiler & IDEs SIGNAL + static Var initialisieren


von Dieter (Gast)


Lesenswert?

Hi, zusammen,

habe ein kleines Problem.
In einer Signal-Routine brauche ich einen Zähler, der statisch ist und
vorinitialisiert sein soll:

static uint16_t counter = 1;

Dummerweise ist der bei Programmstart aber eben nicht 1, sondern
aktuell 37900, warum auch immer.
Im aktuellen Programm ist das nicht so schlimmm, ein zeitgesteuerter
Programmteil arbeitet nicht direkt nach dem Einschalten, sondern erst
ca. 8 Sekunden später, aber blöd ist das schon und in anderen Projekten
undenkbar.

Wo liegt da der Fehler und was muss ich anders machen?
Danke!

von OldBug (Gast)


Lesenswert?

Hallo Dieter!

Wo wird denn die Variable deklariert, global oder erst in der ISR?

Gruß,
Patrick...

von Dieter (Gast)


Lesenswert?

Hallo, Patrick,

die Variable wird erst in der ISR deklariert. Habe es auch mit anderen
ausprobiert, da ist es dasselbe.
Kann es sein, dass statische Variablen in ISRs anders behandelt
werden?

Zur Not kann ich auch eine Init-Routine für jede ISR schreiben und die
Variable dann global definieren. Wäre aber nicht so schön.

Grüsse,
Dieter

von OldBug (Gast)


Lesenswert?

Variablen, die erst in einer Funktion deklariert werden, sind ja nicht
global zugreifbar. Sie existieren zwar, dürfen aber NUR von der
Funktion verwendet werden, die sie angelegt hat.
Ich weis jetzt nicht genau, wo Du versuchst, auf diese Variable
zuzugreifen, aber es hört sich danach an, als wolltest Du in einem
anderen Kontext als der ISR darauf zugreifen!

Wenn Du eine globale Variable brauchst, dann muss sie auch global
deklariert werden. static sagt nur aus, daß die Variable beim verlassen
der Funktion - samt Inhalt - erhalten bleibt.

Gruß,
Patrick...

von OldBug (Gast)


Lesenswert?

P.S.: auch Globale Variablen lassen sich "vorinitialisieren",
allerdings macht

static int i = 0;

keinen Sinn, da sie eh mit 0 initialisiert wird.

static int i = 16;

macht dagegen schon schon Sinn, wenn man halt i mit einem Startwert von
16 verwenden möchte.

von Dieter (Gast)


Lesenswert?

Habe mich wohl falsch ausgedrückt.
Ich meinte Folgendes:

SIGNAL(xxx) {
  static uint16_t counter = 1;

  xxx;
}

Dabei wird die Variable counter aber NICHT initialisiert.
Bei einer "normalen" Funktion wird die Variable beim ersten Aufruf
mit dem Wert - hier die 1 - initialisiert.

In der ISR bei mir haben die Variable nur irgendwelche wilden Werte,
habe das mit mehreren ausprobiert.

von Jörg Wunsch (Gast)


Lesenswert?

Selbstverständlich werden diese Variablen wie alle anderen statischen
Variablen initialisiert.

Womit hast Du denn festgestellt, daß sie nicht initialisiert würde?

Hast Du einen Sourcecode, mit dem man das reproduzieren könnte?

Ich sollte mal wieder an Eric Raymonds Artikel erinnern:

http://www.catb.org/~esr/faqs/smart-questions.html

bzw. dessen deutsche Übersetzung:

http://www.lugbz.org/documents/smart-questions_de.html

Besonders hier der Abschnitt ``Don't claim you have found a bug.''

von Dieter (Gast)


Lesenswert?

Hallo,

ich habe in der ISR-Routine die Variable in eine Temp-Variable kopiert
und mir auf einem LCD-Display anzeigen lassen.
Code werde ich heute abend posten.
Und dass der Fehler nicht bei mir liegt, würde ich auch nie
behaupten...
Habe das jetzt nur zwei Tage lang probiert und bin jetzt wohl
problemblind :(

von OldBug (Gast)


Lesenswert?

Poste mal den Code, oder zumindest den Teil des Codes, der die beiden
Variablen anlegt, den Inhalt kopiert und dann ausgibt.

von Dieter (Gast)


Lesenswert?

So, habe mal ein Code-Fragment angehängt:

//********************************************
#include <inttypes.h>
#include <avr/signal.h>
#include <avr/interrupt.h>
#include "timer0.h"
#include "helper.h"
#include "globals.h"
#include "keyboard.h"
#include "lcd4bit.h"


void init_timer0( void ) {
  TCNT0 = 0x00;
  OCR0 = 0xFA;
  TCCR0 |= ( 1<<WGM21 ) | ( 1<<CS01 );    // OutputCompare With
Prescaler 8 => 250µs @ 8MHz
}


//
// Timer Interrupt 0
//
SIGNAL(SIG_OUTPUT_COMPARE0) {      // Output Compare0 Interrupt
  static uint8_t key_pending;
  static uint16_t counter = 1, key_counter, test, tt = 422;
  uint8_t i, key_temp;

if( tt != 345 ) {
  test = counter;
  tt = 345;
}

// Increment Counter
  counter++;


// 1s Counter
  if( counter == 4000 ) {
  // Update Real Time Clock
    if( ++clock.second == 60 ) {
      if( ++clock.minute == 60 ) {
        if( ++clock.hour == 24 ) {
          clock.hour = 0;
        }
        clock.minute = 0;
      }
      clock.second = 0;
    }
    counter = 1;
  }

// Keyboard Scan + Debouncing
  [xxx];
// End Of IRQ
}

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


Der Effekt ist, dass aufgrund der Nichtinitialisierung die
Tastenfeldabfrage und die Echtzeituhr erst später loslaufen. Im
aktuellen Fall ca. 8 Sekunden später, da der Zähler nicht bei 1 startet
sondern bei genau 37900.

von Jörg Wunsch (Gast)


Lesenswert?

Ich kann da erstmal keinen offensichtlichen Fehler erkennen.
Vielleicht hast Du eine Kollision mit dem Stack?

Der Schnipsel genügt leider auch nicht für ein sinnvolles
Test-Compile.

Davon abgesehen, wenn Du die Variable nicht mit 1 initialisierst, wird
sie implizit als 0 initialisiert.  Zählweitenbegrenzung stattdessen
auf 3999 setzen, schon hast Du 2 Bytes ROM für die Initialwerte
gespart. ;-)

Andere Falle: eventuell wird Deine ISR auch zu lang?  Wenn Du da drin
noch keyboard scan + debounce machst, vielleicht bist Du ja schon an
Deinen 250 µs ran?

von Dieter (Gast)


Lesenswert?

Danke für die Antwort.
An eine Stackkollision glaub ich nicht. Ich verbrauche für die Vars und
Puffer ca. 500 Byte eines Mega16. Da sollte genug übrig sein.

Die ISR ist auch recht kurz. Sie funktioniert ja auch, nur dass sie
halt mit einem zu hohem counter-Wert startet und somit erst nach ca. 8
Sekunden das erste Mal in die Echtzeituhr-Routine kommt.

Allerdings habe ich es jetzt mit Deinem Tip probiert und die implizite
Initialisierung und die Abfrage auf 3999 gemacht - siehe da, es
funktioniert!
Damit bin ich vorerst glücklich, aber ich wüsste trotzdem, warum es so
nicht geht (falls ich mal andere Werte brauch und es nicht umständlich
über globale Vars machen möchte).

Dankeschön erstmal!

von Jörg Wunsch (Gast)


Lesenswert?

Womit testest Du?  Reales Device oder Simulator?

Wie erstellst Du die Ladedatei für den Controller bzw. den Simulator?

Mir dünkt, daß Du vergißt, die Initialwerte für .data mitzugeben...
Die Initialisierung mit 0 funktioniert trotzdem, da die Variable dann
im .bss ist und das immer ausgenullt wird beim Programmstart.

von Dieter (Gast)


Lesenswert?

Ich benutze eine reale Schaltung.
Das Makefile habe ich mit Deinem mfile-Tool erstellt und ich flashe den
MC mit Ponyprog (über das Makefile, nach einer hier vor einiger Zeit
geposteten Kommandozeile).

Ich werde das aber überprüfen, wenn ich am Donnerstag abend zurück bin.
Danke schonmal!

von Jörg Wunsch (Gast)


Lesenswert?

Damit sollte eigentlich wirklich alles im grünen Bereich sein.

Ggf. würde ich mir das Ganze nochmal komplett angucken, wenn Du gar
nicht klarkommst.

von Christian Schifferle (Gast)


Lesenswert?

P.S. static-Variablen werden nicht auf dem Stack abgelegt.

Gruss
Christian

von Jörg Wunsch (Gast)


Lesenswert?

Ja, und?

Wenn Dein Stack mit dem statisch zugewiesenen Bereich kollidiert, hast
Du dennoch `random garbage' in denen drin.  Genau darumg ging's ja.

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.