Timer funktion verständlich erklärt/ hilfe

Hallo!
Ich habe in der Hochschule ein Projekt bekommen, was ich auf einem Arduino Mega 2560 programmieren soll - ein Reaktionsspiel.

Grundsätzlich soll der Ablauf so aussehen:

1 Zufallszahl zwischen 1...9 wird generiert
2 digitaler Ausgang der Zufallszahl soll auf 1 gesetzt werden --> LED leuchtet [hier hätte ich gern die erste Zeit abgefragt = "t1"]
3 dann wird eine vordefinierte Reaktionszeit "tr" gewartet (Timer von "tr" --> 0)
3.1 in dieser zeit wird der richtige Eingang betätigt (Taster, wird in einer if oder while schleife abgefragt, weswegen delay() nicht verwendbar ist) --> ein zähler wird um 1 erhöht und "tr" um einen wert verringert
3.2 in dieser zeit wird nicht der richtige / gar kein Eingang betätigt;

  • bei ablauf von "tr" springt er aus der schleife

4 LED wird ausgeschaltet
--> wieder von vorn

ich habe keine möglichkeit gefunden einen derartigen timer einzufügen, und verstehe ehrlich gesagt die timer 0-5 auch nicht wirklich...
bzw weiß nicht wie ich die einbinden könnte.

Bitte um Hilfe!

Such mal nach "BlinkWithoutDelay". Da ist die ganze Zeitsteuerung drin, die Du brauchst.

Gruß Tommy

snowpanter:
... Bitte um Hilfe!

Evtl. hilft, was ich kürzlich ins Netz gekippt habe. Klick hier.

HTH

Gregor

Hallo,

ins Netz gekippt ...

Achtung: Da die Funktion millis() einen Wert zurückgibt, der 32 Bit breit ist, kann es je nachdem, wie man die Bedingung formuliert, nach rund 49 Tagen zu Überlaufproblemen kommen.
...
Besser:
if(millis() - millisMem < …)

allgemein verständlich ist > statt < wegen problemlosen Überlauf
if (millis() - last_millis > intervall) { ... }

Hey! Schonmal Danke für die schnellen Antworten!

Um die Hardware kümmert sich ein Kollege - die LEDs werden nicht direkt angesteuert, sondern über einen LN2803a (Stromproblem gelöst :D), und ja wir haben an den Vorwiderstand gedacht.
(Bin Elektroniker, also sowas geht!)

Aufbau: Neun LEDs und neun Taster <-- basically :wink:

Die Idee mit millis() hatte ich schon:

unsigned long t0; // start
unsigned long t1; // LED ein
unsigned long t2; // LED aus
unsigned long t3;
unsigned long t4;
unsigned long t5;

void setup()
{
Serial.begin(250000);
pinMode(13,OUTPUT);
}

void loop()
{
t0 = 0;
t1 = 0;
t2 = 0;
t3 = 0;
t4 = 0;
t5 = 0;
digitalWrite(13, LOW); // LED aus

t0 = millis(); // Startzeit erfassen

if(millis() - t0 > 500) // Abfrage d(t0) >= 500
{
digitalWrite(13, HIGH); // LED ein
t1 = millis(); // Anschaltzeit LED erfassen
}

if(millis() - t1 > 500) // Abfrage d(t1) >= 500
{
digitalWrite(13, LOW); // LED aus
}

}

Ziel sollte hier sein, dass die onboard LED im 500ms Takt blinkt.
Aaaaaber - Pustekuchen...

Sieht jmd was falsch is und mag es mir evtl. erklären?

snowpanter:
Sieht jmd was falsch is und mag es mir evtl. erklären?

t0 = millis(); hat die falsche Position, bei t1 hast Du das besser gemacht.

Außerdem wird loop() ständig durchlaufen. Duch t1=0 als Anfangswert wird die zweite Bedingung immer wahr sein. Auch wenn die erste Bedingung die LED an machen möchte, wird sie danach gleich wieder aus gemacht. Lösung: Wenn LED aus, warte, dann mache sie an, sonst warte und mache sie aus.

in der loop schaltest du die Led 13 ohne Bedingung aus, damit kann sie maximal wenige ms an sein

@agmue:

  • zu Beginn habe ich alle Variablen "0" gesetzt, damit keine "Leichen" im Programm sind.

  • t0 soll die Startzeit des Ablaufs erfassen, unabhängig von den Schleifen --> was ist daran falsch?

  • t1 wird in der ersten Schleife gesetzt, und erst in der 2. Schleife verwendet --> die Zuweisung erfolgt vor der Verwendung, quasi: t1=0 ... t1=millis() ... t1 wird verwendet

wie warte ich denn?
(wo wir wieder bei dem timer sind^^
da lobe ich mit SPS - s5time ... gaaanz einfach)

@jurs:

Wie gesagt, die zusätzlichen Abfragen kann ich machen, aber ich bekomme keinen Timer gebaut.
Was ich da gepostet habe, hätte nach meiner Logik blinken sollen - als Test der Antworten vorher quasi.

  • Das ENDproblem ist das komplette Programm, aber Schritt für Schritt laufen lernen ist meine Devise

@ardubu

  • zu Beginn habe ich alle Variablen "0" gesetzt, damit keine "Leichen" im Programm sind.
    [Auch LED AUS]

@ardubu

  • zu Beginn habe ich alle Variablen "0" gesetzt, damit keine "Leichen" im Programm sind.
    [Auch LED AUS]

aber genau damit schaltest du sie aus, auch wenn sie 1 ms vorher eingeschaltet wurde, das sieht dein Auge nicht, dafür ist es zu träge.

void loop()
{
t0 = millis(); // Startzeit erfassen

if(millis() - t0 > 500) // Abfrage d(t0) >= 500
{
digitalWrite(13, HIGH); // LED ein
t1 = millis(); // Anschaltzeit LED erfassen
}

if(millis() - t1 > 500) // Abfrage d(t1) >= 500
{
digitalWrite(13, LOW); // LED aus
}
}

funktioniert auch nicht...
ich vermute das problem ist zwischen t0 und der abfrage ob t0 500 ms größer ist als die aktuelle zeit, nur weiß ich nicht wieso.

aber ich nehme gern vorschläge an wie es funktional wird

snowpanter:
da lobe ich mit SPS - s5time ... gaaanz einfach)

Diese eigentlich nützlichen Vorkenntnisse stehen Dir im Weg, war bei mir nicht anders.

Schau Dir mal diese zwei Zeilen an, die im Abstand von µsec ausgeführt werden:

t0 = millis();              // Startzeit erfassen
 
 if(millis() - t0 > 500)     // Abfrage d(t0) >= 500

millis() -t0 ist immer 0, das ist also eine sinnlose Aktion. Einverstanden?

In #2 ist ein nützlicher Link für Dich und noch einer von mir: Anleitung: Endlicher Automat mit millis().

ok, seh ich ein...
was kann ich also machen? :smiley:

das hab ich mir angeschaut, versteh aber nicht wieso es funktioniert und meins nicht...

snowpanter:
was kann ich also machen? :smiley:

Den Beitrag von jurs durcharbeiten und dann hierüber grübeln:

const byte ledPin = 13;
unsigned long t0, t1;
bool stat;

void setup() {
  pinMode(ledPin, OUTPUT);
}

void loop()
{
  if (millis() - t0 > 500 && !stat)
  {
    stat = !stat;
    digitalWrite(13, HIGH); // LED ein
    t1 = millis();
  }
  if (millis() - t1 > 500 && stat)
  {
    stat = !stat;
    digitalWrite(13, LOW);  // LED aus
    t0 = millis();
  }
}

Doc_Arduino:
... allgemein verständlich ist > statt < wegen problemlosen Überlauf
if (millis() - last_millis > intervall) { ... }
...

Uh ... diesen Fehler habe ich doch tatsächlich wochenlang übersehen. Danke!

Gruß

Gregor

Okay,
@ agmue:
was du gepostet hast funzt zwar, hilft mir aber von verständnis absolut nicht weiter...

@ jurs:
ich habe vorhin das blinken nur probiert um evtl auf den timer zu kommen, aber danke für die erklärung der blinkschaltung :slight_smile:

naja, hab jetzt was über ne blinkschaltung, aber keine ahnung wie ich mein problem lösen kann...

deswegen versuche ichs nochmal:

ein TIMER, der eine zeit X (einstellbar) ablaufen lässt [ob 0...x oder x...0 ist glaube egal]

  • wie baue ich so ein teil zusammen?

denn sorry jungs, aber das hab ich bisher (wenns in einer der erklärungen drin war) nicht gecheckt...

ich behaupte mal wild in den raum, dass das von agmue dem was ich will sehr nahe kommt, aber hab NULL plan was er in dem programm wieso macht. hm

Die Blinkschaltung ist ein Beispiel für einen Timer wie Du ihn willst. Was daran ist unklar?

snowpanter:
was du gepostet hast funzt zwar, hilft mir aber von verständnis absolut nicht weiter...

Dann kennst Du auch den Nachtwächter nicht, der hat noch alle zum Verständnis geführt.

Einen habe ich noch:

#include <INTERVAL.h>
const byte LED = 13;

void setup() {
  pinMode(LED,OUTPUT);
}

void loop() {
   INTERVAL(500UL) { // 500ms
     digitalWrite(LED,!digitalRead(LED));
   }
}

Wenn Dir das angenehmer ist, dann ist INTERVAL etwas für Dich.

agmue:
Dann kennst Du auch den Nachtwächter nicht, der hat noch alle zum Verständnis geführt.

BlinkwithoutDelay - Die Nachtwächtererklärung

:slight_smile:

aber es hilft wirklich ungemein, das mit den millis() zu verstehen.

guntherb:
aber es hilft wirklich ungemein, das mit den millis() zu verstehen.

Absolut richtig!

Möglicherweise hängt das Verständnis aber auch bei der Ablaufsteuerung. Eigentlich sollen ja mehrere Dinge in einer bestimmten Reihenfolge abgearbeitet werden. Ich habe daher mal ein chaotisches (nicht im mathematischen Sinne) Blinkprogramm gemacht:

const byte ledPin = 13;
unsigned long aktMillis, prevMillis, intervall;
byte status = 0;

void setup() {
  pinMode(ledPin, OUTPUT);
}

void loop()
{
  aktMillis = millis();
  switch (status) {
    case 0:
      if (aktMillis - prevMillis >= intervall) {
        prevMillis = aktMillis;
        digitalWrite(ledPin, !digitalRead(ledPin));
        intervall = 500;
        status = 1;
      }
      break;
    case 1:
      if (aktMillis - prevMillis >= intervall) {
        prevMillis = aktMillis;
        digitalWrite(ledPin, !digitalRead(ledPin));
        intervall = 1000;
        status = 2;
      }
      break;
    case 2:
      if (aktMillis - prevMillis >= intervall) {
        prevMillis = aktMillis;
        digitalWrite(ledPin, !digitalRead(ledPin));
        intervall = 100;
        status = 0;
      }
      break;
  }
}

Die Nachtwächter-Geschichte nicht zu verstehen, geht nicht.

Den BlinkWithoutDelay Code solltest du gefunden haben.

Grundlegende C Syntax-Kenntnisse ( wofür die vielen Semikolons ? :wink: ) scheinen auch da zu sein.

Das ganze wird einfacher, wenn du loop() nicht als Programmablauf siehst, sondern als momentane Zustandsbeschreibung, in der normalerweise nur festgestellt wird, dass gerade jetzt nichts zu tun ist.
(Der Nachtwächter braucht für seine Runde keine Zeit, jedenfalls weniger als eine Millisekunde)

Wenn du denkst, BlinkWithoutDelay hast du verstanden, aber agmues Abwandlung ist unklar, kannst du ja mal deine Verständnis-Unklarheiten beschreiben.

Wenn du erklären kannst, was die erste Zeile von deiner Funktion loop()
t0=0;
bedeutet, wird uns eventuell klar, was dein Problem ist.
Wenn wir uns einig sind, dass sie sinnlos aber nicht störend ist, mach sie trotzdem weg :wink:


Nebenbei:
Was eher verwirrt ist, dass du von Timern redest, aber eigentlich Software-Funktionen meinst.
In µControllern sind nämlich auch Hardware-Timer vorhanden, die hier aber nicht gemeint sind.