Uhrentaster , interrupts, while (????) {....}

ich habe eine binäruhr die mir sekunden.minuten und stunden anzeigt. Das habe ich mittels 3 schieberegister gelöst, das läuft.

Nun möchte ich aber während des laufenden betriebs die uhrzeit umstellen.

Dafür habe ich 2 Taster (schwarz und grün). Wird einer der Taster grückt wird eine interrupt ausgelöst, der mir dann wiederrum Flags setzt.
Wird der Taster schwarz 1x gedrückt, wechselt das Programm vom Normalbetrieb(statusBlack = 0) in den Stundenmodus.(statusBlack = 1) Nun kann mit dem grünen Taster duch drücken die gewünschte stunde eingestellt werden. Erneutes drücken von schwarz wechselt in den Minutenmodus(statusBlack = 2) und mit dem grünen Taster kann die gewünschte Minute eingestellt werden. Erneutes Drücken von Schwarz "speichert " die neue Zeit und wechselt in den Normalmodus(statusBlack = 0) und die Uhr läuft mit dieser Zeit nun weiter. wird im Normalmodus grün gedrückt passiert gar nichts.
soweit so gut

Mein Programmtechnisches Problem ist nun aber...

befindet sich mein programm nicht im normalmodus also statusBlack = 1 oder statusBlack = 2, dann soll er in den Normalmodus zurückkehren, wenn entweder statusBlack = 0 passiert oder 5 Sekunden lang keine Taste gedrückt wurde. und mit diesen 5 Sekunden habe ich ein problem, wie kann ich es programmiertechnisch umsetzten zu überprüfen ob zwischen 2 interrupts mehr als 5 sekunden vergangen sind. Denn wenn ja, dann soll er nicht die neue Zeit speichern sonder wieder in den Normalmodus wechseln und mit der alten Zeit weiterzählen.

int greenPin = 2;
int blackPin = 3;


int interruptNumberGreen = 0;
int interruptNumberBlack = 0;
volatile int statusBlack = 0;
volatile int statusGreen = 0;

void setup() {
  //Pin-modus Eingang
  pinMode(greenPin, INPUT);
  pinMode(blackPin, INPUT);
  //Interrupts
  attachInterrupt(interruptNumberGreen, interruptGreen, RISING); // RISING FALLING CHANGE LOW
  attachInterrupt(interruptNumberBlack, interruptBlack, RISING);
}

void interruptGreen(){
}
/*
statusBlack
0=normalbetrieb
1=Modus stunde einstellen
2=Modus Minute einstellen
*/
void interruptBlack(){
  if (statusBlack==0){
    statusBlack = 1;    
    }  
  if (statusBlack==1){
    statusBlack = 2;    
    }
  if (statusBlack==2){
    statusBlack = 0;    
    }
}

void loop() 
{
  if (statusBlack!=0)
  {
    zeitBlackDavor=millis();
/*
Hier liegt mein Problem, der Code hier ist noch nicht fertig
*/
    while ((abs(zeitBlackJetzt-zeitBlackDavor)<(sekunde*5))/* oder....*/)
    {
       zeitBlackJetzt=millis(); 
       Serial.println("jo");
    }
    statusBlack=0;
  }
// problem ende
  
  if (statusBlack==0)
  {
// uhrzeit berechnung und ausgabe jede sekunde (mit millis())
  }
}

Zuerstmal ist die Interruptabfrage der Tasten nicht notwendig. Es genügt ein einfaches regelmäßiges digitalRead().

Das updaten der Led jede 5 Sekunden dafst du nicht mit While triggern sondern mit einem if

if( modus ==0 && (zeitBlackJetzt-zeitBlackDavor)>(sekunde*5)) // zeitanzeigemodus
{ neue Zeit ausgeben}

if(digitalread(greenPin)==HIGH)
modus = 1 // zeiteinstellmodus

Grüße Uwe

darkangel1208:
Dafür habe ich 2 Taster (schwarz und grün). Wird einer der Taster grückt wird eine interrupt ausgelöst, der mir dann wiederrum Flags setzt.

Warum vergeht alleine im deutschsprachigen Teil des Forums keine Woche, in der nicht gleich mehrere Programmieranfänger der Meinung sind, dass man zusätzliche selbst programmierte "Interrupts" in einem Sketch braucht, um so langsame Signale wie manuell gedrückte Tastschalter auszuwerten und zu verarbeiten?

Das ist doch absolut nervig, wenn Anfänger immer wieder komplizierte Programme "mit Interrupts" schreiben wollen, wo ein einfaches Programm "ohne Interrupts" viel eher angebracht wäre. Du bist doch diese Woche bereits der Dritte oder so, der mit demselben Quatsch "Interrupts zur Tasterabfrage" hier aufschlägt.

:-X Muss man eigentlich nichts mehr zu sagen. :smiling_imp:

millis() hat der TE ja bereits entdeckt, nur etwas falsch angewendet. So wie es Uwe schreibt, dürfte es gehen.

jurs:
Warum vergeht alleine im deutschsprachigen Teil des Forums keine Woche, in der nicht gleich mehrere Programmieranfänger der Meinung sind, dass man zusätzliche selbst programmierte "Interrupts" in einem Sketch braucht, um so langsame Signale wie manuell gedrückte Tastschalter auszuwerten und zu verarbeiten?

Das ist doch absolut nervig, wenn Anfänger immer wieder komplizierte Programme "mit Interrupts" schreiben wollen, wo ein einfaches Programm "ohne Interrupts" viel eher angebracht wäre. Du bist doch diese Woche bereits der Dritte oder so, der mit demselben Quatsch "Interrupts zur Tasterabfrage" hier aufschlägt.

Vieleicht sollte man delay() aus allen Tutorials verbannen und dadurch würde millis() besser erklährt und verstanden. Dadurch würden Anfänger sofort auf die richtige Spur geschickt.

Grüße Uwe

uwefed:
Vieleicht sollte man delay() aus allen Tutorials verbannen und dadurch würde millis() besser erklährt und verstanden. Dadurch würden Anfänger sofort auf die richtige Spur geschickt.

Vielleicht sollte man "delay()" auch aus allen Beispielprogrmamen verbannen, die zur IDE mitgeliefert werden?

Ich wäre sofort dabei, neue Beispielprogramme für "Files - Examples" zu schreiben, damit diese vollständig

  • blockierungsfrei ohne "delay()" funktionieren
    und
  • mit nullterminierten C-Strings statt mit String-Objekten arbeiten

wenn ich das von uwe verwende, wäre das ganze dann so

void loop() {

if( modus ==0 && (zeitBlackJetzt-zeitBlackDavor)>(sekunde*5))  // zeitanzeigemodus
  { neue Zeit ausgeben}

if(digitalread(blackPin)==HIGH) //1. mal drücken
  modus = 1  // zeiteinstellmodus

if(digitalread(blackPin)==HIGH) //2. mal drücken
  modus = 2 // zeiteinstellmodus

if(digitalread(blackPin)==HIGH) //3. mal drücken
  modus = 0  // zurück zu normal
}

naja das geht ja nicht, dann etwas anders halt

void loop() {

if( modus ==0 && (zeitBlackJetzt-zeitBlackDavor)>(sekunde*5))  // zeitanzeigemodus
  { neue Zeit ausgeben}

if(digitalread(blackPin)==HIGH) //1. mal drücken
{
  if(modus == 0)
  modus = 1  // zeiteinstellmodus stunde

  if(modus == 1)
  modus = 2 // zeiteinstellmodus minute

  if(modus == 2)
  modus = 0  // zurück zu normal
}
}

hmm was mach ich jetzt wenn da jemand mal etwas länger auf den knopf drückt als wie das programm von der einen if(modus == 0) bis zur nächsten if(modus == 1) gekommen ist, also der user bis dahin den knopf nicht wieder losgelassen hat?

ohne interput wüsste ich es nicht zu lösen und inwiefern habe ich millis() falsch benutzt??

Du mußt den Taster nicht auf HIGH kontrollieren, sondern ob er das erste mal gedrückt wurde und ein kleines delay(10) hier darf man das!! einfügen zum Entprellen.

Grüße Uwe

Mal wieder ein bisschen Generelles Gemecker:

delay() ist Mist, das ist klar.
Wird aber nicht durch millis() ersetzt, wennschon durch if (millis() - startzeit > WARTEZEIT) !

Statt dessen muss die Zustandsführung sehr gut überlegt werden. Und dazu gehört bei Tastern, ob ein Taster gerade neu betätigt (oder losgelassen) wurde und ob diese Änderung schon verarbeitet ist.

Das wichtigste ist generell die Definition der Variablen zur Zustandsführung und die Bedeutung jedes Werts.

if (modus == 0) ist z.B. sehr nichtssagend, auch für den Ersteller selbst, nach einem Monat.
enum {NORMAL, MINUTESTELLEN, STUNDESTELLEN} modus; ist die Variablendefinition und damit das, worauf es ankommt. Und kommt so sogar ohne Kommentartext aus. :wink:

Dazu brauchst du noch ein bool alterTasterZustand, um zu erkennen, dass der Taster neu betätigt wurde und du z.B. von modus==NORMAL auf modus=MINUTESTELLEN umschalten sollst.

Und übrigens, bei:

if(digitalread(blackPin)==HIGH) //1. mal drücken
{
  if(modus == 0)
  modus = 1  // zeiteinstellmodus stunde

  if(modus == 1)
  modus = 2 // zeiteinstellmodus minute

  if(modus == 2)
  modus = 0  // zurück zu normal
}

kommt natürlich IMMER modus=0 raus, das solltest du unbedingt anders lösen!