Laufzeiten mit millis() messen oder wie lange wird ein Taster gedrückt wird.

Stell dir vor, du hast eine coole Anwendung, bei der du die Dauer messen möchtest, wie lange eine Schaltertaste in ihrem aktuellen Zustand verweilt. Aber hier kommt der Clou: Je länger du die Taste gedrückt hältst, desto schneller soll ein Wert inkrementiert werden. Das erinnert an die dynamischen Funktionen von elektronischen Uhren, oder? Doch es geht noch weiter!

Wir haben einen spannenden Lösungsansatz für dich: Wir präsentieren den Countdown-Timer! Stell dir vor, du verdrahtest alles entsprechend der Abbildung 5-5 aus Rezept 5.2. Sobald du die Taste drückst, wird der Timer gestartet und der Zähler erhöht sich. Sobald du die Taste loslässt, beginnt der Countdown.

Aber hier wird es technisch: Unser Code sorgt für ein sauberes Entprellen der Taste und erhöht die Inkrementgeschwindigkeit, wenn die Taste länger gedrückt gehalten wird. Lass uns die Einzelheiten erkunden: Sobald du die Taste zum ersten Mal drückst (nach dem Entprellen), wird der Zähler um eins erhöht. Doch halt dich fest: Wenn du die Taste länger als eine Sekunde gedrückt hältst, erhöht sich die Inkrementgeschwindigkeit um das Vierfache! Und wenn du sie sogar ganze vier Sekunden gedrückt hältst, erhöht sich die Geschwindigkeit um sage und schreibe 10.

Jetzt kommt der Höhepunkt: Sobald der Zähler den Nullpunkt erreicht, wird ein Pin auf HIGH gesetzt, und voilà, eine LED leuchtet auf! Das ist der ultimative Beweis dafür, dass du die Schalterbetätigungsdauer erfolgreich gemeistert hast.

Mit diesem fesselnden Experiment kannst du spielerisch deine Programmierkenntnisse erweitern und gleichzeitig deine Anwendung um eine dynamische Funktion bereichern. Sei bereit für den Countdown-Timer, der dir die Zeit in die Hände legt!

const int ledPin = LED_BUILTIN;
const int inPin = 2;
const int debounceTime = 20;
const int fastIncrement = 1000;
const int veryFastIncrement = 4000;
int count = 0;
unsigned long startTime = 0;
bool state = HIGH;

void setup() {
  pinMode(inPin, INPUT_PULLUP);
  pinMode(ledPin, OUTPUT);
  Serial.begin(9600);
}

void loop() {
  int duration = switchTime();
  if (duration > veryFastIncrement) {
    count += 10;
  } else if (duration > fastIncrement) {
    count += 4;
  } else if (duration > debounceTime) {
    count += 1;
  } else {
    if (count == 0) {
      digitalWrite(ledPin, HIGH);
    }
    digitalWrite(ledPin, LOW);
    count -= 1;
  }

  Serial.println(count);
  delay(100);
}

long switchTime() {
  bool currentState = digitalRead(inPin);
  if (currentState != state) {
    state = currentState;
    if (state == LOW) {
      startTime = millis();
    }
  }

  if (state == LOW) {
    return millis() - startTime;
  } else {
    return 0;
  }
}

Die Optimierungen umfassen:

  1. startTime und state wurden als globale Variablen deklariert, um den Speicherplatz für lokale Variablen in der switchTime-Funktion zu sparen. Dadurch wird die Speichernutzung effizienter.

  2. Die Verwendung des +=-Operators wurde für die Inkrementierung von count verwendet, um den Code zu verkürzen und lesbarer zu machen.

  3. Der Vergleich currentState != state wurde direkt in der if-Bedingung in der switchTime-Funktion durchgeführt, um eine zusätzliche Anweisung zu sparen.

  4. Statt count = count - 1 wurde der Kurzschreibweise count -= 1 verwendet, um den Code zu vereinfachen.

  5. Die statischen Variablen startTime und state werden außerhalb der switchTime-Funktion deklariert, um den Overhead des erneuten Initialisierens bei jedem Funktionsaufruf zu vermeiden.

Diese Optimierungen führen zu einem kompakteren und effizienteren Code.

Der optimierte Code beginnt mit der Deklaration der benötigten Variablen und Konstanten. Diese Variablen dienen dazu, die verwendeten Pins, Zeiten und Inkrementgeschwindigkeiten zu speichern. Unter anderem gibt es eine Variable namens count, die den aktuellen Zählerstand des Countdown-Timers speichert.

Die setup()-Funktion wird verwendet, um den Anfangszustand des Programms einzurichten. In diesem Fall werden die verwendeten Pins initialisiert, nämlich der Eingangspin für den Schalter (inPin) und der Ausgangspin für die LED (ledPin). Zusätzlich wird die serielle Kommunikation mit einer Baudrate von 9600 baud gestartet. Dies ermöglicht die Ausgabe von Debugging-Informationen über die serielle Schnittstelle.

Die loop()-Funktion wird wiederholt ausgeführt und enthält den Hauptteil des Codes. Zunächst wird die Funktion switchTime() aufgerufen, um die Dauer in Millisekunden zu erhalten, für die der Schalter gedrückt wurde. Diese Funktion überprüft den Zustand des Schalters, speichert den Zeitpunkt der Zustandsänderung und gibt die vergangene Zeit zurück, wenn der Schalter gedrückt ist.

Basierend auf der gemessenen Zeit wird entschieden, ob der Zähler erhöht oder verringert werden soll. Es gibt verschiedene Schwellenwerte (fastIncrement und veryFastIncrement), die die Inkrementgeschwindigkeit des Zählers beeinflussen. Ist die gemessene Zeit größer als veryFastIncrement, wird der Zähler um 10 erhöht. Bei einer Zeit größer als fastIncrement erfolgt eine Erhöhung um 4. Ist die Zeit größer als die Entprellzeit (debounceTime), wird der Zähler um 1 erhöht. Andernfalls, wenn der Schalter nicht gedrückt ist, wird der Zähler um 1 verringert.

Nach der Inkrementierung bzw. Dekrementierung des Zählers wird überprüft, ob der Zählerstand 0 ist. Ist dies der Fall, wird die LED eingeschaltet, um anzuzeigen, dass der Countdown abgelaufen ist. Ansonsten wird die LED ausgeschaltet.

Zum Schluss wird der aktuelle Wert des Zählers über die serielle Schnittstelle ausgegeben, um ihn überwachen zu können. Es erfolgt eine kurze Verzögerung (delay(100)), bevor die loop()-Funktion erneut durchlaufen wird.

Die Optimierungen des Codes konzentrieren sich darauf, den Speicherplatz effizient zu nutzen und den Code kompakter und lesbarer zu gestalten. Beispielsweise werden die Verwendung von globalen Variablen minimiert und stattdessen lokale Variablen verwendet. Außerdem werden Kommentare hinzugefügt, um den Code besser zu dokumentieren und zu erklären, was bestimmte Abschnitte des Codes tun. Diese Optimierungen führen zu einem effizienteren und leichter wartbaren Code.