RC Memory Schalter um Relais zu schalten

Hallo zusammen,
ich bin absoluter Neuling in Sachen Arduino und habe von Programmierung keine Ahnung. Da mich die Möglichkeiten aber faszinieren, habe ich mich etwas eingearbeitet und bin bis jetzt auch zu einem (für mich) befriedigenden Ergebnis gekommen.
Aber jetzt stehe ich vor einem Problem bei dem ich nicht weiterkomme:
Ich möchte bei einem ferngesteuerten Modellschiff Lichter, Radar und ähnliche Sonderfunktionen schalten. Um diese Verbraucher einzuschalten werden Relais verwendet. Diese 8 Relais möchte ich über 4 Schaltkanäle (AN-AUS-AN) der Fernsteuerung schalten. Und zwar sollte es ein Memory-Schalter sein. Also wenn ich einen Schalter kurz einschalte, soll das Relais solange geschaltet bleiben bis ich den selben Schalter erneut schalte.
Einen normalen Schalter (keine Memory-Funktion) habe ich schon programmiert und der funktionierte auch gut.... aber die Memory-Funktion fuxt mich irgendwie
Mein Problem ist, dass die Relais schalten wann und wie sie wollen und nicht wann ich will. :astonished:

Ich benutze einen Arduino UNO und eine Flysky FS-i6X Fernsteuerung mit einem 10 Kanal Empfänger.

Mein Sketch sieht folgendermaßen aus:

int X = 0;
byte CH7 = A5;                            // Signaleingang 
byte CH8 = A4;
byte CH9 = A3;
byte CH10 = A2;

byte OUT1 = 2;
byte OUT2 = 3;                             // Schaltausgänge
byte OUT3 = 4;
byte OUT4 = 5;
byte OUT5 = 6;
byte OUT6 = 7;
byte OUT7 = 8;
byte OUT8 = 9;

void setup() {
  pinMode(CH7, INPUT);                    // Definition der Pins Input oder Output
  pinMode(CH8, INPUT);
  pinMode(CH9, INPUT);
  pinMode(CH10, INPUT);
   
  pinMode(OUT1, OUTPUT);
  pinMode(OUT2, OUTPUT);
  pinMode(OUT3, OUTPUT);
  pinMode(OUT4, OUTPUT);
  pinMode(OUT5, OUTPUT);
  pinMode(OUT6, OUTPUT);
  pinMode(OUT7, OUTPUT);
  pinMode(OUT8, OUTPUT);
  
  Serial.begin(9600);                     // zum testen
}
void loop() 
  {
  if (pulseIn <= 10) {                    // Ohne Signal alles abschalten
    digitalWrite (OUT1, LOW);
    digitalWrite (OUT2, LOW);              
    digitalWrite (OUT3, LOW);
    digitalWrite (OUT4, LOW);
    digitalWrite (OUT5, LOW);
    digitalWrite (OUT6, LOW);
    digitalWrite (OUT7, LOW);
    digitalWrite (OUT8, LOW);
    
  } else{
   X = pulseIn(CH7, HIGH, 250000);                        // Eingangssignal abfragen
    int OUT1v = digitalRead (OUT1);                       // Variable erzeugen, die schau ob Ausgang1 ein- oder ausgeschaltet ist 
    if ((X>=10) && (X <= 1300) && (OUT1v==LOW)) {         // wenn  Eingangssignal im Bereich von 10 bis 1300 ms ist und Ausgang1 ausgeschaltet ist
      digitalWrite(OUT1, HIGH);                           // dann Ausgang 1 einschalten
    }
    delay (300);                                          // kurze Pause, sonst erkennt er den Unterschied nicht
    if ((X >= 10) && (X <= 1300) && (OUT1v==HIGH)){       // wenn  Eingangssignal im Bereich von 10 bis 1300 ms ist und Ausgang1 eingeschaltet ist
      digitalWrite(OUT1, LOW);                            // dann Ausgang1 ausschalten
    }
    
    X = pulseIn(CH7, HIGH, 250000);                       // Eingangssinal abfragen
    int OUT2v = digitalRead (OUT2);                       // siehe oben, nur mit Ausgang2
    if ((X >= 1701) && (OUT2v==LOW)) {                    // wenn Eingangssignal größer als 1701 ms und Ausgang2 ausgeschaltet ist 
      digitalWrite(OUT2, HIGH);                           // Ausgang2 einschalten
    }
    delay (300);                                          // kurze Pause
    if ((X >= 1701) && (OUT2v==HIGH)){                    // wenn Eingangssignal größer als 1701 ms und Ausgang2 eingeschaltet ist
      digitalWrite(OUT2, LOW);                            // Ausgang2 ausschalten
    }
    
  }

  if (pulseIn <= 10) {                                    // ab hier genau das gleiche wie oben, nur mit den weiteren Kanälen und Ausgängen
    digitalWrite (OUT1, LOW);
    digitalWrite (OUT2, LOW);              
    digitalWrite (OUT3, LOW);
    digitalWrite (OUT4, LOW);
    digitalWrite (OUT5, LOW);
    digitalWrite (OUT6, LOW);
    digitalWrite (OUT7, LOW);
    digitalWrite (OUT8, LOW);
    
  } else{
   X = pulseIn(CH8, HIGH, 250000);
    int OUT3v = digitalRead (OUT3);
    if ((X>=10) && (X <= 1300) && (OUT3v==LOW)) {        
      digitalWrite(OUT3, HIGH);
    }
    delay (300);
    if ((X >= 10) && (X <= 1300) && (OUT3v==HIGH)){
      digitalWrite(OUT3, LOW);                                                   
    }
    
    X = pulseIn(CH8, HIGH, 250000);
    int OUT4v = digitalRead (OUT4);
    if ((X >= 1701) && (OUT4v==LOW)) {        
      digitalWrite(OUT4, HIGH);
    }
    delay (300);
    if ((X >= 1701) && (OUT4v==HIGH)){
      digitalWrite(OUT4, LOW);                                                   
    }
    
  }

  if (pulseIn <= 10) {
    digitalWrite (OUT1, LOW);
    digitalWrite (OUT2, LOW);              
    digitalWrite (OUT3, LOW);
    digitalWrite (OUT4, LOW);
    digitalWrite (OUT5, LOW);
    digitalWrite (OUT6, LOW);
    digitalWrite (OUT7, LOW);
    digitalWrite (OUT8, LOW);
    
  } else{
   X = pulseIn(CH9, HIGH, 250000);
    int OUT5v = digitalRead (OUT5);
    if ((X>=10) && (X <= 1300) && (OUT5v==LOW)) {        
    }
    delay (300);
    if ((X >= 10) && (X <= 1300) && (OUT5v==HIGH)){
      digitalWrite(OUT5, LOW);                                                  
    }
    
    X = pulseIn(CH9, HIGH, 250000);
    int OUT6v = digitalRead (OUT6);
    if ((X >= 1701) && (OUT6v==LOW)) {        
      digitalWrite(OUT6, HIGH);
    }
    delay (300);
    if ((X >= 1701) && (OUT6v==HIGH)){
      digitalWrite(OUT6, LOW);                                                   
    }
    
  }

  if (pulseIn <= 10) {
    digitalWrite (OUT1, LOW);
    digitalWrite (OUT2, LOW);              
    digitalWrite (OUT3, LOW);
    digitalWrite (OUT4, LOW);
    digitalWrite (OUT5, LOW);
    digitalWrite (OUT6, LOW);
    digitalWrite (OUT7, LOW);
    digitalWrite (OUT8, LOW);
    
  } else{
   X = pulseIn(CH10, HIGH, 250000);
    int OUT7v = digitalRead (OUT7);
    if ((X>=10) && (X <= 1300) && (OUT7v==LOW)) {        
      digitalWrite(OUT7, HIGH);
    }
    delay (300);
    if ((X >= 10) && (X <= 1300) && (OUT7v==HIGH)){
      digitalWrite(OUT7, LOW);                                                   
    }
    
    X = pulseIn(CH10, HIGH, 250000);
    int OUT8v = digitalRead (OUT8);
    if ((X >= 1701) && (OUT8v==LOW)) {        
      digitalWrite(OUT8, HIGH);
    }
    delay (300);
    if ((X >= 1701) && (OUT8v==HIGH)){
      digitalWrite(OUT8, LOW);                                                   
    }
    
  }
  }

Ich hoffe, ich habe mich verständlich ausgedrückt :slight_smile: und würde mich freuen wenn mir hier jemand helfen kann.

Viele Grüße
Markus

Hallo Markus,
bitte ändere Deinen Themeneinstieg, in dem Du Dein Programm in code-Tags setzt, sonst kann die Anzeige Fehler enthalten.

franky0304:
Einen normalen Schalter (keine Memory-Funktion) habe ich schon programmiert und der funktionierte auch gut....

Bitte zeige mal diese funktionierende Variante!

Damit willkommen im Forum!

Eine gewisse Grundformatierung (+T in der IDE hilft Dir dabei) erhöhkt ebenfalls die Lesbarkeit.

Gruß Tommy

Und wie setzte ich das Programm in code-Tags?

(</>-Button oben links im Forumseditor oder [code] davor und [/code] dahinter ohne *).
Das kannst Du auch noch nachträglich ändern.

Gruß Tommy

Moin Markus,
deine "Aufrufe" mit dem pulseIn ohne Parameter sind vermutlich die Ursache des Problems:

 if (pulseIn <= 10)
  {

Da müsstest Du Dich schon jeweils für einen der Kanäle CH7 bis CH10 entscheiden.

Und vor allem einen Funktionsaufruf mit den () hintendran machen und nicht die Adresse der Funktion prüfen. Die ist mit Sicherheit > 10.

Gruß Tommy

Das heißt, ich müsste es so schreiben:

if (pulseIn(CH7) <= 10)

und dann könnte ich ja danach auch die anderen Ausgänge weglassen?

also nur:

if (pulseIn(CH7) <= 10) {
    digitalWrite (OUT1, LOW);
    digitalWrite (OUT2, LOW);

und bei den anderen Kanälen dann die jeweils anderen Ausgänge.

Verstehe ich das richtig?

@ Tommy56
Das mit dem Funktionsaufruf und den () verstehe ich jetzt nicht

franky0304:
Das mit dem Funktionsaufruf und den () verstehe ich jetzt nicht

Also so?

if (pulseIn(CH7, HIGH) <= 10) {
    digitalWrite (OUT1, LOW);
    digitalWrite (OUT2, LOW);

Oder stehe ich immer noch am Schlauch?

franky0304:
Einen normalen Schalter (keine Memory-Funktion) habe ich schon programmiert und der funktionierte auch gut....

Was ist denn ein Schalter mit ohne Memory-Funktion?
Ein Taster?

Mein Problem ist, dass die Relais schalten wann und wie sie wollen und nicht wann ich will.

Du willst es nicht - Dann Ursache suchen.

Ich benutze einen Arduino UNO

Ich hoffe, ich habe mich verständlich ausgedrückt :slight_smile: und würde mich freuen wenn mir hier jemand helfen kann.

Nein.

Ich habs mal auf das runtergebrochen, was ich für notwendig erachte und versuche es.

Als Erstes:
Ich habe mich bemüht irgendetwas zu finden, was spezifisch zur Steuerung ist.
Ja. Der Receiver.
Das Ganze gibt es auch nur als 6Ch.
Also für die Zukunft: Bitte unbedingt einen Link/URL einfügen, was Du hast.

Nachdem ich jetzt durch bin ist das, was Du suchst, komplett von der Fernbedienung unabhängig.

An irgendeinem PIN Aktion, ein einem anderen PIN ReAktion.
Du möchtest einen Schalter nicht als Schalter, sondern als Taster benutzen.
Umgeschalten wird IMMER mit gleichem Pegel. Der andere Pegel ersetzt den Schalterstaus "umgeschaltet" bzw. Tasterstatus "losgelassen"

Dann brauchst Du zwei Variablen.
Die erste die sich den letzten Status des Schalter/Taster merkt und eine, die das Timing für das entprellen übernimmt.

Das, was ich bisher sehe, scheint ungeeignet zu sein:

  pinMode(CH7, INPUT);                    // Definition der Pins Input oder Output

Kannst Du sicherstellen, das extern der Zustand IMMER definiert ist? (PULL_UP / PULL_DOWN)
Nein? - Dann gilt es das als erstes zu lösen.

[edit]
Ich versteh noch nicht ganz, was Du mit dem Pulsein() willst..

franky0304:

if (pulseIn(CH7, HIGH) <= 10) {

Formal richtig.

Allerdings frage ich mich, wie eine Impulslänge <= 10 überhaupt zustande kommen soll.
Der Empfänger gibt doch ständig die Sollposition des Servos aus, d.h. die Impulslänge wird bei selbst neutralisierendem Knüppel in Nullstellung immer so um 1500 Mikrosekunden liegen. Die Extreme sind üblicherweise 1000 und 2000.
So zwischen 1300 und 1700 willst Du vermutlich nix tun, unter 1300 den einen Output bedienen, über 1700 den anderen.

Nebenbei:
Hier hat mal jemand mit einem Arduino Pulslängen gemessen.

Was den Funktionsaufruf angeht:
pulseIn(pin, HIGH); mit den Klammern ruft die Funktion auf. Was an Parametern in den Klammern stehen muss, hängt von der Funktion ab.
pulseIn ist nur der Name der Funktion und wird (vereinfacht) vom Compiler mit ihrer Anfangsadresse im Speicher ersetzt. Damit ist
if (pulseIn <= 10)vermutlich immer wahr.

wno158:
Formal richtig.

Der Empfänger gibt doch ständig die Sollposition des Servos aus,

Bei Channel 0-6.
Danach wirds knifflig.

Ahh - da habe ich noch gar nicht drauf geschaut.
Der TO macht die pulseIn auf den (Analog) Eingängen:

byte CH7 = A5;                            // Signaleingang
byte CH8 = A4;
byte CH9 = A3;
byte CH10 = A2;

Geht das überhaupt?

wno158:
Geht das überhaupt?

Die erste Frage ist, warum macht er das.
Ist denn ab CH7 tatsächlich ein "Servo"signal oder nur noch HIGH/LOW vorhanden?
Ist die PIN-Konfig am Arduino dazu passend?

franky0304:
ich bin absoluter Neuling in Sachen Arduino und habe von Programmierung keine Ahnung.

An der Stelle setze ich an, um etwas auszuholen.

franky0304:
Und zwar sollte es ein Memory-Schalter sein. Also wenn ich einen Schalter kurz einschalte, soll das Relais solange geschaltet bleiben bis ich den selben Schalter erneut schalte.

Weil es sich sozusagen um einen Klassiker der Programmierung handelt, reduziere ich die Fragestellung auf einen Taster und eine LED: Wird der Taster gedrückt, soll sich der Zustand der LED verändern.

Habe ich die Frage richtig verstanden?

Wenn ja, dann die Lösung: Aus technischer Sicht ist die Aufgabe schlecht formuliert, besser wäre: Ändert sich der Zustand des Tasters von "nicht gedrückt" nach "gedrückt", soll sich der Zustand der LED (ein/aus) verändern. Als Programm:

//
// RC Memory Schalter um Relais zu schalten
const byte CH7 = A5;
const byte OUT = 13;

void setup() {
  pinMode(CH7, INPUT_PULLUP); // aktiv LOW
  pinMode(OUT, OUTPUT);
}

void loop() {
  bool ch7_akt = !digitalRead(CH7);         // hier dreht sich die Logik nach aktiv HIGH
  static bool ch7_alt = ch7_akt;
  if (ch7_alt != ch7_akt) {                 // Zustandsänderung des Tasters?
    if (ch7_akt) {                          // Taster gedrückt?
      digitalWrite(OUT, !digitalRead(OUT)); // LED-Zustand ändern
    }
    delay(100); // simples Entprellen, wenn man es mit einem mechanischen Kontakt probiert
  }
  ch7_alt = ch7_akt;                        // Tasterzustand merken
}

Ist das die von Dir gewünschte Funktionalität?

Hallo zusammen,

ich habe jetzt mal die Signale der Kanäle 7 - 10 ausgelesen. Danke wno158 für den Link :slight_smile:

Ich habe für jeden Kanal folgende Ergebnisse erzielt:
Schalter oben: ungefähr 990 ms
Schalter Mitte: 1490 ms
Schalter unten: 1990 ms
und zwar unabhängig ob ich am digitalen PIN 2 oder am analogen PIN A5 angeschlossen habe.

Wahrscheinlich habe ich mich gestern schlecht ausgedrückt, deshalb versuche ich es heute nochmal etwas deutlicher zu beschreiben.
Ich schalte den Schalter von CH7 kurz nach oben und zurück in Mittelstellung (Signal ändert sich von 1490 auf 990 und wieder auf 1490) und PIN x wird eingeschaltet und soll solange eingeschaltet bleiben bis ich den Schalter erneut kurz nach oben drücke.
Beim Schalten des Schalters nach unten ( Änderung von 1490 auf 1990) soll PIN y eingeschaltet werden und ebenfalls solange eingeschaltet bleiben bis der Schalter erneut nach unten gedrückt wird.

Die Abfrage if (pulseIn <= 10) soll lediglich dafür sorgen dass alle PINs ausgeschaltet werden falls der Empfänger aus irgendeinem Grund gar kein Signal mehr empfängt ( z.B. durch Ausfall der Fernsteuerung).
Dies ist aber nicht zwingens erforderlich.

Ich hoffe es ist jetzt etwas verständlicher.

Danke Markus

Hallo Markus,
prima - jetzt hast Du es schon fast geschafft.

Jetzt kannst Du im Prinzip den Code von agmue verwenden.
Du musst Dir nur statt mit digitalRead() von einem Taster am Input-Pin zu lesen ein eigenes Eingangssignal aus den Signalen (pulseIn()) basteln - die liefern Dir pro Kanal jeweils den Status von zwei Tastern:

signal < 1200           --> Taster 1 gedrückt
1200  <= signal <= 1700 --> kein Taster gedrückt
signal > 1700           --> Taster 2 gedrückt.

Man könnte / sollte das noch in eine Funktion verpacken, damit Du den Logik-Code nicht mehrfach schreiben musst. Das ist aber dann wohl die Kür.

https://www.arduino.cc/en/tutorial/switch

Der Begriff, wonach du suchst ist "toggle".