Arduino Timer

Hallo,

Ich möchte mit einer 4x7 Segment Anzeige einen 60 Minuten Timer Programmieren. Ich habe mir überlegt wie ich das anstellen könnt und habe versuch eine vierstellige Zahl (in dem Fall 6000) einfach langsam runter laufen zu lassen. Leider Zählt es aber dann immer 100 Sekunden für eine Minute und nicht wie normal 60. Leider weiß ich nicht wie ich das anders machen könnte.

Habt ihr eine Idee was ich machen kann?

1 Sekunde hat 1000 millis() milliSekunden. Danach die Restzeit um 1s erniedrigen und anzeigen lassen. Siehe auch BlinkWithoutDelay Beispiel.

und habe versuch eine vierstellige Zahl (in dem Fall 6000) einfach langsam runter laufen zu lassen.

Das runterzählen ist eine weit verbreitete, leider falsche, Idee.

Aus Startzeit und Jetztzeit, kannst du jederzeit die Differenz berechnen.

Hallo
hier kommt eine Lösung für einen Rückwärtszähler. Der Sketch bleibt bei der Zeit=0 stehen und muss neugestartet werden. In der Zeile static unsigned long zeit = 2 * 60; wird die Startzeit in Minuten*Sekunden programmiert. Der Sketch läuft nicht blockadefrei, da die delay()-Funktion verwendet wird. Viel Spass beim Testen.

void loop() {
  static unsigned long zeit = 2 * 60;
  unsigned long minute;
  unsigned long sekunde;
  minute = zeit / 60;
  sekunde = zeit % 60;
  Serial.print(minute); Serial.print(":"); Serial.println(sekunde);
  while (!zeit);
  zeit--;
  delay (1000);
}

zeit--;

Genau das meinte ich mit:

Das runterzählen ist eine weit verbreitete, leider falsche, Idee.

Was ist an dem Runterzählen so schlimm ?

#include <MobaTools.h>
MoToTimebase ticker;
int zeit;
void setup() {
  Serial.begin( 115200 );
  ticker.setBasetime( 1000 );
  zeit = 60;

}

void loop() {
  // put your main code here, to run repeatedly:
  if  ( ticker.tick() ) {
    Serial.println( zeit-- );
    if ( zeit == 0 ) {
      Serial.println( "Eine Minute vergangen");
      zeit = 60;
    }
  }
}

ticker.tick()

Ich weiß jetzt nicht, wie dein Ticker reagiert, wenn die Anwendung ihn mal 3 Sekunden nicht aufruft...

Bei meiner Methode ist es egal, wie lange irgendwas blockiert.
Die Zeitüberschreitung, wird zum möglichst frühesten Zeitpunkt erkannt.

combie:
Ich weiß jetzt nicht, wie dein Ticker reagiert, wenn die Anwendung ihn mal 3 Sekunden nicht aufruft...

Hmm ja, ist die Frage was man will. Derzeit ist es so, dass er die Pause überspringt um dann im richtigen Takt-Rhythmus zu bleiben - hier also immer die glatten Sekunden. Nach dem Motto: was vorbei ist, ist vorbei. Wobei dann natürlich Takte fehlen.
Edit: und der erste Takt nach der Pause passt dann allerdings auch nicht genau in den Rhythmus .. :frowning:
Alternative wäre, die fehlenden Takte nach den 3 Sekunden möglichst schnell nachzuholen ( wenn wieder schnell genug aufgerufen wird ). Dann stimmt die Gesamtzahl der Takte ( was hier natürlich richtig wäre ), dafür wird aber zu falschen Tickerzeiten ausgelöst - u.U sehr schnell hintereinander, was auch Probleme machen könnte.
Vielleicht sollte man das noch einstellbar machen. Hängt eher von der Anwendung ab, was richtig(er) ist.

Edit: wirklich 'richtig' kann es nicht funktionieren, wenn die Anwendung falsch programmiert ist, und den Ticker nicht häufig genug aufruft.

Nochmal zum ersten Problem.
Zeit zählt in Minuten und Sekunden in 60-ger Schritten.
Zum Runterzählen (für die Restzeit-Anzeige) kann man eine von 2 Lösungen nehmen:

  • man wandelt die Minuten und Sekunden in Sekunden um und zählt diese herunter. Dann braucht man 2 Funktionen: die Sekunden in Minuten-Sekunden umrechen und zurück.
  • man schaut wenn ein Übertrag ansteht zB x100 auf x099 in x059. Am einfachsten ist da 2 Variablen zu haben und wenn die Sekunden 00 erreichen und 1 weggezählt werden soll dann die Minuten um 1 kleiner werden und die Sekunden 59.
sekunden --;
if (sekunden == 99)
  {
  sekunden = 59;
  minuten --;
  if ( minuten < 0)
    Ende erreicht.
  }

Man kann den Wink mit dem Zaunpfahl von combie beherzigen, dann muß man aus der Startzeit, dem Interval und den Millis die Restzeit errechnen und diese als Min - Sek darstellen. Dies hätte den Vorteil daß die Zeit keine Fehler durch nicht zeitgenaues Vermindern der Restzeit aufsummiert.

Grüeß Uwe

Hallo Uwe,

uwefed:

sekunden --;

if (sekunden == 99)
  {

Das mit den 'sekunden == 99' verstehe ich nicht.

uwefed:
Dies hätte den Vorteil daß die Zeit keine Fehler durch nicht zeitgenaues Vermindern der Restzeit aufsummiert.

Da summiert sich bei meinem Ticker auch nichts auf, wenn er - in diesem Fall - häufiger als 1x pro Sekunde aufgerufen wird. Deinen Code könnte man da einfach in die tick() Funktion reinschreiben.

Hallo moritz2405
hast Du dein Arduino Timer Projekt zum Laufen gebracht?

Eine primitive Stoppuhr aus meiner Wühlkiste.
Evtl kann man sich da ja etwas abschauen.

Bedient wird sie mit
r stoppt die Uhr und setzt auf Null (Reset)
s startet die Zeitmessung (ohne Reset)
h stoppt die Zeitmessung (ohne Reset)

OK, das ist jetzt eher ein "Countup", als ein "Countdown",
aber die Hürde sollte zu schaffen sein :o :o :o :o :o :o

class StoppUhr: public Printable
{
  private:
  unsigned long startzeit;
  unsigned long abgelaufenezeit; 
  bool isrunning;

  public:
  void reset()
  {
    isrunning = false;
    startzeit = 0;
    abgelaufenezeit = 0;
  }
  
  StoppUhr()
  {
    reset();
  }
  
  void start()
  {
    if(!isrunning)
    {
      isrunning = true;
      startzeit = millis();
    }
  }
  
  void halt()
  {
    if(isrunning)
    {
      isrunning = false;
      abgelaufenezeit += millis()-startzeit;
    }  
  }
 
  virtual size_t printTo(Print &printer) const
  {
    return printer.print(isrunning?millis()-startzeit+abgelaufenezeit:abgelaufenezeit);
  }
} stoppuhr;


void uhrSteuerung()
{
  switch(Serial.read())
  {
    case 'r':stoppuhr.reset();break;
    case 's':stoppuhr.start();break;
    case 'h':stoppuhr.halt(); break;
  }
}

int bufferSize = 0; // merker fuer FiFo groesse

void serielleAusgabe()
{
  if(bufferSize == Serial.availableForWrite()) // nur schreiben, wenn Buffer ganz leer
  {
    Serial.println(stoppuhr);
  }
} 

void setup() 
{
  Serial.begin(9600);
  bufferSize = Serial.availableForWrite();
}

void loop()  
{
  uhrSteuerung();
  serielleAusgabe();
}

Evtl kann man sich da ja etwas abschauen

// nur schreiben, wenn Buffer ganz leer

Danke, Combie.

Die OT Ideen sind immer interessant.

Dass availableForWrite int zurückliefert, ist natürlich schwach.
Kann leider nicht mehr korrigiert werden.

michael_x:
Dass availableForWrite int zurückliefert, ist natürlich schwach.

Befindet sich aber in guter Gesellschaft :slight_smile:

Auch digitalRead liefert int zurück :fearful:
siehe: ArduinoCore-avr/cores/arduino/Arduino.h at master · arduino/ArduinoCore-avr · GitHub

Die OT Ideen sind immer interessant.

Schön, dass es dir gefällt.

Ziel war, dass Print immer möglichst frische Daten ausgibt und nicht den RingBuffer mit "Vergangenheit" flutet.
Zudem vermeidet es unnütze Blockaden.

Anekdote am Rande
Diese Stoppuhr war einer der Gründe, weswegen der ESP32 Arduino Core um die Methode bereichert wurde.

Zudem vermeidet es unnütze Blockaden.

Wenn Ausgaben NICHT die loop Geschwindigkeit bremsen sollen, aber man trotzdem viel übertragen will, besser als andere Ansätze.

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.