Neues RC Projekt - 16 Kanal Schalter für Lichtsteuerung

// 16 Kanal Schalter für Lichtsteuerung
// Fernsteuerung: Flysky i6X
// CPU: Arduino Nano
// https://forum.arduino.cc/t/neues-rc-projekt-16-kanal-schalter-fur-lichtsteuerung/1143800/23


enum State {IDLE, PULSE, MEMA, MEMB};  // Leerlauf, Impulse,

class Kanal {
  protected:
    const byte channel;
    const byte pin;
    const byte mem;
    State state;
    uint32_t previousMillis = 0; // Zeitmanagement

  public:
    Kanal(const byte channel, const byte pin, const byte mem) : channel(channel), pin(pin), mem(mem) {}

    void fire() {
      if (state == IDLE) {
        if (mem == 0) {
          previousMillis = millis();
          digitalWrite(pin, HIGH);
          state = PULSE;
        }
        else {
          state = MEMA;
          previousMillis = millis();
          digitalWrite(pin, HIGH);
        }
      }
      else if (state == MEMB && mem == 1) {
        digitalWrite(pin, LOW);
        state = IDLE;
      }
    }

    void begin() {
      pinMode(pin, OUTPUT);
    }

    void update(uint32_t currentMillis = millis()) {
      switch (state) {
        case PULSE :
          if (currentMillis - previousMillis > 1000) {   // nach n millisekunden abschalten
            digitalWrite(pin, LOW);
            state = IDLE;
          }
          break;
        case MEMA :
          if (currentMillis - previousMillis > 1000) {  // nach n millisekunden in den nächsten Status
            state = MEMB;
          }
          break;
      }
    }
};

const byte PWMPin1 {2};
const byte PWMPin2 {3};
uint16_t PWMEingang1;
uint16_t PWMEingang2;



Kanal kanal [] = {
  //                channel, Pin,  mem,   befehl auf serieller
  /*  Daten Kanal01 = */{1,   4,   1 },  // a
  /*  Daten Kanal02 = */{2,   5,   0 },  // b
  /*  Daten Kanal03 = */{3,   6,   1 },  // c
  /*  Daten Kanal04 = */{4,   7,   1 },  // d
  /*  Daten Kanal05 = */{5,   8,   0 },  // e
  /*  Daten Kanal06 = */{6,   9,   0 },  // f
  /*  Daten Kanal07 = */{7,  10,   0 },  // g
  /*  Daten Kanal08 = */{8,  11,   0 },  // h
  /*  Daten Kanal09 = */{9,  12,   0 },  // i
  /*  Daten Kanal10 = */{10, 13,   0 },  // j
  /*  Daten Kanal11 = */{11, A0,   0 },  // k
  /*  Daten Kanal12 = */{12, A1,   0 },  // l
  /*  Daten Kanal13 = */{13, A2,   0 },  // m
  /*  Daten Kanal14 = */{14, A3,   0 },  // n
  /*  Daten Kanal15 = */{15, A4,   0 },  // o
  /*  Daten Kanal16 = */{16, A5,   0 }   // p
};

void setup() {

  pinMode (PWMPin1, INPUT);
  pinMode (PWMPin2, INPUT);

  Serial.begin(115200);
  
  for (auto &i : kanal) {
    i.begin();
  }
  Serial.println("und go");
}

void loop() {
  readRCinput();
  checkRCSwitch1();
  Serial.print(F("PWM CH1: "));
  Serial.print(PWMEingang1);
  Serial.print(F("  PWM CH2: "));
  Serial.println(PWMEingang2);




  
  handleSerial();
  uint32_t currentMillis = millis();
  for (auto &i : kanal) {
    i.update(currentMillis);
  }
}

// nur testweise um Befehle einzugeben
void handleSerial() {
  int c = Serial.read();
  if (c >= 'a' && c <= 'p') {
    kanal[c - 'a'].fire();       // a = 0 ...  p = 15
  } else if (c >= '0' && c <= '9') {
    kanal[c - '0'].fire();       // ok, die ersten 10 Ziffern gehen auch ;-)
  }
}

void readRCinput()
{
  int PWM1IN = pulseIn(PWMPin1, HIGH ); //Read PWM Pulse
  if (PWM1IN > 900 && PWM1IN < 2100)
  {
    PWMEingang1 = PWM1IN;
  }
  int PWM2IN = pulseIn(PWMPin2, HIGH ); //Read PWM Pulse
  if (PWM2IN > 900 && PWM2IN < 2100)
  {
    PWMEingang2 = PWM2IN;
  }
}

void checkRCSwitch1()
{
  switch (PWMEingang1)
  {
    case 950 ... 1050:
      kanal[0].fire();
      break;
    case 1950 ... 2050:
      kanal[1].fire();
      break;
    case 1100 ... 1200:
      kanal[2].fire();
      break;
    case 1800 ... 1900:
      kanal[3].fire();
      break;
    case 1240 ... 1340:
      kanal[4].fire();
      break;
    case 1350 ... 1450:
      kanal[5].fire();
      break;
    case 1530 ... 1630:
      kanal[6].fire();
      break;
    case 1660 ... 1760:
      kanal[7].fire();
      break;
    default:
      break;
  }
}

Das ist der Code mit der wiederhergestellten handleSerial und der von mir eingefügten noch eingefügten checkRCswitch und dem switch/case.

Den neuen Code aus dem Simulator habe ich auch getestet. Auch dort schaltet sich der Kanal nicht wieder aus :thinking:

ich hab im Simulator ein paar Serial prints ergänzt.
Bitte aktualisiere das mal.

Dann zeig mir bitte die Ausgaben von deinem Seriellen Monitor.

Zunächst mit einem mem 0 Kanal.
Dann mit einen mem 1 Kanal.

ok, einem Moment bitte

Das ist mit mem=0

17:40:02.877 -> und go
17:40:05.806 -> Neuer Wert auf pin2 ist 0pin=4 fire
17:40:05.806 -> pin=4 state=1
17:40:05.806 -> Neuer Wert auf pin2 ist -1Neuer ert auf pin2 ist 0pin=4 fire
17:40:05.852 -> pin=4 state=1
17:40:05.852 -> Neuer Wert auf pin2 ist -1euer Wert auf pin2 ist 0pin=4 fire
17:40:05.852 -> pin=4 state=1
17:40:05.852 -> Neuer Wert auf pin2 ist -1Neuer Wert auf pin2 ist 0pin=4 fire
17:40:05.852 -> pin=4 state=1
17:40:05.898 -> Neuer Wert auf pin2 ist -1Neuer Wert auf pin2 ist 0pin=4 fire
17:40:05.898 -> pin=4 state=1
17:40:05.898 -> Neuer Wert auf pin2 ist -1Neuer Wert auf pin2 ist 0pin=4 fire
17:40:05.898 -> pin=4 state=1
17:40:05.945 -> Neuer Wert auf pin2 ist -1Neuer Wert auf pin2 ist 0pin=4 fire
17:40:05.945 -> pin=4 state=1
17:40:05.945 -> Neuer Wert auf pin2 ist -1Neuer Wert auf pin2 ist 0pin=4 fire
17:40:05.945 -> pin=4 state=1
17:40:05.945 -> Neuer Wert auf pin2 ist -1Neuer Wert auf pin2 ist 0pin=4 fire
17:40:05.992 -> pin=4 state=1
17:40:05.992 -> Neuer Wert auf pin2 ist -1Neuer Wert auf pin2 ist 0pin=4 fire
17:40:05.992 -> pin=4 state=1
17:40:05.992 -> Neuer Wert auf pin2 ist -1Neuer Wert auf pin2 ist 5pin=9 fire
17:40:06.039 -> pin=9 state=1
17:40:06.039 -> Neuer Wert auf pin2 ist -1pin=4 state=0
17:40:07.059 -> pin=9 state=0

Das ist mit mem=1

17:41:15.188 -> und go
17:41:18.975 -> Neuer Wert auf pin2 ist 0pin=4 fire
17:41:18.975 -> pin=4 state=2
17:41:19.022 -> Neuer Wert auf pin2 ist -1Neuer Wert auf pin2 ist 0pin=4 fire
17:41:19.022 -> pin=4 state=2
17:41:19.022 -> Neuer Wert auf pin2 ist -1Neuer Wert auf pin2 ist 0pin=4 fire
17:41:19.022 -> pin=4 state=2
17:41:19.022 -> Neuer Wert auf pin2 ist -1Neuer Wert auf pin2 ist 0pin=4 fire
17:41:19.068 -> pin=4 state=2
17:41:19.068 -> Neuer Wert auf pin2 ist -1Neue Wert auf pin2 ist 0pin=4 fire
17:41:19.068 -> pin=4 state=2
17:41:19.068 -> Neuer Wert auf pin2 ist -1Neuer Wert auf pin2 ist 0pin=4 fire
17:41:19.068 -> pin=4 state=2
17:41:19.116 -> Neuer Wert auf pin2 ist -1Neuer Wert auf pin2 ist 0pin=4 fire
17:41:19.116 -> pin=4 state=2
17:41:19.116 -> Neuer Wert auf pin2 ist -1Neuer Wert auf pin2 ist 0pin=4 fire
17:41:19.116 -> pin=4 state=2
17:41:19.161 -> Neuer Wert auf pin2 ist -1Neuer Wert auf pin2 ist 0pin=4 fire
17:41:19.161 -> pin=4 state=2
17:41:19.161 -> Neuer Wert auf pin2 ist -1Neuer Wert auf pin2 ist 0pin=4 fire
17:41:19.161 -> pin=4 state=2
17:41:19.161 -> Neuer Wert auf pin2 ist -1Neuer Wert auf pin2 ist 0pin=4 fire
17:41:19.207 -> pin=4 state=2
17:41:19.207 -> Neuer Wert auf pin2 ist -1euer Wert auf pin2 ist 4pin=8 fire
17:41:19.254 -> pin=8 state=1
17:41:19.254 -> Neuer Wert auf pin2 ist -1Neuer Wert auf pin2 ist 5pin=9 fire
17:41:19.254 -> pin=9 state=1
17:41:19.254 -> Neuer Wert auf pin2 ist -1Neuer Wert auf pin2 ist 5pin=9 fire
17:41:19.254 -> pin=9 state=1
17:41:19.300 -> Neuer Wert auf pin2 ist -1pin=4 state=3
17:41:20.231 -> pin=8 state=0
17:41:20.278 -> pin=9 state=0

Habe den Taster nur jeweils 1x betätigt

ich versteh noch nicht warum das in dieser Kombi ausgegeben wird.

das kann nicht mein vollständiger Sketch sein - ich habe den zweiten PWM Kanal noch nicht aktiviert.

ich hab jetzt nur eine Zeilenschaltung eingefügt. Probier bitte mal:

// 16 Kanal Schalter für Lichtsteuerung
// Fernsteuerung: Flysky i6X
// CPU: Arduino Nano
// https://forum.arduino.cc/t/neues-rc-projekt-16-kanal-schalter-fur-lichtsteuerung/1143800/23
// 2023-07-02 noiasca
// work in progress - Testfeld

enum State {IDLE, PULSE, MEMA, MEMB};  // die einzelnen Zustände der Kanäle/Pins

class Kanal {
  protected:
    const byte channel;          // braucht es das wirklich ?!? grauslich...
    const byte pin;              // der GPIO
    const byte mem;              // Gibt das Verhalten des Pins an
    State state;                 // Status des Kanals/Pins
    uint32_t previousMillis = 0; // Zeitmanagement

  public:
    Kanal(const byte channel, const byte pin, const byte mem) : channel(channel), pin(pin), mem(mem) {}

    void fire() {
      Serial.print(F("pin=")); Serial.print(pin); Serial.println(F(" fire"));
      switch (state) {
        case IDLE:
          if (mem == 0) {
            previousMillis = millis();
            digitalWrite(pin, HIGH);
            state = PULSE;
          }
          else {
            previousMillis = millis();
            digitalWrite(pin, HIGH);
            state = MEMA;
          }
          break;
        case MEMB:
          digitalWrite(pin, LOW);
          state = IDLE;
          break;
      }
      Serial.print(F("pin="));Serial.print(pin); Serial.print(F(" state=")); Serial.println(state);
    }

    void begin() {
      pinMode(pin, OUTPUT);
    }

    void update(uint32_t currentMillis = millis()) {
      switch (state) {
        case PULSE :
          if (currentMillis - previousMillis > 1000) {   // nach n millisekunden abschalten
            digitalWrite(pin, LOW);
            state = IDLE;
            Serial.print(F("pin="));Serial.print(pin); Serial.print(F(" state=")); Serial.println(state);
          }
          break;
        case MEMA :
          if (currentMillis - previousMillis > 1000) {  // nach n millisekunden in den nächsten Status
            state = MEMB;
            Serial.print(F("pin="));Serial.print(pin); Serial.print(F(" state=")); Serial.println(state);
          }
          break;
      }
    }
};

Kanal kanal [] = {
  //                channel, Pin,  mem,   befehl auf serieller
  /*  Daten Kanal01 = */{1,   4,   1 },  // a
  /*  Daten Kanal02 = */{2,   5,   0 },  // b
  /*  Daten Kanal03 = */{3,   6,   1 },  // c
  /*  Daten Kanal04 = */{4,   7,   1 },  // d
  /*  Daten Kanal05 = */{5,   8,   0 },  // e
  /*  Daten Kanal06 = */{6,   9,   0 },  // f
  /*  Daten Kanal07 = */{7,  10,   0 },  // g
  /*  Daten Kanal08 = */{8,  11,   0 },  // h
  /*  Daten Kanal09 = */{9,  12,   0 },  // i
  /*  Daten Kanal10 = */{10, 13,   0 },  // j
  /*  Daten Kanal11 = */{11, A0,   0 },  // k
  /*  Daten Kanal12 = */{12, A1,   0 },  // l
  /*  Daten Kanal13 = */{13, A2,   0 },  // m
  /*  Daten Kanal14 = */{14, A3,   0 },
  /*  Daten Kanal15 = */{15, A4,   0 },
  /*  Daten Kanal16 = */{16, A5,   0 }
};

struct RC {
  const uint8_t pin;         // the GPIO
  uint16_t previousChannel;  // last channel or -1 if last pwm signal was invalid
};

RC rc[] {
  {2, -1},
  //{3, -1}      // @todo: zweiter RC Pin wird noch nicht funktionieren ... siehe unten
};

// nur testweise um Befehle einzugeben
void handleSerial() {
  int c = Serial.read();
  if (c >= 'a' && c <= 'p') {         // a = 0 ...  p = 15
    kanal[c - 'a'].fire();            // entsprechenden Kanal triggern
  } else if (c >= '0' && c <= '9') {  // die ersten 10 Ziffern gehen auch ;-)
    kanal[c - '0'].fire();
  }
}

// translate pulseIn length into channel 
// returns -1 if invalid
int pulseToChannel (uint16_t pulseLength) {
  switch (pulseLength) {
    case 950 ... 1050:
      return 0;
      break;                // können später mal gelöscht werden
    case 1950 ... 2050:
      return 1;
      break;
    case 1100 ... 1200:
      return 2;
      break;
    case 1800 ... 1900:
      return 3;
      break;
    case 1240 ... 1340:
      return 4;
      break;
    case 1350 ... 1450:
      return 5;
      break;
    case 1530 ... 1630:
      return 6;
      break;
    case 1660 ... 1760:
      return 7;
      break;
    default:
      return -1;    // invalid pwm range
  }
}

void readRCinput() {
  for (size_t i = 0; i < sizeof(rc) / sizeof(rc[0]); i++) {
    uint16_t pulseLength = pulseIn(rc[i].pin, HIGH, 20000);  // Read PWM pulse
    int actualChannel = pulseToChannel(pulseLength);         // try to get an channel from the pwm pulse length
    if (actualChannel != rc[i].previousChannel) {            // only react on channel state changes
      Serial.print(F("Neuer Wert auf pin")); Serial.print(rc[i].pin);
      Serial.print(F(" ist ")); Serial.println(actualChannel);
      if (actualChannel >= 0 && actualChannel <= 7) kanal[actualChannel].fire();       // @todo cleanup dirty hardcoded 7
      else if (actualChannel >= 8 && actualChannel <= 15) kanal[actualChannel].fire();
    }
    rc[i].previousChannel = actualChannel;
  }
}

void setup() {
  Serial.begin(115200);
  for (auto &i : rc) pinMode(i.pin, INPUT);
  for (auto &i : kanal)  i.begin();
  Serial.println("und go");
}

void loop() {
  readRCinput();
  handleSerial();                     // Eingaben prüfen/verarbeiten
  uint32_t currentMillis = millis();  // der Zeitstempel wird 16 mal benötigt, daher holen wir ihn uns in eine Variable
  for (auto &i : kanal) {
    i.update(currentMillis);
  }
}

Das kommt mit mem=0

18:02:42.799 -> und go
18:02:44.333 -> Neuer Wert auf pin2 ist 0
18:02:44.333 -> pin=4 fire
18:02:44.333 -> pin=4 state=1
18:02:44.333 -> Neuer Wert auf pin2 ist -1
18:02:44.333 -> Neuer Wert auf pin2 ist 0
18:02:44.333 -> pin=4 fire
18:02:44.380 -> pin=4 state=1
18:02:44.380 -> Neuer Wert auf pin2 ist -1
18:02:44.380 -> Neuer Wert auf pin2 ist 0
18:02:44.380 -> pin=4 fire
18:02:44.380 -> pin=4 state=1
18:02:44.380 -> Neuer Wert auf pin2 ist -1
18:02:44.380 -> Neuer Wert auf pin2 ist 0
18:02:44.380 -> pin=4 fire
18:02:44.380 -> pin=4 state=1
18:02:44.426 -> Neuer Wert auf pin2 ist -1
18:02:44.426 -> Neuer Wert auf pin2 ist 0
18:02:44.426 -> pin=4 fire
18:02:44.426 -> pin=4 state=1
18:02:44.426 -> Neuer Wert auf pin2 ist -1
18:02:44.426 -> Neuer Wert auf pin2 ist 0
18:02:44.426 -> pin=4 fire
18:02:44.426 -> pin=4 state=1
18:02:44.473 -> Neuer Wert auf pin2 ist -1
18:02:44.473 -> Neuer Wert auf pin2 ist 0
18:02:44.473 -> pin=4 fire
18:02:44.473 -> pin=4 state=1
18:02:44.473 -> Neuer Wert auf pin2 ist -1
18:02:44.473 -> Neuer Wert auf pin2 ist 0
18:02:44.473 -> pin=4 fire
18:02:44.473 -> pin=4 state=1
18:02:44.473 -> Neuer Wert auf pin2 ist -1
18:02:44.473 -> Neuer Wert auf pin2 ist 0
18:02:44.473 -> pin=4 fire
18:02:44.520 -> pin=4 state=1
18:02:44.520 -> Neuer Wert auf pin2 ist -1
18:02:44.520 -> Neuer Wert auf pin2 ist 0
18:02:44.520 -> pin=4 fire
18:02:44.520 -> pin=4 state=1
18:02:44.520 -> Neuer Wert auf pin2 ist -1
18:02:44.520 -> Neuer Wert auf pin2 ist 0
18:02:44.520 -> pin=4 fire
18:02:44.520 -> pin=4 state=1
18:02:44.566 -> Neuer Wert auf pin2 ist -1
18:02:44.566 -> Neuer Wert auf pin2 ist 0
18:02:44.566 -> pin=4 fire
18:02:44.566 -> pin=4 state=1
18:02:44.566 -> Neuer Wert auf pin2 ist -1
18:02:44.566 -> Neuer Wert auf pin2 ist 0
18:02:44.566 -> pin=4 fire
18:02:44.566 -> pin=4 state=1
18:02:44.613 -> Neuer Wert auf pin2 ist -1
18:02:44.613 -> Neuer Wert auf pin2 ist 0
18:02:44.613 -> pin=4 fire
18:02:44.613 -> pin=4 state=1
18:02:44.613 -> Neuer Wert auf pin2 ist -1
18:02:44.613 -> Neuer Wert auf pin2 ist 0
18:02:44.613 -> pin=4 fire
18:02:44.613 -> pin=4 state=1
18:02:44.613 -> Neuer Wert auf pin2 ist -1
18:02:44.613 -> Neuer Wert auf pin2 ist 0
18:02:44.613 -> pin=4 fire
18:02:44.659 -> pin=4 state=1
18:02:44.659 -> Neuer Wert auf pin2 ist -1
18:02:44.659 -> Neuer Wert auf pin2 ist 5
18:02:44.659 -> pin=9 fire
18:02:44.659 -> pin=9 state=1
18:02:44.706 -> Neuer Wert auf pin2 ist -1
18:02:45.359 -> pin=4 state=0
18:02:45.685 -> pin=9 state=0

und nochmal mit mem=1

18:03:48.732 -> und go
18:03:50.225 -> Neuer Wert auf pin2 ist 2
18:03:50.225 -> pin=6 fire
18:03:50.225 -> pin=6 state=2
18:03:50.225 -> Neuer Wert auf pin2 ist -1
18:03:50.225 -> Neuer Wert auf pin2 ist 0
18:03:50.225 -> pin=4 fire
18:03:50.225 -> pin=4 state=2
18:03:50.272 -> Neuer Wert auf pin2 ist -1
18:03:50.272 -> Neuer Wert auf pin2 ist 0
18:03:50.272 -> pin=4 fire
18:03:50.272 -> pin=4 state=2
18:03:50.272 -> Neuer Wert auf pin2 ist -1
18:03:50.272 -> Neuer Wert auf pin2 ist 0
18:03:50.272 -> pin=4 fire
18:03:50.272 -> pin=4 state=2
18:03:50.272 -> Neuer Wert auf pin2 ist -1
18:03:50.272 -> Neuer Wert auf pin2 ist 0
18:03:50.272 -> pin=4 fire
18:03:50.319 -> pin=4 state=2
18:03:50.319 -> Neuer Wert auf pin2 ist -1
18:03:50.319 -> Neuer Wert auf pin2 ist 0
18:03:50.319 -> pin=4 fire
18:03:50.319 -> pin=4 state=2
18:03:50.319 -> Neuer Wert auf pin2 ist -1
18:03:50.319 -> Neuer Wert auf pin2 ist 0
18:03:50.319 -> pin=4 fire
18:03:50.319 -> pin=4 state=2
18:03:50.366 -> Neuer Wert auf pin2 ist -1
18:03:50.366 -> Neuer Wert auf pin2 ist 0
18:03:50.366 -> pin=4 fire
18:03:50.366 -> pin=4 state=2
18:03:50.366 -> Neuer Wert auf pin2 ist -1
18:03:50.366 -> Neuer Wert auf pin2 ist 0
18:03:50.366 -> pin=4 fire
18:03:50.366 -> pin=4 state=2
18:03:50.413 -> Neuer Wert auf pin2 ist -1
18:03:50.413 -> Neuer Wert auf pin2 ist 0
18:03:50.413 -> pin=4 fire
18:03:50.413 -> pin=4 state=2
18:03:50.413 -> Neuer Wert auf pin2 ist -1
18:03:50.413 -> Neuer Wert auf pin2 ist 0
18:03:50.413 -> pin=4 fire
18:03:50.413 -> pin=4 state=2
18:03:50.413 -> Neuer Wert auf pin2 ist -1
18:03:50.413 -> Neuer Wert auf pin2 ist 0
18:03:50.413 -> pin=4 fire
18:03:50.458 -> pin=4 state=2
18:03:50.458 -> Neuer Wert auf pin2 ist -1
18:03:50.458 -> Neuer Wert auf pin2 ist 0
18:03:50.458 -> pin=4 fire
18:03:50.458 -> pin=4 state=2
18:03:50.458 -> Neuer Wert auf pin2 ist -1
18:03:50.458 -> Neuer Wert auf pin2 ist 5
18:03:50.458 -> pin=9 fire
18:03:50.458 -> pin=9 state=1
18:03:50.505 -> Neuer Wert auf pin2 ist -1
18:03:50.505 -> Neuer Wert auf pin2 ist 5
18:03:50.505 -> pin=9 fire
18:03:50.505 -> pin=9 state=1
18:03:50.505 -> Neuer Wert auf pin2 ist -1
18:03:50.505 -> Neuer Wert auf pin2 ist 5
18:03:50.505 -> pin=9 fire
18:03:50.505 -> pin=9 state=1
18:03:50.552 -> Neuer Wert auf pin2 ist -1
18:03:50.552 -> Neuer Wert auf pin2 ist 5
18:03:50.552 -> pin=9 fire
18:03:50.552 -> pin=9 state=1
18:03:50.552 -> Neuer Wert auf pin2 ist -1
18:03:51.206 -> pin=6 state=3
18:03:51.253 -> pin=4 state=3
18:03:51.486 -> pin=9 state=0

Das ist doch der Pin für das einlesen des ersten Kanals, Pin 3 ist der für den zweiten

eigentlich ja. ich habe nur pin 2 aktiviert. pin 3 ist noch nicht aktiviert.

offenbar bekommst du da im Wechsel schon einen ungültigen Range - einen gültigen Range im Wechsel.
Damit klappt dann dieser Retrigger Sperre nicht wie gedacht.

Vermutlich kann man nur die Unterscheidung machen obs ein anderer GÜLTIGER Kanal ist...

Nö! :face_with_monocle:
Und offensichtlich scheint es mit dem merken da noch mehr Probleme zu geben.
volatile?

Vielleicht eine doofe Frage aber was ist denn, wenn man den case MEMB aus der void fire in die void update verpflanzt? Und dort dann den pin low schaltet und den status zurück auf idle setzt? Quasi wie beim pulsen.

          if (currentMillis - previousMillis > 1000) {   // nach n millisekunden abschalten
            digitalWrite(pin, LOW);
            state = IDLE;
            Serial.print(F("pin="));Serial.print(pin); Serial.print(F(" state=")); Serial.println(state);
          }

der Fehler liegt ja offenbar in der RC Auswertung, und nicht im Kanal sonst würde es ja über die serielle auch nicht gehen.

ich hab mal eine Zeile geändert:

// 16 Kanal Schalter für Lichtsteuerung
// Fernsteuerung: Flysky i6X
// CPU: Arduino Nano
// https://forum.arduino.cc/t/neues-rc-projekt-16-kanal-schalter-fur-lichtsteuerung/1143800/23
// 2023-07-02 noiasca
// work in progress - Testfeld

enum State {IDLE, PULSE, MEMA, MEMB};  // die einzelnen Zustände der Kanäle/Pins

class Kanal {
  protected:
    const byte channel;          // braucht es das wirklich ?!? grauslich...
    const byte pin;              // der GPIO
    const byte mem;              // Gibt das Verhalten des Pins an
    State state;                 // Status des Kanals/Pins
    uint32_t previousMillis = 0; // Zeitmanagement

  public:
    Kanal(const byte channel, const byte pin, const byte mem) : channel(channel), pin(pin), mem(mem) {}

    void fire() {
      Serial.print(F("pin=")); Serial.print(pin); Serial.println(F(" fire"));
      switch (state) {
        case IDLE:
          if (mem == 0) {
            previousMillis = millis();
            digitalWrite(pin, HIGH);
            state = PULSE;
          }
          else {
            previousMillis = millis();
            digitalWrite(pin, HIGH);
            state = MEMA;
          }
          break;
        case MEMB:
          digitalWrite(pin, LOW);
          state = IDLE;
          break;
      }
      Serial.print(F("pin="));Serial.print(pin); Serial.print(F(" state=")); Serial.println(state);
    }

    void begin() {
      pinMode(pin, OUTPUT);
    }

    void update(uint32_t currentMillis = millis()) {
      switch (state) {
        case PULSE :
          if (currentMillis - previousMillis > 1000) {   // nach n millisekunden abschalten
            digitalWrite(pin, LOW);
            state = IDLE;
            Serial.print(F("pin="));Serial.print(pin); Serial.print(F(" state=")); Serial.println(state);
          }
          break;
        case MEMA :
          if (currentMillis - previousMillis > 1000) {  // nach n millisekunden in den nächsten Status
            state = MEMB;
            Serial.print(F("pin="));Serial.print(pin); Serial.print(F(" state=")); Serial.println(state);
          }
          break;
      }
    }
};

Kanal kanal [] = {
  //                channel, Pin,  mem,   befehl auf serieller
  /*  Daten Kanal01 = */{1,   4,   1 },  // a
  /*  Daten Kanal02 = */{2,   5,   0 },  // b
  /*  Daten Kanal03 = */{3,   6,   1 },  // c
  /*  Daten Kanal04 = */{4,   7,   1 },  // d
  /*  Daten Kanal05 = */{5,   8,   0 },  // e
  /*  Daten Kanal06 = */{6,   9,   0 },  // f
  /*  Daten Kanal07 = */{7,  10,   0 },  // g
  /*  Daten Kanal08 = */{8,  11,   0 },  // h
  /*  Daten Kanal09 = */{9,  12,   0 },  // i
  /*  Daten Kanal10 = */{10, 13,   0 },  // j
  /*  Daten Kanal11 = */{11, A0,   0 },  // k
  /*  Daten Kanal12 = */{12, A1,   0 },  // l
  /*  Daten Kanal13 = */{13, A2,   0 },  // m
  /*  Daten Kanal14 = */{14, A3,   0 },
  /*  Daten Kanal15 = */{15, A4,   0 },
  /*  Daten Kanal16 = */{16, A5,   0 }
};

struct RC {
  const uint8_t pin;         // the GPIO
  uint16_t previousChannel;  // last channel or -1 if last pwm signal was invalid
};

RC rc[] {
  {2, -1},
  //{3, -1}      // @todo: zweiter RC Pin wird noch nicht funktionieren ... siehe unten
};

// nur testweise um Befehle einzugeben
void handleSerial() {
  int c = Serial.read();
  if (c >= 'a' && c <= 'p') {         // a = 0 ...  p = 15
    kanal[c - 'a'].fire();            // entsprechenden Kanal triggern
  } else if (c >= '0' && c <= '9') {  // die ersten 10 Ziffern gehen auch ;-)
    kanal[c - '0'].fire();
  }
}

// translate pulseIn length into channel 
// returns -1 if invalid
int pulseToChannel (uint16_t pulseLength) {
  switch (pulseLength) {
    case 950 ... 1050:
      return 0;
      break;                // können später mal gelöscht werden
    case 1950 ... 2050:
      return 1;
      break;
    case 1100 ... 1200:
      return 2;
      break;
    case 1800 ... 1900:
      return 3;
      break;
    case 1240 ... 1340:
      return 4;
      break;
    case 1350 ... 1450:
      return 5;
      break;
    case 1530 ... 1630:
      return 6;
      break;
    case 1660 ... 1760:
      return 7;
      break;
    default:
      return -1;    // invalid pwm range
  }
}

void readRCinput() {
  for (size_t i = 0; i < sizeof(rc) / sizeof(rc[0]); i++) {
    uint16_t pulseLength = pulseIn(rc[i].pin, HIGH, 20000);  // Read PWM pulse
    int actualChannel = pulseToChannel(pulseLength);         // try to get an channel from the pwm pulse length
    if (actualChannel != rc[i].previousChannel) {            // only react on channel state changes
      Serial.print(F("Neuer Wert auf pin")); Serial.print(rc[i].pin);
      Serial.print(F(" ist ")); Serial.println(actualChannel);
      if (actualChannel >= 0 && actualChannel <= 7) kanal[actualChannel].fire();       // @todo cleanup dirty hardcoded 7
      else if (actualChannel >= 8 && actualChannel <= 15) kanal[actualChannel].fire();

      /*  *************************** */
      if (actualChannel >= 0) rc[i].previousChannel = actualChannel;  // testweise
      /*  *************************** */

    }
    
  }
}

void setup() {
  Serial.begin(115200);
  for (auto &i : rc) pinMode(i.pin, INPUT);
  for (auto &i : kanal)  i.begin();
  Serial.println("und go");
}

void loop() {
  readRCinput();
  handleSerial();                     // Eingaben prüfen/verarbeiten
  uint32_t currentMillis = millis();  // der Zeitstempel wird 16 mal benötigt, daher holen wir ihn uns in eine Variable
  for (auto &i : kanal) {
    i.update(currentMillis);
  }
}

Jetzt funzt dat :+1:

Der Kanal lässt sich jetzt ein und aus schalten bei mem=1. Bei mem=0 pulst er auch wie er soll

was hast du denn jetzt geändert?

die Änderung hab ich dir doch mit Sternchen gekennzeichnet ...

zeig mir bitte noch eine Abfolge bei einem mem=1 Kanal.

ok, gefunden

ok, kleinen Moment bitte.

18:24:44.142 -> und go
18:24:45.546 -> Neuer Wert auf pin2 ist 2
18:24:45.546 -> pin=6 fire
18:24:45.546 -> pin=6 state=2
18:24:45.594 -> Neuer Wert auf pin2 ist -1
18:24:45.594 -> Neuer Wert auf pin2 ist 0
18:24:45.594 -> pin=4 fire
18:24:45.594 -> pin=4 state=2
18:24:45.594 -> Neuer Wert auf pin2 ist -1
18:24:45.594 -> Neuer Wert auf pin2 ist -1
18:24:45.640 -> Neuer Wert auf pin2 ist -1
18:24:45.640 -> Neuer Wert auf pin2 ist -1
18:24:45.685 -> Neuer Wert auf pin2 ist -1
18:24:45.685 -> Neuer Wert auf pin2 ist -1
18:24:45.731 -> Neuer Wert auf pin2 ist -1
18:24:45.731 -> Neuer Wert auf pin2 ist -1
18:24:45.779 -> Neuer Wert auf pin2 ist -1
18:24:45.779 -> Neuer Wert auf pin2 ist -1
18:24:45.779 -> Neuer Wert auf pin2 ist -1
18:24:45.779 -> Neuer Wert auf pin2 ist 5
18:24:45.779 -> pin=9 fire
18:24:45.827 -> pin=9 state=1
18:24:45.827 -> Neuer Wert auf pin2 ist -1
18:24:45.827 -> Neuer Wert auf pin2 ist -1
18:24:45.827 -> Neuer Wert auf pin2 ist -1
18:24:45.873 -> Neuer Wert auf pin2 ist -1
18:24:45.873 -> Neuer Wert auf pin2 ist -1
18:24:45.873 -> Neuer Wert auf pin2 ist -1

@noiasca

Wertebereich überschritten - habe ich bereits oben geschrieben.

soll egal sein, sind beides 16 bit. Ist eh viel zu groß. Ich mach jetzt int8_t draus.

@suschi77
Naming things, ich hab noch Kanal auf Output geändert

geht das immer noch ?
sind die Zeilen auf der Seriellen jetzt weniger?

// 16 Kanal Schalter für Lichtsteuerung
// Fernsteuerung: Flysky i6X
// CPU: Arduino Nano
// https://forum.arduino.cc/t/neues-rc-projekt-16-kanal-schalter-fur-lichtsteuerung/1143800/23
// 2023-07-02 noiasca
// work in progress - Testfeld

enum State {IDLE, PULSE, MEMA, MEMB};  // die einzelnen Zustände der Kanäle/Pins

class Output {
  protected:
    const byte pin;              // der GPIO
    const byte mem;              // Gibt das Verhalten des Pins an
    State state;                 // Status des Output Pins (Kanal)
    uint32_t previousMillis = 0; // Zeitmanagement

  public:
    Output(const byte pin, const byte mem) : pin(pin), mem(mem) {}

    void fire() {
      Serial.print(F("pin=")); Serial.print(pin); Serial.println(F(" fire"));
      switch (state) {
        case IDLE:
          if (mem == 0) {
            previousMillis = millis();
            digitalWrite(pin, HIGH);
            state = PULSE;
          }
          else {
            previousMillis = millis();
            digitalWrite(pin, HIGH);
            state = MEMA;
          }
          break;
        case MEMB:
          digitalWrite(pin, LOW);
          state = IDLE;
          break;
      }
      Serial.print(F("pin=")); Serial.print(pin); Serial.print(F(" state=")); Serial.println(state);
    }

    void begin() {
      pinMode(pin, OUTPUT);
    }

    void update(uint32_t currentMillis = millis()) {
      switch (state) {
        case PULSE :
          if (currentMillis - previousMillis > 1000) {   // nach n millisekunden abschalten
            digitalWrite(pin, LOW);
            state = IDLE;
            Serial.print(F("pin=")); Serial.print(pin); Serial.print(F(" state=")); Serial.println(state);
          }
          break;
        case MEMA :
          if (currentMillis - previousMillis > 1000) {  // nach n millisekunden in den nächsten Status
            state = MEMB;
            Serial.print(F("pin=")); Serial.print(pin); Serial.print(F(" state=")); Serial.println(state);
          }
          break;
      }
    }
};

Output output [] = {
  //Pin,  mem,    befehl auf serieller
  { 4,   1 },  // a 0
  { 5,   0 },  // b 1 
  { 6,   1 },  // c 2
  { 7,   1 },  // d 3
  { 8,   0 },  // e 4
  { 9,   0 },  // f 5
  {10,   0 },  // g 6
  {11,   0 },  // h 7
  {12,   0 },  // i 8
  {13,   0 },  // j 9
  {A0,   0 },  // k 
  {A1,   0 },  // l
  {A2,   0 },  // m
  {A3,   0 },  // o
  {A4,   0 },  // p
  {A5,   0 }   // q
};

struct RC {
  const uint8_t pin;         // the GPIO
  int8_t previousChannel;  // last channel or -1 if last pwm signal was invalid
};

RC rc[] {
  {2, -1},
  //{3, -1}      // @todo: zweiter RC Pin wird noch nicht funktionieren ... siehe unten
};

// nur testweise um Befehle einzugeben
void handleSerial() {
  int c = Serial.read();
  if (c >= 'a' && c <= 'p') {         // a = 0 ...  p = 15
    output[c - 'a'].fire();            // entsprechenden Kanal triggern
  } else if (c >= '0' && c <= '9') {  // die ersten 10 Ziffern gehen auch ;-)
    output[c - '0'].fire();
  }
}

// translate pulseIn length into channel
// returns -1 if invalid
int8_t pulseToChannel (uint16_t pulseLength) {
  switch (pulseLength) {
    case 950 ... 1050:
      return 0;
      break;                // können später mal gelöscht werden
    case 1950 ... 2050:
      return 1;
      break;
    case 1100 ... 1200:
      return 2;
      break;
    case 1800 ... 1900:
      return 3;
      break;
    case 1240 ... 1340:
      return 4;
      break;
    case 1350 ... 1450:
      return 5;
      break;
    case 1530 ... 1630:
      return 6;
      break;
    case 1660 ... 1760:
      return 7;
      break;
    default:
      return -1;    // invalid pwm range
  }
}

void readRCinput() {
  for (size_t i = 0; i < sizeof(rc) / sizeof(rc[0]); i++) {
    uint16_t pulseLength = pulseIn(rc[i].pin, HIGH, 20000);  // Read PWM pulse
    int actualChannel = pulseToChannel(pulseLength);         // try to get an channel from the pwm pulse length
    if (actualChannel >= 0 && actualChannel != rc[i].previousChannel) {            // only react on channel state changes
      Serial.print(F("Neuer Wert auf rc pin=")); Serial.print(rc[i].pin);
      Serial.print(F(" ist ")); Serial.println(actualChannel);
      if (actualChannel >= 0 && actualChannel <= 7) output[actualChannel].fire();       // @todo cleanup dirty hardcoded 7
      else if (actualChannel >= 8 && actualChannel <= 15) output[actualChannel].fire();
      rc[i].previousChannel = actualChannel;
    }
  }
}

void setup() {
  Serial.begin(115200);
  for (auto &i : rc) pinMode(i.pin, INPUT);
  for (auto &i : output)  i.begin();
  Serial.println("und go");
}

void loop() {
  readRCinput();
  handleSerial();                     // Eingaben prüfen/verarbeiten
  uint32_t currentMillis = millis();  // der Zeitstempel wird 16 mal benötigt, daher holen wir ihn uns in eine Variable
  for (auto &i : output) {
    i.update(currentMillis);
  }
}