Ich habe einen Arduino Uno und ein lcd keypad shield. Ich möchte gerne einen einstellbaren Countdown haben der zum einen über die Tasten einstellbar ist und die Zeit anzeigt die Abläuft.
Ein bisschen was habe ich schon. Ich kann die Zeit einstellen und der Timer läuft eigentlich auch... Mit einer Einschränkung.
Über die Hoch und Runter Tasten auf dem LCD wähle ich einen Wert in Sekunden aus. Über die Select Taste soll der Timer dann starten und das Runterzählen auf dem Display anzeigen.
Der Timer startet aber ich muss immer wieder die Select Taste drücken damit der Wert aktualisiert wird.
Kann mir von euch jemand etwas helfen? Vielleicht bin ich ja auch ganz verkehrt damit.
Anbei der Code:
#include <LiquidCrystal.h>
#include <Bounce2.h>
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
// define some values used by the panel and buttons
int lcd_key = 0;
int adc_key_in = 0;
int buttonState = 0;
int count_value = 10;
int new_count = 0;
int prestate = 0;
long hour = 23, minute = 59, second = 59;
long countdown_time = (hour*3600) + (minute * 60) + second;
#define btnRIGHT 0
#define btnUP 1
#define btnDOWN 2
#define btnLEFT 3
#define btnSELECT 4
#define btnNONE 5
int read_LCD_buttons(){ // read the buttons
adc_key_in = analogRead(0); // read the value from the sensor
if (adc_key_in > 1000) return btnNONE;
if (adc_key_in < 50) return btnRIGHT;
if (adc_key_in < 195) return btnUP;
if (adc_key_in < 380) return btnDOWN;
if (adc_key_in < 500) return btnLEFT;
if (adc_key_in < 700) return btnSELECT;
return btnNONE; // when all others fail, return this.
}
void setup(){
Serial.begin(9600);
lcd.begin(16, 2); // start the library
lcd.setCursor(0,0); // set the LCD cursor position
lcd.print("3.1 Elektronik"); // print a simple message on the LCD
lcd.setCursor(0,1); // set the LCD cursor position
lcd.print("Set Timer:"); // print a simple message on the LCD
lcd.setCursor(10,1); // set the LCD cursor position
lcd.print(count_value + String("s"));
}
void loop()
{
lcd.setCursor(10,1); // move to the begining of the second line
lcd_key = read_LCD_buttons(); // read the buttons
long countdowntime_seconds = count_value - (millis() / 1000);
switch (lcd_key) // depending on which button was pushed, we perform an action
{
case btnRIGHT:
{
lcd.print("RIGHT ");
break;
}
case btnLEFT:
{
lcd.print("LEFT ");
break;
}
case btnUP:
{
if(count_value != -1) {
lcd.setCursor (11,1);
lcd.print(' ');
}
lcd.setCursor(10,1);
new_count = count_value++;
lcd.print(count_value);
Serial.println(new_count);
delay(250);
break;
}
case btnDOWN:
{
if (count_value < 10){
lcd.setCursor(11,1);
lcd.print(' ');
}
lcd.setCursor(10,1);
new_count = count_value--;
lcd.print(new_count);
Serial.println(new_count);
delay(250);
break;
}
case btnSELECT:
{
lcd.clear();
lcd.setCursor(0,1);
lcd.print("Time left: ");
lcd.setCursor(13,1);
lcd.print("s");
if (btnSELECT == 4){
digitalWrite(btnSELECT, HIGH);
Serial.println(btnSELECT);
delay(200);
if (countdowntime_seconds >=0 ) {
long countdown_hour = countdowntime_seconds / 3600;
long countdown_minute = ((countdowntime_seconds / 60)%60);
long countdown_sec = countdowntime_seconds % 60;
//Serial.println(countdown_sec);
lcd.setCursor(10,1);
lcd.print(countdown_sec);
Serial.println(countdown_sec);
// lcd.setCursor(10,1);
// // if (countdown_sec < 10) {
// // lcd.print("0");
// // }
}
else{
digitalWrite(btnSELECT, HIGH);
}
}
}
}
}
Damit etwas "automatisch" angezeigt wird, müsste das passieren, wenn der Normalfall (btnNONE) vorliegt. Dann aber möglichst nur einmal je Sekunde, damit das Display nicht flackert.
Ein delay(1000) ist aber auch nicht gut, damit man schneller auf Tasteneingabe reagieren kann.
Besser man merkt sich den millis() - Wert, wann der Zähler um 1 runtergezählt (und angezeigt) wurde und macht das, wenn seitdem 1000 ms vergangen sind, wieder.
(Das berühmte BlinkWithoutDelay Beispiel, das nichts mit Blink aber mit WithoutDelay zu tun hat.
In deinem Code ist auch einiges andere merkwürdig
#define btnSELECT 4
...
if (btnSELECT == 4){ // das ist immer erfüllt
digitalWrite(btnSELECT, HIGH); // Pin 4 wird vom LCD verwendet ! ??
Serial.println(btnSELECT); // warum gibst du eine "4" aus ??
Dann würde sich auch anbieten, bei UP/DOWN den Timer anzuhalten, in btnNONE also nur runterzuzählen, wenn zuletzt per btnSELECT der Zähler gestartet wurde.
ArduinoPins sind standardmäßig Eingänge, so dass sie nicht explizit mit pinMode() als Eingänge deklariert werden müssen, wenn man sie als Eingänge verwendet.
bitte poste deinen letzten Stand (voll kompilierbarer Sketch) und beschreibe exakt bei welchem Buttondruck was genau passiert, und was statt dessen passieren soll.
Poste dazu auch die Ausgaben von deiner Seriellen Schnittstelle.
erstmal danke für eure Antworten. Für mich macht es den Eindruck, als würde es zusammen mit dem Display schwierig sein einen vernünftigen Ablauf hinzubekommen.
Hier mal der momentane Code und die Erklärung dazu:
#include <LiquidCrystal.h>
#include <Bounce2.h>
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
// define some values used by the panel and buttons
int lcd_key = 0;
int adc_key_in = 0;
int buttonState = 0;
int count_value = 10;
int new_count = 0;
int prestate = 0;
long hour = 23, minute = 59, second = 59;
long countdown_time = (hour*3600) + (minute * 60) + second;
#define btnRIGHT 0
#define btnUP 1
#define btnDOWN 2
#define btnLEFT 3
#define btnSELECT 4
#define btnNONE 5
int read_LCD_buttons(){ // read the buttons
adc_key_in = analogRead(0); // read the value from the sensor
if (adc_key_in > 1000) return btnNONE;
if (adc_key_in < 50) return btnRIGHT;
if (adc_key_in < 195) return btnUP;
if (adc_key_in < 380) return btnDOWN;
if (adc_key_in < 500) return btnLEFT;
if (adc_key_in < 700) return btnSELECT;
return btnNONE; // when all others fail, return this.
}
void setup(){
Serial.begin(9600);
lcd.begin(16, 2); // start the library
lcd.setCursor(0,0); // set the LCD cursor position
lcd.print("3.1 Elektronik"); // print a simple message on the LCD
lcd.setCursor(0,1); // set the LCD cursor position
lcd.print("Set Timer:"); // print a simple message on the LCD
lcd.setCursor(10,1); // set the LCD cursor position
lcd.print(count_value + String("s"));
}
void loop()
{
lcd.setCursor(10,1); // move to the begining of the second line
lcd_key = read_LCD_buttons(); // read the buttons
long countdowntime_seconds = count_value - (millis() / 1000);
switch (lcd_key) // depending on which button was pushed, we perform an action
{
case btnRIGHT:
{
lcd.print("RIGHT ");
break;
}
case btnLEFT:
{
lcd.print("LEFT ");
break;
}
case btnUP:
{
if(count_value != -1) {
lcd.setCursor (11,1);
lcd.print(' ');
}
lcd.setCursor(10,1);
new_count = count_value++;
lcd.print(count_value);
Serial.println(new_count);
delay(250);
break;
}
case btnDOWN:
{
if (count_value < 10){
lcd.setCursor(11,1);
lcd.print(' ');
}
lcd.setCursor(10,1);
new_count = count_value--;
lcd.print(new_count);
Serial.println(new_count);
delay(250);
break;
}
case btnSELECT:
{
lcd.clear();
lcd.setCursor(0,1);
lcd.print("Time left: ");
lcd.setCursor(13,1);
lcd.print("s");
}
case btnNONE:{
if (btnSELECT == 4){
if (countdowntime_seconds >=0 ) {
long countdown_hour = countdowntime_seconds / 3600;
long countdown_minute = ((countdowntime_seconds / 60)%60);
long countdown_sec = countdowntime_seconds % 60;
//Serial.println(countdown_sec);
lcd.setCursor(10,1);
lcd.print(countdown_sec);
Serial.println(countdown_sec);
lcd.setCursor(10,1);
if (countdown_sec < 10) {
lcd.print("0");
}
}
}
}
}
}
Wenn das Programm startet startet der Timer umgehend und im Display werden die voreingestellten 10 Sekunden runtergezählt.
Danach kann ich über die Hoch und Runtertasten einen Wert einstellen.
Drücke ich dann Setup wird das Display geleert und es steht "Time Left" da aber dann passiert nichts mehr.
Ich hatte erhofft, dass wenn ich den Taster btnSELECT drücke die die if Abfrage startet und der Timer losläuft. Aber er startet ja direkt nach dem Programmstart.
Ok. Dann mal von Anfang.
Du wertest aus, ob btnNone aktiv ist.
willst aber gleichzeitig feststellen, ob btnSELECT aktiv ist. Das geht nicht.
Mehr noch. Die Bedingung btnSELECT == 4 stimmt immer.
Denn Du hast btnSELECT den Wert 4 zugewiesen.
Es wäre auch schlimm, wenn sich der Inhalt verändern würde. Denn dann würde Deine Zuordnung
nicht mehr stimmen.
Nu hast Du für btnSelect aber zwei inhaltliche Funktionen. Sowohl:
Was dafür sorgt, das Du beim drücken des Tasters die Ausgabe auf dem Display erhälst.
und andererseis den Codeteil:
der auch irgendwo untergebracht gehört - aber eben in einer Abhängigkeit und nicht mit der von Dir geschriebenen Bedingung.
Beschreib mal, was Du genau in welcher Reihenfolge mit welchen Tasten machen willst.
Er startet mit 10 sekunden Vorgabe.
Geht mit dem Start in den Countdown.
Mit Ablauf des Countdown oder wenn Du select drückst, geht er in die Einstellung.
Da kannst Du mit auf/ab die Sekunden einstellen udn mit select wieder den countdown starten.
Ist mehr oder weniger eine ausbaufähige Grundstruktur.
Es muss nicht funktionieren.
Kompiliert aber Fehler- und Warnungsfrei.
Wenn was nicht geht, bau Dir serielle Ausgaben ein.
Wenn Du was nicht verstehst, frag.
#include <LiquidCrystal.h>
//#include <Bounce2.h>
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
enum btn {btnRIGHT, btnUP, btnDOWN, btnLEFT, btnSELECT, btnNONE};
enum dis {einstellen, countdown};
constexpr uint32_t oneSecond {1000};
uint32_t countDownSeconds = 10;
uint32_t startZeit;
byte displayType = dis::countdown;
byte myKey = btn::btnNONE;
byte lastKey = myKey;
byte read_LCD_buttons() // read the buttons
{
byte key = btn::btnNONE;
switch (analogRead(0))
{
case 10 ... 40:
key = btnRIGHT;
break;
case 60 ... 180:
key = btnUP;
break;
case 210 ... 350:
key = btnDOWN;
break;
case 380 ... 480:
key = btnLEFT;
break;
case 500 ... 650:
key = btnSELECT;
break;
}
return key;
}
void setup()
{
Serial.begin(9600);
lcd.begin(16, 2); // start the library
lcd.setCursor(0, 0); // set the LCD cursor position
lcd.print("3.1 Elektronik"); // print a simple message on the LCD
lcd.setCursor(0, 1); // set the LCD cursor position
lcd.print("Set Timer:"); // print a simple message on the LCD
lcd.setCursor(10, 1); // set the LCD cursor position
displayCountDown();
startZeit = millis();
}
//
void displayCountDown()
{
lcd.setCursor(10, 1);
if (countDownSeconds < 10)
{
lcd.print(' ');
}
lcd.print(countDownSeconds);
Serial.println(countDownSeconds);
}
//
void loop()
{
myKey = read_LCD_buttons();
switch (displayType)
{
case dis::einstellen:
if (myKey != lastKey)
{
lastKey = myKey;
switch (myKey)
{
case btn::btnUP:
countDownSeconds++;
break;
case btn::btnDOWN:
countDownSeconds--;
break;
case btn::btnSELECT:
displayType = dis::countdown;
startZeit = millis();
break;
if (countDownSeconds >= 100 || countDownSeconds < 10)
{ countDownSeconds = 10; }
displayCountDown();
delay(50); // rudimentärer debounce
}
}
break;
case dis::countdown:
if (millis() - startZeit >= oneSecond)
{
startZeit += oneSecond;
countDownSeconds--;
displayCountDown();
}
if (countDownSeconds == 0)
{ displayType = dis::einstellen; }
if (myKey != lastKey)
{
lastKey = myKey;
switch (myKey)
{
case btn::btnSELECT:
displayType = dis::einstellen;
break;
}
delay(50); // rudimentärer debounce
}
}
}