mmoerth:
Das mit der Beschallung des Tasters wusste ich bis jetzt noch nicht.
Na ja, eigentlich Beschaltung und nicht Beschallung.
Jedenfalls müßtest Du mit Deinen Programmen eine Nummer kleiner anfangen!
Man kann sinnvollerweise nicht den dritten Schritt (drei Schalter auswerten) machen, wenn man den ersten Schritt (einen Schalter auswerten) nicht fehlerfrei hinbekommt. Das kann nur in völliger Konfusion und garantierter Fehlfunktion enden.
Anbei mal ein Beispielcode zur Verdeutlichung der Trennung in Eingabe-Verarbeitung-Ausgabe.
Beachte bitte, was in der loop-Funktion drinsteht!
Vielleicht kannst Du Dir für Deine Programme was abgucken.
Zum Verständnis des Codes schaust Du Dir am besten auch mal an, was "static" im Zusammenhang mit einer deklarierten Variablen in einer Funktion bedeutet.
Die Auswertung der Schalter erfolgt so: Reagiert wird immer auf das Drücken eines Schalters, d.h. wenn der vorherige Schalterzustand "nicht gedrückt" war und der Schalter in den Zustand "gedrückt" übergeht. Damit das "Prellen" mechanischer Taster Prellen – Wikipedia nicht zu Fehlfunktionen (Mehrfachzählungen) führt, ist in der loop-Funktion ein kurzes Delay von 5 Millisekunden enthalten, so dass ein Tasterzustand nicht öfter als alle 5 Millisekunden ausgewertet wird.
#include <LiquidCrystal.h>
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
/* in der nachfolgenden Zeile wird festgelegt, ob die Schalter
mit PullUp oder PullDown Widerständen beschaltet sind.
INPUT_PULLUP aktiviert die internen PullUp-Widerstände des Atmega
INPUT setzt voraus, dass die Schalter mit externen PullDown-Widerständen beschaltet sind
*/
#define INPUTMODE INPUT_PULLUP // INPUT_PULLUP oder INPUT setzen
const int minuten_switch = 7;
const int sekunden_switch = 6;
const int start_switch = 8;
int timerLaufzeit = 0;
boolean timerGestartet=false;
void eingabe()
{
static boolean oldMinSwitch=false; // Statische Variable für letzten Schalterzustand
static boolean oldSecSwitch=false; // Statische Variable für letzten Schalterzustand
static boolean oldStartSwitch=false; // Statische Variable für letzten Schalterzustand
boolean MinSwitch= digitalRead(minuten_switch); // aktueller Schalterzustand
boolean SecSwitch= digitalRead(sekunden_switch); // aktueller Schalterzustand
boolean StartSwitch= digitalRead(start_switch); // aktueller Schalterzustand
if (INPUTMODE==INPUT_PULLUP) // Vertauschte Schaltlogik bei PullUp
{
MinSwitch=!MinSwitch; // ausgelesenen Zustand vertauschen wg. PullUp
SecSwitch=!SecSwitch; // ausgelesenen Zustand vertauschen wg. PullUp
StartSwitch=!StartSwitch; // ausgelesenen Zustand vertauschen wg. PullUp
}
if (MinSwitch==HIGH && oldMinSwitch==LOW) timerLaufzeit+=60; // Zustandsänderung gedrückt?
oldMinSwitch=MinSwitch; // aktueller Schalterzustand wird zum alten Schalterzustand
if (SecSwitch==HIGH && oldSecSwitch==LOW) timerLaufzeit++; // Zustandsänderung gedrückt?
oldSecSwitch=SecSwitch; // aktueller Schalterzustand wird zum alten Schalterzustand
if (StartSwitch==HIGH && oldStartSwitch==LOW) timerGestartet=true; // Zustandsänderung gedrückt?
oldStartSwitch=StartSwitch; // aktueller Schalterzustand wird zum alten Schalterzustand
}
void verarbeitung()
{
static unsigned long lastMillis=0; // statischer Zähler für letzten Stand des millis() Timers
static unsigned long timedMillis=0;// statischer Zähler für Millisekunden beim Herunterzählen
unsigned long nowMillis=millis(); // aktueller Stand des millis() Timers
if (timerGestartet && timerLaufzeit>0) // Zähler läuft und Restzeit vorhanden
{
timedMillis+= nowMillis-lastMillis; // Millisekunden hochzählen
if (timedMillis>=1000) // Nach jeweils 1000 Millisekunden
{
timedMillis=0; // Millisekundenzähler auf 0 setzen
timerLaufzeit--; // Eine Sekunde Laufzeit abziehen
if (timerLaufzeit==0) timerGestartet=false; // Timer anhalten
}
}
lastMillis=nowMillis; // Zählerstand merken, bei dem diese Funktion zuletzt lief
}
void ausgabe()
{
int minuten=timerLaufzeit/60; // Ganzzahldivision durch 60
int sekunden=timerLaufzeit%60;// Modulo-Divisionsrecht bei geteilt durch 60
lcd.setCursor(0, 1);
if (minuten < 10) lcd.print("0");
lcd.print(minuten);
lcd.print(":");
if (sekunden < 10) lcd.print("0");
lcd.print(sekunden);
}
void setup() {
lcd.begin(16, 2);
pinMode(minuten_switch,INPUTMODE);
pinMode(sekunden_switch ,INPUTMODE);
pinMode(start_switch, INPUTMODE);
lcd.print("TIMER:");
}
void loop()
{
eingabe();
verarbeitung();
ausgabe();
delay(5); // Kleines Delay zum softwaremäßigen Entprellen der mechanischen Schalter
}
Der Code ist so wie er dasteht für eine Schaltung OHNE PULLDOWN-Widerstände, stattdessen werden die internen PullUps aktiviert. Im Quellcode kann man leicht zwischen INPUT_PULLUP (interne PullUps) oder INPUT (externe PullDowns) wechseln, je nach vorhandener Schaltung.
Bei den internen Variablen verwende ich nicht Minuten und Sekunden getrennt, sondern eine Variable "timerLaufzeit", in der die Timerlaufzeit in Sekunden drinsteht. Wenn man die verschiedenen Buttons drückt, wird diese Variable entweder um 60 Sekunden hochgesetzt (plus 1 Minute) oder um 1 Sekunde, dadurch vermeidet man Umstände beim Minutenwechsel.
Der aktuelle Zählerstand in Minuten und Sekunden wird erst bei der Ausgabe mit Modulo-Arithmetik ausgerechnet, und dann auf dem LCD ausgegeben.
Nur mal so als Demo, wie ein modulares und leicht wartbares Programm aussehen könnte.