Go Down

Topic: Timerverzögerungsaktionsschaltung mit Poti und Button (Read 343 times) previous topic - next topic

engineeeer

Hallo zusammen,

Das Programm soll:

Nach Spannungszugabe am Arduino soll das eigentliche Programm (nach einstellen des Potis) durch einen Taster aktiviert werden können. Man sollte einen Zahlenwert über den Poti einlesen und im Programm an diesem Wert ein Aktion starten können. (Bisher mit Switch Case gelöst.)


Zudem soll der Compiler nach Bearbeitung eines Case Falls, in den nächst höheren Case springen und diesen abarbeiten bis zum letzten Case.
Beim letzten Case soll das Programm wieder in Ausgangslage, also vor die Poti-Eingabe gebracht werden.

Des weiteren wäre es vorteilhaft das Programm bzw. den Aktionsteil in den Switch Cases jederzeit über den (oder einen) Taster stoppen zu können um das System zur Poti Eingabe zurückzusetzen.

z.B. Stellt man den Poti auf 5 (Auf Display sichtbar), startet das Programm per Knopfdruck und case5 wird ausgeführt. Somit wird z.B. eine Methode aktiviert die einen Motor steuert. Dieser Arbeitet eine gewissen Zeit, trotzdem wird der nächst zahlenmäßig höhere Case (Im Beispiel also Case 6) genau nach z.B. 3 stunden angesteuert, ohne die Zeit die der Motor bei Case5 braucht mitzurechnen.

Das Programm "kann":
-Potiwert einlesen und Wertzittern entfernen.
-Hauptprogramm per Knopfdruck starten.


Problem:

-->Das Programm kann nicht richtig durch den Taster ausgeschaltet werden. Wie am besten die Switch Case und die For schleife durchbrechen?
-->Wie kann man die Cases um jeweils z.B. 3 h zeitversetzt ansteuern, gleichzeitig aber ein aktuator bzw. eine Methode schalten die, die Zeitmessung möglichst nicht beeinträchtigt?


Für Tipps/Tricks und sonstige Hilfen bin ich sehr dankbar. Ich erwarte keinen fertigen code. Ich bin mir nicht sicher ob die aktuelle Herangehensweise sinnvoll genug ist, und ob ich die gesamt Idee so zum laufen bekomme. Bisher habe ich schon einigen Content auf YT bezüglich blinkWithoutDelay, StateMachine, Multitasking etc. angeschaut, komme im Moment jedoch seit einigen Stunden nicht weiter. Stehe auf dem Schlauch.
Ich hoffe der code ist nicht zu vertüddelt da meine Kenntnisse & Syntax bisher noch auf eher Anfängerniveau sind. Habe den Ardi erst ein paar Tage. Vielen Dank für Rückmeldung.


noiasca

Quote
->Das Programm kann nicht richtig durch den Taster ausgeschaltet werden. Wie am besten die Switch Case und die For schleife durchbrechen?
ich vermute du sollst deinen Button debouncen. Dein Taster wird "prellen" und/oder du lässt den Taster zu spät wieder los und durchläuft microsekunden später noch mal den gleichen Code und stellt deine Flags wiederum. Zum Debouncen und zum Tasten auswerten gibt es in der IDE Beispiele.

Auf alle Fälle kannst du auch mehr Serial.print Ausgaben ergänzen, damit du siehst warum dein Sketch nicht so reagiert wie du glaubst dass er das tun soll.

Zeitsteuerung sollte relativ einfach sein. Halte dich an "BlinkWithoutDelay".
 --> wenn deine Aktion beginnt, merkst du dir die startZeit (=millis).
in deinem onOFF prüfst du dann ,ob die aktuelle Zeit (millis) - startZeit > 3 *60*1000UL ist . Wenn ja - schaltest weiter.

by the way...
warum du in deinem runningProgram() den switch case 10 mal durchführst ... finde ich eigenartig:
for (int i = comparator ; i <= 10 ; i++ ) {

aber wenn es wirklich das ist was du willst ... auch recht.
how to react on postings:
- post helped: provide your final sketch, say thank you & give karma.
- post not understood: Ask as long as you understand the post
- post is off topic (or you think it is): Stay to your topic. Ask again.
- else: Ask again.

engineeeer

Danke für den Tipp, die for Schleife war sinnlos. Habe auch noch ein paar Sachen angepasst. Jetzt kann ich zumindest nach dem Start die case´s abarbeiten lassen, und danach auf OFF schalten. Werde noch einen externen Reset Knopf einbauen.

Jetzt stellt sich mir nurnoch die Frage wie ich nach z.B. Case5   24 stunden später Case6 aktivieren kann im BlinkWithoutDelay style. Werde mir das jetzt nochmal genauer anschauen.

 Vielen Dank für die Hilfe !

Doc_Arduino

#3
Sep 24, 2020, 12:13 pm Last Edit: Sep 24, 2020, 12:20 pm by Doc_Arduino
Hallo,

in deinem switch case fehlt die break Anweisung. Derzeit werden alle case in einem Rutsch abgearbeitet, Stichwort "Falltrough". Desweiteren fehlt dir eine default Auswertung. Schaue dir den Aufbau von switch case nochmal genauer an.

In der IDE alle Ausgaben einschalten.
Datei > Voreinstellungen >
- Ausführliche Ausgabe während > beide Haken rein
- Compilerwarnungen > "ALLE"
Zeilennummern und Codefaltung sind auch hilfreich.
Speichern beim Überprüfen und Hochladen würde ich abschalten.

Eine einfache Tasterentprellung wäre, dabei aufpassen ob INPUT oder INPUT_PULLUP und dessen negierte Logik.
Oder du nimmst die https://github.com/thomasfredericks/Bounce2 Lib.
Code: [Select]

const byte pinTaster {2};

void setup()
{
  pinMode(pinTaster, INPUT_PULLUP);    
  Serial.begin(115200);
  Serial.println("\nStart");
}


void loop()
{
  const bool state = updateTaster(pinTaster, 30);
  if (state)
  {
    Serial.println(F("Taster wird gedrueckt"));
  }
}


bool updateTaster (const byte pin, const unsigned long interval)
{
  static unsigned long lastMillis {0};
  static bool state {false};

  if (millis() - lastMillis >= interval)
  {
    lastMillis = lastMillis + interval;
    state = !digitalRead(pin);
  }

  return state;
}
Tschau
Doc Arduino '\0'

Messschieber auslesen: http://forum.arduino.cc/index.php?topic=273445
EA-DOGM Display - Demos: http://forum.arduino.cc/index.php?topic=378279

uwefed

Quote
Zudem soll der Compiler nach Bearbeitung eines Case Falls, in den nächst höheren Case springen und diesen abarbeiten bis zum letzten Case.
In diesem Fall braucht es keinen Break bzw Du realisierst es durch ändern der Switch-Variable für den nächsten Durchlauf.

Der Compiler führt gar nichts aus. Der Compiler mit dem Linker und Preprozessor (hab ich da noch was vergessen) übersetzen den C-Code in Maschinencode. Dieser wird dann auf den Arduino übertragen und vom Controller auf dem Arduino sobald er resetiert wird oder Spannungsversorgung eingeschaltet wird ausgeführt.

Grüße Uwe

Tommy56

In diesem Fall braucht es keinen Break
Wenn er immer alle case-Fälle in einem Rutsch abarbeiten will, braucht es auch kein switch/case.

Ich denke aber er meint es so, dass beim nächsten Durchlauf der nächste case erfolgen soll. Dann braucht es aber break.

Gruß Tommy
"Wer den schnellen Erfolg sucht, sollte nicht programmieren, sondern Holz hacken." (Quelle unbekannt)

uwefed

Quote
Wenn er immer alle case-Fälle in einem Rutsch abarbeiten will, braucht es auch kein switch/case.
Wenn alle dann schon; aber wenn er verschiedene Einspringpunkte wählt dann schon.
Grüße Uwe

Tommy56

Richtig, wobei ich das auch noch nicht sehe.

Gruß Tommy
"Wer den schnellen Erfolg sucht, sollte nicht programmieren, sondern Holz hacken." (Quelle unbekannt)

engineeeer

Also ich habe den Code2 im 3. Post eingefügt. Vielen Dank für die Rückmeldung!!

Falls jemand weiß wie ich die Aktionen in den Cases um jeweils z. B. 24 Stunden verzögern kann, bescheid geben.
Habe mir überlegt das evtl. doch in einer For Schleife zu machen, und in die if Bedingung dann Millis und timestamp einzubauen. Habe aber noch kein konkreten Entwurf.

Tommy56

Was soll Dir eine for-Schleife bei der Bestimmung von 24 Stunden helfen?
Code: [Select]

const uint32_t t24 = 24UL * 3600 * 1000;

In der vorhergehenden Aktion den Startwert setzen und dann die normale millis-Abfrage.

Gruß Tommy

"Wer den schnellen Erfolg sucht, sollte nicht programmieren, sondern Holz hacken." (Quelle unbekannt)

Doc_Arduino

Hallo,

zur Ergänzung. Lies mal hier https://www.arduino.cc/reference/en/language/functions/time/millis/. Der Wertebereich vom Rückgabewert hat den Datentyp unsigned long. Der Maximalwert davon in Millisekunden betrachtet ergibt welche maximale Zeit die du intervallmäßig abfragen kannst? Dann musste nur noch das funktionelle Prinzip der Intervall Abfragen verinnerlicht haben, dann kannste damit sehr viel machen.

Theseus erklärt millis()

GuntherB - BlinkwithoutDelay - Die Nachtwächtererklärung


Denke dabei an deine Armbanduhr o.ä. mit der du sicherlich unbewusst jeden Tag irgendwelche Zeitdifferenzen bildest.
Tschau
Doc Arduino '\0'

Messschieber auslesen: http://forum.arduino.cc/index.php?topic=273445
EA-DOGM Display - Demos: http://forum.arduino.cc/index.php?topic=378279

engineeeer

Habe es mir nochmal genau angeschaut, aber komme einfach nicht auf den Trichter.
Mehrere Versuche bisher gescheitert. Habe mir den BlinkWithoutDelay und den Nachtwächter angeschaut.
Kann den Syntax einfach nicht auf meine Anwendung übertragen.

Wenn ich es so versuche:

int runningProgram() {
  comparator = smoothedPotiVal ();
  timeStampOne = millis();                              //Vergangene Zeit bis zum betätigen des Programmstartknopfs

  if ( millis() - timeStampOne == 86 400 000     && comparator == 1 ) {               //86 400 000 ms = 1 Tag
    AktionTag2();
    comparator++;
  }
  if (      millis() - timeStampOne == 86 400 000 * 2 && comparator == 2) {
    AktionTag3();
    comparator++;
  }

  if (     millis() - timeStampOne == (86 400 000 * 3) && comparator == 3) {
    AktionTag4();
    comparator++;
  }



  Komme ich einfach nicht auf den Trichter.
Wie ich ab dem Potiwert starten kann, und die aktionen nacheinander, mit 24h verzögerung starte.....
Die Aktionen die gestartet werden sollen, werden dann auch durch eine eigene millis() Methode angesteuert nehme ich an.

expected ')' before numeric constant muss auch noch beseitigt werden. Oder ist das Syntax problem?

uxomm

Zahlen dürfen keine Leerzeichen enthalten.
86 400 000 funktioniert also nicht
86400000 würde prinzipiell funktionieren.

Allerdings...
int timeStampOne;
und später
timeStampOne = millis();
Ein int kann Werte zwischen -32,768 und 32,767 annehmen (zumindest auf einem UNO), da ist ein Überlauf schnell passiert. Sollte besser unsigned long sein.

Außerdem:
timeStampOne = millis(); 
if ( millis() - timeStampOne == 86400000 ...
Diese Bedingung wird höchstwarhscheinlich nie erfüllt sein. Ich schätze
millis() - timeStampOne
wird in den allermeisten Fällen wohl 0 sein,
in seltenen Fällen vielleicht 1. :)
Always decouple electronic circuitry.

Doc_Arduino

#13
Sep 25, 2020, 11:40 am Last Edit: Sep 25, 2020, 11:43 am by Doc_Arduino
Hallo,

warum multiplizierst du den Wert vom Intervall? Das Intervall bleibt doch immer gleich, nämlich genau aller 24h. Mit Multiplikation wäre das nachfolgende Intervall dann 48h und das nächste 96h usw. Irgendwann sprengst du den Wertebereich.

Das Prinzip ist, es wird verglichen ob die Differenzzeit (Intervall) erreicht wurde oder noch nicht. Erst wenn es erreicht wurde, wir die aktuelle Zeit (millis) abgespeichert für den nächsten Vergleich.

Wenn du vorm Vergleich das hier machst
Code: [Select]

comparator = smoothedPotiVal ();
timeStampOne = millis();    


dann hebelst du das gesamte Prinzip aus. Deine Comparatoraddition ist futsch bzw. überflüssig und deine Vergleiche werden nie erfüllt. Laut meiner Meinung benötigst du nur diesen einen Vergleich der ständig aufgerufen wird. Aller 24h wird comparator um eins erhöht.

Code: [Select]

if ( millis() - timeStampOne >= 86400000) // 86400000 ms = 1 Tag
{              
   timeStampOne += 86400000;
   comparator++;
}


Danach folgt meinetwegen die Auswertung vom comparator Wert in deinem switch case mit break und default Anweisung.

Wegen der Lückenhaften Schreibweise. Du kannst 8'6400'000 schreiben. Desweiteren solltest du dir angewöhnen im Forum Code in Code Tags einzubetten, dann ist das besser lesbar und im dümmsten Fall werden keine Zeichen verstümmelt.

Und baue dir Funktionen, sonst blickst du irgendwann im Wirrwarr von Tausenden globaler Variablen nicht mehr durch. Wo möglich lokale Variablen verwenden.  Bsp.:
Code: [Select]

byte updateVergleich (const unsigned long interval)
{
  static unsigned long lastMillis {0};
  static byte comparator {0};

  if (millis() - lastMillis >= interval)
  {
    lastMillis += interval;
    comparator++;
    if(comparator >=10) // zählt von 0...9
    {
      comparator = 0;
    }
  }

  return comparator;
}


Nutzung:
Code: [Select]

byte comp = updateVergleich(8'6400'000);     // 24h Abfrage

Die Variable comp übergibts du dann deinem switch case.

Nochwas. Der Vergleich hier mit millis wird immer >= gemacht, nie ==.
Falls der Vergleich eine ms später erfolgt, durch Programmablaufverzögerungen, würde der Vergleich verpasst und nie gültig. Verstehste? Wenn das alles verstanden ist, kannste das nach Lust und Laune passend abändern oder auch nicht ...

Tschau
Doc Arduino '\0'

Messschieber auslesen: http://forum.arduino.cc/index.php?topic=273445
EA-DOGM Display - Demos: http://forum.arduino.cc/index.php?topic=378279

wno158


Go Up