Delay aus einzelner Void Funktion entfernen

Hallo
Ich bastel gerade an einer Steuerung für eine Gartenbahn. An einem Arduino Mega sind mehrere Schieberegister kaskadiert angeschlossen, welche wiederum die Eingänge von vielen L298N Treibern (für die Weichen) ansteuern. Der Mega empfängt über Bluetooth an der Seriellen Schnittstelle Befehle und schiebt dann die entsprechenden Bits in die Register. Soweit so gut. Es ist aber notwendig das nach dem umpolen (L298N) der Strom wieder abgeschaltet werden muss und alles auf LOW geht.
Dafür habe ich das Delay eingesetzt, was ich jedoch gerne durch die Millis Funktion ersetzen will.
Nach mehreren Versuchen hab ich es aufgegeben. Kann mir evtl. jemand unter die Arme greifen?

#include <SerialCommand.h>

#define arduinoLED 13   // Arduino LED on board

SerialCommand sCmd;     // The demo SerialCommand object


int shiftPin = 8;       //Pin verbunden mit SH_CP des 74HC595
int storePin = 9;       //Pin verbunden mit ST_CP des 74HC595
int dataPin = 10;       //Pin verbunden mit DS des 74HC595


void setup() {
  
  pinMode(storePin, OUTPUT);        // Pins 8,9,10 auf Ausgabe stellen
  pinMode(shiftPin, OUTPUT);        // Pins 8,9,10 auf Ausgabe stellen
  pinMode(dataPin, OUTPUT);         // Pins 8,9,10 auf Ausgabe stellen
  pinMode(arduinoLED, OUTPUT);      // LED auf Ausgabe
  digitalWrite(arduinoLED, LOW);    // LED aus

  Serial.begin(9600);
  Serial1.begin(9600);

  // Setup callbacks for SerialCommand commands
  sCmd.addCommand("PINON_40",    LED_on);          // Turns LED on
  sCmd.addCommand("PINOFF_40",   LED_off);         // Turns LED off
  sCmd.addCommand("w14on",     Weiche1_on);
  sCmd.addCommand("w14off",    Weiche1_off);
  Serial1.println("Ready");
}

void loop() {
  sCmd.readSerial1();     // We don't do much, just process serial commands
}


void LED_on() {
  Serial1.println("LED on");
  digitalWrite(arduinoLED, HIGH);
}

void LED_off() {
  Serial1.println("LED off");
  digitalWrite(arduinoLED, LOW);
}
void Weiche1_on() {
    
  Serial1.println("Weiche1 on");
  digitalWrite(storePin, LOW);
  shiftOut(dataPin, shiftPin, MSBFIRST, 0);  //alle Ausgänge am 2. Register aus
  shiftOut(dataPin, shiftPin, MSBFIRST, 1);  //Ausgang 1 am ersten Register auf HIGH und Ausgang 2 auf LOW / Motor dreht links
  digitalWrite(storePin, HIGH);
  delay(2000); [color=red]Das Delay soll raus[/color]
  Serial1.println("Weiche1 Strom aus");
  digitalWrite(storePin, LOW);
  shiftOut(dataPin, shiftPin, MSBFIRST, 0);  //alles auf LOW
  shiftOut(dataPin, shiftPin, MSBFIRST, 0);  //alles auf LOW Motor steht
  digitalWrite(storePin, HIGH);
  
}

void Weiche1_off() {
 
  Serial1.println("Weiche1 off");
  digitalWrite(storePin, LOW);
  shiftOut(dataPin, shiftPin, MSBFIRST, 0);  //alle Ausgänge am 2. Register aus
  shiftOut(dataPin, shiftPin, MSBFIRST, 2);  //Ausgang 2 am ersten Register auf HIGH und Ausgang 1 auf LOW / Motor dreht rechts
  digitalWrite(storePin, HIGH);
  delay(2000); [color=red]Das Delay soll raus[/color]
  Serial1.println("Weiche1 Strom aus");
  digitalWrite(storePin, LOW);
  shiftOut(dataPin, shiftPin, MSBFIRST, 0);  //alles auf LOW
  shiftOut(dataPin, shiftPin, MSBFIRST, 0);  //alles auf LOW Motor steht
  digitalWrite(storePin, HIGH);
  
 }

Hier mal ein Auszug aus dem Sketch

Grüße

André

Schau dir mal den Nachtwächter an- die Erklärung ist perfekt!

Die Lösung mit den Klassen finde ich gut, man muß nur auch noch dafür sorgen, daß alle Instanzen regelmäßig aufgefordert werden, ihren Status zu überprüfen. Das kann man auch ohne Klassen mit einem Array machen, oder mit den Instanzen in einem Array, und regelmäßig (einmal pro loop Durchlauf) alle Einträge im Array prüfen.

Ich glaube wir haben uns etwas Missverstanden. Die Weiche wird z.B. mit dem seriellen Befehl w1on gestellt und am L298N ist HIGH/LOW angelegt. Danach soll nach 2 Sekunden der Strom weggeschaltet werden indem am L298N LOW/LOW angelegt wird.
Mit dem nächsten Befehl w1off wird die Weiche wieder gestellt allerdings mit LOW/HIGH am L298N und dann wird nach 2 Sekunden wieder auf LOW/LOW geschaltet.
Die Weichen werden durch umpolen gestellt und müssen anschließend stromlos gemacht werden.

Hoffe das war jetzt nicht zu umständlich geschrieben.

Grüße

André

Du beschreibst eine ganz normale Ablaufsteuerung.

Ablaufsteuerungen und endliche Automaten mit Zeitsteuerung, sind hier ein tagtäglicher Dauerbrenner. Da solltest du massig zu finden.

murdok1980:
Dafür habe ich das Delay eingesetzt, was ich jedoch gerne durch die Millis Funktion ersetzen will.
Nach mehreren Versuchen hab ich es aufgegeben. Kann mir evtl. jemand unter die Arme greifen?

Man kann Delay nicht einfach durch Millis ersetzen. Der komplette Programmablauf muss geändert werden. Millis entspricht einer Uhr.
Alltagsbeispiel: Du hast einen Arzttermin. Die Sprechstundenhilfe sagt dir, du musst eine halbe Stunde warten. Du kannst dich eine halbe Stunde ins Wartezimmer setzen und Löcher in die Luft starren. Eine Zeitschrift lesen, wäre schon zu viel Aktivität. Das ist Delay. Oder du merkst dir die Uhrzeit und gehst in die umgebenden Geschäfte, trinkst in der Bäckerei drei Straßen wieter einen Kaffee usw.. Das einzige was du machen musst, ist regelmäßig auf die Uhr schauen und die Zeitdifferenz zwischen Zeit, wo du losgelaufen bist, mit der aktuellen berechnen und rechtzeitig zum Arzt zurückkehren. Das ist der millis-Ansatz.
Du schaltest eine Weiche, merkst dir mit einem Flag dass sie und wann sie geschaltet wurde, und schaust regelmäßig zwischen den anderen Aufgaben, ob die Zeit schon vergangen ist, bis du abschalten musst.

sCmd.addCommand("w14on",     Weiche1_on);

sCmd.addCommand("w14off",    Weiche1_off);

Willst du bei 16 Weichen 32 Funktionen definieren?

Welche serialCommand Library genau verwendest du da?

Es muss doch sicher möglich sein, mehrere Weichen gleichzeitig, zumindest innerhalb der 2 sec Wartezeit, zu schalten. Da ist der Ansatz "delay() durch millis() ersetzen", nicht hilfreich/ausreichend.
"Aufgabe komplett neu denken" wäre eher angesagt.

Zu einer "ganz normalen Ablaufsteuerung" gehört üblicherweise, ein Statusabbild aller Objekte (Weichen) zu führen. Insbesondere, wenn du sie wegen deiner Schieberegister nicht unabhängig voneinander ansprechen kannst.

Q

murdok1980:
Hoffe das war jetzt nicht zu umständlich geschrieben.

Ich möchte dich jetzt nicht komplett verwirren, aber evtl. solltest du dein Konzept noch etwas überdenken.
Aus meiner Sicht ist die Ansteuerung der Weichen durch I2C und entsprechenden I2C-Portexpander deutlich einfacher zu realisieren.
Da wird mit einer passenden Library jeder Ausgang einzeln angesprochen und keine Bits verschoben.
Denke mal drüber nach.

@ noiasca
Genau. Eine Weiche wird gestellt und nach 2 Sekunden kann die nächste Weiche gestellt werden. Während der 2 Sekunden kann ich schon den nächsten Befehl schicken. Der wird anschließend abgearbeitet. Ich benutze hier eine SerialCommand Library die vermutlich einen Buffer hat. (Soweit reicht mein Horizont nicht). Das mit dem Delay funktioniert ja auch soweit und gebaute Android App auch. Ich dachte mir nur das mit dem Delay könnte irgendwann mal unweigerlich zu Problemen führen wenn man weitere Ideen hat.

@HotSystems
Kannst du das mit dem I2C Portexpander kurz erklären. Unabhängiges schalten wär natürlich das ganz Hohe C.

@michael_x
Da hast du recht das wären 32 Funktionen für 16 Weichen plus Sonderfunktionen.
Die Library ist die hier
[url=https://github.com/scogswell/ArduinoSerialCommand[/url]

Ich bin immer offen für Vorschläge. Ich bin allerdings nicht so fit wie manch anderer hier.

Grüße
Andre

URL-Reparatur-Dienst, schon zu Ihrer Stelle :slight_smile:

Die Library ist die hier
ArduinoSerialCommand, GitHub

@ postmaster-ino
Danke dir.

Ich hab mir gerade mal den MCP23017 16-Bit I/O Expander mit I2C Interface angeschaut. Wenn ich das richtig verstehe kann man damit gleichzeitig mehrere Ausgänge völlig unabhängig schalten.

Grüße
Andre

Welche Hardware man dafür verwendet, ist aus meiner Sicht zweitrangig.
Ein MCP23017 ist auch nicht viel mehr, als ein aufgeblasenes Schieberegister.
Das eine dürfte für diesen Zweck genau so brauchbar sein, wie das andere.

Dein Problem liegt eher im Algorithmus, oder logischen Bereich.

Den Treiber kann kann austauschbar gestalten, so dass er wahlweise mit einfachen Schieberegistern, mit Arduino Pins oder auch mit dem MCP23017 arbeiten kann.

murdok1980:
.....

Ich hab mir gerade mal den MCP23017 16-Bit I/O Expander mit I2C Interface angeschaut. Wenn ich das richtig verstehe kann man damit gleichzeitig mehrere Ausgänge völlig unabhängig schalten.
....

Genau das ist der Expander den ich meine.
Klar dass es mit den Schieberegistern auch geht, allerdings ist die Steuerung der Expander aus meiner Sicht einfacher zu erledigen. Auch aus dem von dir genannten Grund.

murdok1980:
Ich dachte mir nur das mit dem Delay könnte irgendwann mal unweigerlich zu Problemen führen wenn man weitere Ideen hat.

das wird es auch.

Damit du Überblick empfehle ich dir jetzt schrittweise vorzugehen.

Daher, mach mal 3 separte Funktionen:

a) eine um eine Weiche x auf gerade zu stellen
b) eine um den Motor der Weiche x abzustellen
c) eine um eine Weiche x auf abbiegen zu stellen

und zwar a) nicht als

void Weiche1_off()

sonderm

void Weiche_off(byte aktuelleWeiche)

wenn du dann c auch machst und zu viele Zeilen gleich wie a) sind, mach eine Funktion mit zwei Parameter (Weiche-Nr und gerade/ungerade)

Eine besondere Aufgabe hast du bei b)

b) darf ausschließlich die Motoren der übergebenen Weiche beeinflussen, also ein generelles

//alles auf LOW

ist nicht gestattet.

Wenn du dann a/b/(c) hast kann man weiter mit dem Ablauf arbeiten, der sich aber im wesentlichen am "BlinkWithoutDelay" orientieren wird.

dann im nächsten Schritt schauen wir uns an, wie du b) korrekt innerhalb von 2 Sekunden nach einem a) oder c) aufrufst.

Oha.
Da werd ich mal mein Arduino Buch noch etwas studieren müssen. Ich mach das ja nicht beruflich und hab’s auch nicht gelernt sondern nur in kleinen Schritten angeeignet.

Grüße
Andre

murdok1980:
Oha.

... kenne ich gg

...
Ich mach das ja nicht beruflich und hab's auch nicht gelernt sondern nur in kleinen Schritten angeeignet.

Denke, genau Das ist die Zielgruppe von der Idee Arduino.

Aber eine interessante Frage: Setzt irgendwo Einer einen Arduino beruflich ein?
Wobei eine interaktive Schaufensterbeleuchtung wohl schon in diese Richtung geht.
Denke mir, daß 'Gelehrte' (kA, wie lernt man µC als Beruf?) auf andere Steinchen setzen.

MfG

Ja das stimmt schon aber wer z.B. C beherrscht kann auch mit Arduino umgehen.

murdok1980:
Ja das stimmt schon aber wer z.B. C beherrscht kann auch mit Arduino umgehen.

Da muss ich widersprechen.
Denn Arduino ist C++.
Und gerade in der C Programmierer Gilde findet man viele extreme C++ Feinde/Hasser.

Ich liebe es, teilweise Combie zu widersprechen

combie:
Da muss ich widersprechen.
Denn Arduino ist C++.
Und gerade in der C Programmierer Gilde findet man viele extreme C++ Feinde/Hasser.

wer C kennt und nicht direkt C++ Hasser ist, freut sich über die Arduino Umgebung. Wo zwar C++ Konstruktionen verwendbar sind, man aber trotzdem bei den Grundlagen bleiben kann.

Ausserdem glaube ich, Murdok (Andre) wollte sich mit "C" gar nicht von "C++" abgrenzen.

Mit Verlaub, euch zwei möchte ich nicht vermissen.
Für mich stand schon immer fest, es gibt nicht nur die eine Wahrheit.

Gruß Fips