Diese Seite ist auch in 2 anderen Sprachen verfügbar.
Sprache wechseln  

volatile

[Data Types]

Beschreibung

volatile ist ein Variablenkennzeichner. Dieser wird normalerweise vor dem Datentyp der Variable angegeben. Der Compiler behandelt je nach Kennzeichner dann die Variable auf andere Art.

Eine volatile- Variable ist eine Direktive für den Compiler. Der Compiler ist eine Software, die deinen C/C++-Code in Maschinencode übersetzt, der dann die "richtigen" Anweisungen für den Arduino enthält.

Im Detail zeigt volatile dem Compiler, dass er die Variable aus dem RAM und nicht aus dem Speicherregister laden soll. Unter bestimmten Bedingungen können die Variablen in den Registern ungenau sein.

Eine Variable sollte als volatile deklariert werden, wenn sie von irgendwo anders geändert werden kann außer in dem Codeteil, in dem sie auftaucht. Beispiele dafür sind Threads, die parallel ausgeführt werden. Im Arduino kann das nur bei Interrupts vorkommen, in sogennanten Interrupt Service Routinen.

int oder long volatile Variablen

Wenn die Variable größer als Byte ist (also z.B. ein 16-Bit-Integer oder ein 32-Bit-Long), kann der Mikrocontroller sie nicht in einem Durchgang lesen, da es ein 8-Bit-Mikrocontroller ist. Das bedeutet, das während das Hauptprogramm die ersten 8 Bit der Variable liest, kann der Interrupt bereits die zweiten 8 Bit geändert haben. Das kann zufällig und unvorhersehbare Ergebnisse liefern.

Gegenmaßnahme:

Während die Variable gelesen wird, müssen Interrupts deaktiviert werden, sodass diese die Bits nicht verändern können während sie gelesen werden.

Es gibt mehrere Möglichkeiten, das zu tun:

  1. SPRACHE noInterrupts

  2. Das ATOMIC_BLOCK-Makro. Atomare Operationen sind einzelne MCU-Operationen-Die kleinste mögliche Einheit.

Beispielcode

Der Modifikator volatile stellt sicher, dass Änderungen an der Variablen state sofort in loop() sichtbar sind. Ohne den Modifikator volatile kann die Variable state beim Eingeben der Funktion in ein Register geladen werden und wird erst nach Beendigung der Funktion aktualisiert.

// Die LED wird angeschaltet, wenn der Interrupt-Pin den Status ändert.
volatile byte changed = 0;

void setup() {
  // Deklariere den LED-Pin als Output-Pin
  pinMode(LED_BUILTIN, OUTPUT);
  // Setze einen Interrupt
  attachInterrupt(digitalPinToInterrupt(2), toggle, CHANGE);
}

void loop() {
  if (changed == 1) {
    // toggle() wurde vom Interrupt aus aufgerufen!
    // changed auf 0 zurücksetzen
    changed = 0;
    // LED für 200 ms blinken lassen
    digitalWrite(LED_BUILTIN, HIGH);
    delay(200);
    digitalWrite(LED_BUILTIN, LOW);
  }
}

void toggle() {
  // Invertiere den Status, dass die LED blinkt
  changed = 1;
}

Verwenden Sie das Makro ATOMIC_BLOCK, um auf eine Variable zuzugreifen, deren Größe größer ist als der 8-Bit-Datenbus des Mikrocontrollers. Das Makro stellt sicher, dass die Variable in einer atomaren Operation gelesen wird, d.H. ihr Inhalt kann nicht geändert werden, während sie gelesen wird.

#include <util/atomic.h> // Diese Bibliothek fügt das ATOMIC_BLOCK-Makro ein.
volatile int input_from_interrupt;

// Irgendwo im Code, z.B. in loop()
ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
  // Code mit geblockten Interrupts hier (Mehrere atomare Operationen hintereinander werden nicht durch Interrupts unterbrochen)
  int result = input_from_interrupt;
}

Siehe auch