Hallo Leute,
ich möchte einen Intervalltimer programmieren. Dazu habe ich einen Arduino Nano und ein LCD I2C 16x2 Display verwendet. Den Code habe ich mit Chat-GPT erstellt und teilweise selber angepasst.
Mein Ziel ist es mit fünft Buttons durch die Zeilen des Displays zu navigieren und die Rundenzeit, Pausenzeit und Rundenanzahl mit den Buttons HOCH und RUNTER, LINKS und RECHTS einstellen zu können.
Ich bin jetzt so weit gekommen, dass die Zeiten richtig ablaufen und auch der Buzzer ertönt, wenn die Zeiten vorbei sind.
Jetzt möchte ich mit dem Cursor aber nur an die Stellen springen die für die Zeit/Rundeneinstellung relevant sind. Der Cursor bewegt sich aber von selbst durch die Zeilen, sobald ich den Button ein Mal gedrückt habe. Erkennt er nicht, dass der Button nicht mehr gedrückt ist?
Im Bild seht ihr grob meinen Aufbau und was das Display anzeigt.
Ziel ist es:
- Mit den 5 Buttons an die Zeitangaben zu navigieren und diese einzustellen
- Mit dem mittleren Button den Timer starten/stoppen/neustarten
Habt ihr vielleicht eine bessere Idee, wie man das realisieren könnte? Eventuell mit einem anderen Button oder anderer Hardware? Ich stelle mir diese Funktion sehr einfach vor, aber es scheint als wäre es doch nicht so leicht. Zumindest auf diesem Weg.
#include <Wire.h>
#include <hd44780.h>
#include <hd44780ioClass/hd44780_I2Cexp.h>
hd44780_I2Cexp lcd(0x27);
const int LCD_COLS = 16;
const int LCD_ROWS = 2;
const int cursorButtonPin = 5;
int cursorPositionX = 5;
int cursorPositionY = 0;
bool cursorButtonState = LOW;
bool lastCursorButtonState = LOW;
unsigned long lastDebounceTime = 0;
unsigned long debounceDelay = 50;
const int rundenZeit = 5; // Rundenzeit in Sekunden
const int pausenZeit = 5; // Pausenzeit in Sekunden
const int rundenAnzahl = 2; // Anzahl der Runden
int aktuelleRunde = 1;
unsigned long rundenStartzeit;
unsigned long pausenStartzeit;
bool inRundenzeit = true;
const int buzzerPin = 9;
void ertoneBuzzer() {
tone(buzzerPin, 2500); // Ton mit 2500Hz abspielen
delay(1000); // 1 Sekunde warten
noTone(buzzerPin); // Ton ausschalten
delay(500); // 0.5 Sekunden Pause nach dem Ton
}
void setup() {
lcd.begin(LCD_COLS, LCD_ROWS);
lcd.setCursor(0, 0);
lcd.print("Zeit");
lcd.setCursor(11, 0);
lcd.print("Runde");
lcd.setCursor(0, 1);
lcd.print("Ruhe");
lcd.setCursor(12, 1);
lcd.print(aktuelleRunde);
lcd.setCursor(14, 1);
lcd.print(rundenAnzahl);
lcd.setCursor(13, 1);
lcd.print("/");
// Pausenzeit von Anfang an anzeigen
anzeigeZeit(5, 1, pausenZeit);
rundenStartzeit = millis(); // Startzeit für die erste Runde
pausenStartzeit = millis(); // Startzeit für die erste Pause
pinMode(buzzerPin, OUTPUT);
pinMode(cursorButtonPin, INPUT);
}
void loop() {
// Tastenstatus lesen und entprellen
int reading = digitalRead(cursorButtonPin);
if (reading != lastCursorButtonState) {
lastDebounceTime = millis();
}
if ((millis() - lastDebounceTime) > debounceDelay) {
if (reading != cursorButtonState) {
cursorButtonState = reading;
if (cursorButtonState == HIGH) {
moveCursor();
delay(200); // Kurze Verzögerung, um das Springen zu erleichtern
}
}
}
lastCursorButtonState = reading;
unsigned long aktuelleZeit = millis();
// Rundenzeit
int verbleibendeRundenzeit = rundenZeit - (aktuelleZeit - rundenStartzeit) / 1000;
int verbleibendePausenzeit = pausenZeit - (aktuelleZeit - pausenStartzeit) / 1000;
if (inRundenzeit) {
// Zeige die Rundenzeit an, auch wenn sie abgelaufen ist
anzeigeZeit(5, 0, max(0, verbleibendeRundenzeit));
// Wenn die Rundenzeit abgelaufen ist
if (verbleibendeRundenzeit == 0) {
if (aktuelleRunde < rundenAnzahl) {
// Wechsle zur Pausenzeit für alle Runden außer der letzten
inRundenzeit = false;
pausenStartzeit = millis(); // Startzeit für die Pausenzeit zurücksetzen
anzeigeZeit(5, 0, rundenZeit);
ertoneBuzzer(); // Buzzer für 1 Sekunde ertönen lassen
} else {
// Direkt zum Ende, wenn die letzte Runde abgeschlossen ist
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("ENDE!");
tone(buzzerPin, 2500); // Ton mit 2500Hz abspielen
delay(300); // 0.3 Sekunden warten
noTone(buzzerPin); // Ton ausschalten
delay(200); // 0.2 Sekunden warten
tone(buzzerPin, 2500); // Ton mit 2500Hz abspielen
delay(400); // 0.4 Sekunden warten
noTone(buzzerPin); // Ton ausschalten
delay(500); // 0.5 Sekunden warten
tone(buzzerPin, 2500); // Ton mit 2500Hz abspielen
delay(1000); // 1.0 Sekunden warten
noTone(buzzerPin); // Ton ausschalten
while (true) {
// Hier könnten zusätzliche Aktionen nach dem Abschluss erfolgen
}
}
}
} else {
anzeigeZeit(5, 1, max(0, verbleibendePausenzeit));
// Wenn die Pausenzeit abgelaufen ist
if (verbleibendePausenzeit == 0) {
inRundenzeit = true;
aktuelleRunde++;
lcd.setCursor(12, 1);
lcd.print(aktuelleRunde);
anzeigeZeit(5, 1, pausenZeit);
ertoneBuzzer(); // Buzzer für 1 Sekunde ertönen lassen
rundenStartzeit = millis(); // Startzeit für die nächste Runde zurücksetzen
}
}
}
void moveCursor() {
// Bewege den Cursor nach rechts
cursorPositionX++;
if (cursorPositionX >= LCD_COLS || !isAllowedPosition(cursorPositionX, cursorPositionY)) {
cursorPositionX = 5;
cursorPositionY = (cursorPositionY + 1) % LCD_ROWS;
}
// Setze den Cursor an die neue Position
lcd.setCursor(cursorPositionX, cursorPositionY);
lcd.blink(); // Cursor blinken lassen
}
bool isAllowedPosition(int x, int y) {
// Überprüfe, ob die Position erlaubt ist
int allowedX[] = {5, 6, 7, 8, 9, 5, 6, 7, 8, 9, 14};
int allowedY[] = {0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1};
for (int i = 0; i < sizeof(allowedX) / sizeof(allowedX[0]); i++) {
if (x == allowedX[i] && y == allowedY[i]) {
return true;
}
}
return false;
}
void anzeigeZeit(int position, int zeile, int zeit) {
int minuten = zeit / 60;
int sekunden = zeit % 60;
lcd.setCursor(position, zeile);
if (minuten < 10) lcd.print("0");
lcd.print(minuten);
lcd.print(":");
if (sekunden < 10) lcd.print("0");
lcd.print(sekunden);
}