Bremslicht für RC-Auto programmieren

unbestritten.

Ich habs mal umgebaut.
Zumindest kompilieren tuts...
@etoilevolante das wäre jetzt der Umbau und wir verbrauchen kein zusätzliches Array.

//#define DEBUG

#ifdef DEBUG
  #define DEBUG_P(...) Serial.print(__VA_ARGS__)
  #define DEBUG_Pln(...) Serial.println(__VA_ARGS__)
  #define BLINK_P(...) Serial.print(__VA_ARGS__)
  #define BLINK_Pln(...) Serial.println(__VA_ARGS__)
#else
  #define DEBUG_P(...)
  #define DEBUG_Pln(...)
  #define BLINK_P(...)
  #define BLINK_Pln(...)
#endif

const byte PINZAHL = 13;
union
{
  byte alle[PINZAHL];
  struct
  {
    const byte fogLight = 2;
    const byte fogLightPwm = 3;
    const byte rearLight = 4;
    const byte rechtsBlinkPwm = 5;
    const byte linksBlinkPwm = 6;
    const byte rechtsBlink = 7;
    const byte linksBlink = 8;
    const byte griffPwm = 9;
    const byte rueckLichtPwm = 10;
    const byte bremsLichtPwm = 11;
    const byte backFire = 12;
    const byte bremsLicht = 13;
    const byte frontLight = 15;
  };
} pin;

bool warnState, griffState, posLightState, backFireState, fogLightState, backwardState = false;
enum class blinkCondition : byte {links, rechts, warn, aus};
enum class lightCondition : byte {tag, nacht, aus};
lightCondition light = lightCondition::aus;
uint8_t rearLightPwm = 0;                 // Für Rücklicht...

const uint8_t numCh = 5;
const uint8_t chInputPin[numCh] = {A2, A3, A4, A5, A0};
const uint8_t CH2 = 0, CH3 = 1, CH4 = 2,  CH5 = 3, CH6 = 4;
const char myType[numCh][20] = {"CH2 Gas", "CH3 Taster", "CH4 Tag/Nacht", "CH5 BlueLEd", "CH6 Blinker"};
volatile uint16_t aktChTime[numCh] = {1500};
volatile uint16_t altChTime[numCh] = {0};
volatile bool aktChStatus[numCh] = {0};
volatile bool altChStatus[numCh] = {0};
volatile uint16_t altChInput[numCh] = {0};

uint16_t chInput[numCh] = {0};

void setup()
{
  PCICR |= B00000010;   // Enable PCIE1 Bit2 = 1 (Port C)
  PCMSK1 |= B00111101;  // Enable PCINT8 (Pin A0) & PCINT10(Pin A2) & PCINT11(Pin A3) & PCINT12(Pin A4) & PCINT13(Pin A5)
  Serial.begin(115200);
  Serial.println("\nStart ...");
  delay(1000);
  randomSeed(A1);
  for (byte b = 0; b < numCh; b++)
  {
    pinMode(chInputPin[b], INPUT);
  }
  for (byte b = 0; b < PINZAHL; b++)
  {
    digitalWrite(pin.alle[b], LOW);
    pinMode(pin.alle[b], OUTPUT);
  }
}
//
void loop()
{
  readSwitch();
  setLighting();
  kickBack();
  brakeLight();
  blinkLicht();
  frontLicht();
  rueckLicht();
  backLight();
  nebelLicht();
  griffLicht();
}
//
void readSwitch()
{
  const uint32_t timeOut = 400;  // [war ursprünglich auf 200] // Die Zeit soweit wie möglich verringern.
  static uint32_t startTime = 0;
  static bool lastState = false;
  static byte counter = 0;
  bool state = LOW;
  if (aktChTime[CH3] > 1600)
  { state = HIGH;}
  if (state != lastState)
  {
    startTime = millis();
    lastState = state;
    counter++;
  }
  if (millis() - startTime > timeOut)
  {
    switch (counter)
    {
      case 1:
        warnState = !warnState;
        DEBUG_P(F("Warnstate: "));
        DEBUG_Pln(warnState ? "ein" : "aus");
        break;
      case 2:
        griffState = !griffState;
        DEBUG_P(F("Griffstate: "));
        DEBUG_Pln(griffState ? "ein" : "aus");
        break;
      case 3:
        posLightState = !posLightState;
        DEBUG_P(F("Positionstate: "));
        DEBUG_Pln(posLightState ? "ein" : "aus");
        break;
      case 4:
        backFireState = !backFireState;
        DEBUG_P(F("Backfirestate: "));
        DEBUG_Pln(backFireState ? "ein" : "aus");
        break;
      case 5:
        fogLightState = !fogLightState;
        DEBUG_P(F("Nebelstate: "));
        DEBUG_Pln(fogLightState ? "ein" : "aus");
    }
    counter = 0;
  }
}
//
void setLighting()
{
  static lightCondition lastCondition = lightCondition::aus;
  switch (aktChTime[CH4])
  {
    case 0 ... 1200:
      light = lightCondition::nacht;
      if (lastCondition != lightCondition::nacht)
      {
        posLightState = true;
        fogLightState = true;
        lastCondition = lightCondition::nacht; // [war ursprünglich ==]
      }
      break;
    case 1300 ... 1600:
      light = lightCondition::aus;
      lastCondition = lightCondition::aus;
      break;
    case 1800 ... 2000:
      light = lightCondition::tag;
      if (lastCondition != lightCondition::tag)
      {
        posLightState = false;
        fogLightState = false;
        lastCondition = lightCondition::tag;
      }
      break;
  }
#ifdef DEBUG
  static lightCondition lastState = lightCondition::aus;
  if (lastState != light)
  {
    lastState = light;
    Serial.print(F("Licht: "));
    if (lastState == lightCondition::nacht)
    { Serial.println(F("Nacht")); }
    else if (lastState == lightCondition::aus)
    { Serial.println(F("aus")); }
    else if (lastState == lightCondition::tag)
    { Serial.println(F("Tag")); }
  }
#endif
}
//
void griffLicht()
{
  const uint8_t griffPwm = 30; // [war ursprünglich auf 100]
  uint8_t tempPwm = 0;
  if ((light != lightCondition::aus) && griffState)    // funktioniert bei Tag und Nacht!
  { tempPwm = griffPwm; }
  tempPwm ? analogWrite(pin.griffPwm, griffPwm) : digitalWrite(pin.griffPwm, LOW);
#ifdef DEBUG
  static uint8_t lastState = LOW;
  if (lastState != tempPwm)
  {
    lastState = tempPwm;
    Serial.print(F("Grifflicht: "));
    Serial.println(lastState ? "ein" : "aus");
  }
#endif
}
//
void backLight()                                             // Rückfahrscheinwerfer
{
  if ((light != lightCondition::aus) && backwardState)        // Tag und Nacht
  { digitalWrite(pin.rearLight, HIGH); }
  else
  { digitalWrite(pin.rearLight, LOW); }
#ifdef DEBUG
  static bool lastState = false;
  if (lastState != digitalRead(pin.rearLight))
  {
    lastState = !lastState;
    Serial.print(F("Rückwärts: "));
    Serial.println(lastState ? "ein" : "aus");
  }
#endif
}
//
uint16_t blueLed()                                           // verwendet von Nebelscheinwerfer
{
  const uint16_t obereSchwelle = 1900;
  const uint16_t untereSchwelle = 1100;
  uint8_t blueLight = 0;
  uint16_t temp = aktChTime[CH5];
  if (light != lightCondition::aus)                           // Wenn nicht Tag oder Nacht
  {
    if (temp > obereSchwelle)
    { blueLight = 255; }
    else if (temp > untereSchwelle)
    { blueLight = map(temp, untereSchwelle, obereSchwelle, 0, 255); }
  }
#ifdef DEBUG
  static byte lastState = 255;
  if (lastState != blueLight)
  {
    lastState = blueLight;
    Serial.print(F("blueLed: "));
    Serial.println(lastState);
  }
#endif
  return blueLight;
}
//
void nebelLicht()                                            // Nebelscheinwerfer
{
  if ((light != lightCondition::aus) && fogLightState)        // Pin 3 funktioniert Tags und Nachts
  {
    digitalWrite(pin.fogLight, HIGH);
    analogWrite(pin.fogLightPwm, blueLed());                  // gekoppelt an CH5
  }
  else
  {
    digitalWrite(pin.fogLight, LOW);
    digitalWrite(pin.fogLightPwm, LOW);
  }
#ifdef DEBUG
  static bool lastState = false;
  if (lastState != digitalRead(pin.fogLight))
  {
    lastState = !lastState;
    Serial.print(F("Nebelleuchte: "));
    Serial.println(lastState ? "ein" : "aus");
  }
#endif
}
//
void rueckLicht()
{
  if (light == lightCondition::nacht)                          // nur in Nachtkondition
  { rearLightPwm = 90; }
  else
  { rearLightPwm = 0; }
  analogWrite(pin.rueckLichtPwm, rearLightPwm);
#ifdef DEBUG
  static byte lastState = 255;
  if (lastState != rearLightPwm)
  {
    lastState = rearLightPwm;
    Serial.print(F("Rücklicht: "));
    Serial.println(lastState);
  }
#endif
}
//
void frontLicht()
{
  if (light == lightCondition::nacht)                         // nur in Nachtkondition
  { digitalWrite(pin.frontLight, HIGH); }
  else
  { digitalWrite(pin.frontLight, LOW); }
#ifdef DEBUG
  static bool lastState = false;
  if (lastState != digitalRead(pin.frontLight))
  {
    lastState = !lastState;
    Serial.print(F("Frontlicht: "));
    Serial.println(lastState ? "ein" : "aus");
  }
#endif
}
//
void linksBlinken(const byte myBlink)
{
  const uint8_t posLightPwm = 30;
  switch (myBlink)
  {
    case 0:
      digitalWrite(pin.linksBlink, LOW);
      if (light == lightCondition::aus || !posLightState)
      { digitalWrite(pin.linksBlinkPwm, LOW);}
      else
      { analogWrite(pin.linksBlinkPwm, posLightPwm);}
      break;
    case 1: digitalWrite(pin.linksBlink, HIGH); break;
    case 2: digitalWrite(pin.linksBlink, !digitalRead(pin.linksBlink)); break;
  }
  if (myBlink)
  { digitalWrite(pin.linksBlinkPwm, digitalRead(pin.linksBlink)); }
}
//
void rechtsBlinken(const byte myBlink)
{
  const uint8_t posLightPwm = 30;
  switch (myBlink)
  {
    case 0:
      digitalWrite(pin.rechtsBlink, LOW);
      if (light == lightCondition::aus || !posLightState)
      { digitalWrite(pin.rechtsBlinkPwm, LOW); }
      else
      { analogWrite(pin.rechtsBlinkPwm, posLightPwm); }
      break;
    case 1: digitalWrite(pin.rechtsBlink, HIGH);  break;
    case 2: digitalWrite(pin.rechtsBlink, !digitalRead(pin.rechtsBlink)); break;
  }
  if (myBlink)
  { digitalWrite(pin.rechtsBlinkPwm, digitalRead(pin.rechtsBlink)); }
}
//
void blinkLicht()
{
  blinkCondition zustand = blinkCondition::aus;                  // Vorbelegung
  static blinkCondition lastBlinkCondition = blinkCondition::warn;
  byte blinkByte = 0;                                            // 0=aus, 1=an, 2=toggle
  const uint32_t blinkTime = 500;
  static uint32_t lastBlinkTime = 0;
  if (light != lightCondition::aus)
  {
    if (warnState)                                                 // Warnblinker?
    { zustand = blinkCondition::warn; }
    else if (aktChTime[CH6] < 1300)                                // links?
    { zustand = blinkCondition::links; }
    else if (aktChTime[CH6] > 1700)                                // rechts?
    { zustand = blinkCondition::rechts; }
  }
  //
  if (zustand != lastBlinkCondition)                             // Neue Auswahl?
  {
    blinkByte = 1;                                               // Startbyte setzen
    lastBlinkCondition = zustand;                                // merken
    lastBlinkTime = millis();
  }
  else
  { blinkByte = 2; }                                             //  oder wenn nicht, dann blinkt es
  //
  if (zustand == blinkCondition::aus)
  {
    linksBlinken(0);
    rechtsBlinken(0);
  }
  else if ((blinkByte == 2 && millis() - lastBlinkTime > blinkTime) || blinkByte == 1)
  {
    lastBlinkTime = millis();
    switch (zustand)
    {
      case blinkCondition::links:  { linksBlinken(blinkByte); rechtsBlinken(0); }  break;
      case blinkCondition::rechts: { rechtsBlinken(blinkByte); linksBlinken(0);} break;
      case blinkCondition::warn:
        {
          rechtsBlinken(blinkByte);
          linksBlinken(blinkByte);
        }
        break;
      default: break;
    }
  }
}
//
void kickBack()
{
  const uint16_t minSpeed = 1880;                           // SpeedWert ab wann ausgelöst
  static uint32_t blinkTime = 0;                            // Zeitmerker
  static uint32_t lastFireTime = 0;                         // Letzter Umschaltvorgang LED
  static bool ledStatus = LOW;
  if ((light != lightCondition::aus) && backFireState)      // aktiv
  {
    if (aktChTime[CH2] > minSpeed)                          // Schnell genug
    {
      if (millis() - lastFireTime > blinkTime)              // Umschaltzeit erreicht
      {
        ledStatus = !digitalRead(pin.backFire);            // Toggel
        blinkTime = random(30, 100);                        // neue Zufallszeit
        if (!digitalRead(pin.backFire))                    // Pin ist aus?...
        { blinkTime *= 3; }                                 // ... Auszeit verlängern
        lastFireTime = millis();                            // umschaltzeit merken
        DEBUG_Pln(F("BackFire"));
      }
    }
    else
    { ledStatus = LOW; }
  }
  digitalWrite(pin.backFire, ledStatus);
}
//
void brakeLight()
{
  enum condition {forward, neutral, backward};
  static byte myState = condition::neutral;
  static uint32_t lastForwardTime = 0;                      // Zeitmerker
  const uint32_t reaktionsZeit = 200;                       // Zeit in ms... Das muss getestet werden
  const uint16_t neutralSpeed = 1490;                       // Hier ist nüscht
  const uint8_t  hysterese = 200;                           // Pendel der Neutralstellung +/-
  static bool ledStatus = LOW;
  if (light == lightCondition::aus)                         // kein Licht
  { myState = condition::neutral; }
  switch (myState)
  {
    case condition::forward:
      if (aktChTime[CH2] < neutralSpeed + hysterese)        // Neutralbereich erreicht?
      {
        myState = condition::neutral;                       // Zustand setzen
        lastForwardTime = millis();                         // Zeit merken
      }
      if (aktChTime[CH2] < neutralSpeed - hysterese)        // Neutralbereich unterschritten?
      { myState = condition::backward; }                    // direkt Zustand wechseln
      break;
    case condition::neutral:
      if (aktChTime[CH2] < neutralSpeed - hysterese)        // Neutralbereich rückwärts verlassen?
      { myState = condition::backward; }
      else if (aktChTime[CH2] > neutralSpeed + hysterese)   // Neutralbereich vorwärts verlassen?
      { myState = condition::forward;  }
      backwardState = false;                                // merken das nicht mehr zurück gefahren
      ledStatus = LOW;                                      // merken das nicht gebremst wird
      break;
    case condition::backward:
      if (millis() - lastForwardTime < reaktionsZeit)       // Zeit nicht abgelaufen ...
      { ledStatus = HIGH; }                                 // ... Bremse aktivieren
      if (!ledStatus)                                       // Bremse nicht aktiv ...
      { backwardState = true; }                             // ... dann Rückwärts
      if (aktChTime[CH2] > neutralSpeed - hysterese)        // Neutralbereich vorwärts verlassen? ...
      { myState = condition::neutral; }                     // ... Zustand setzen
      break;
  }
  // Ab hier Ausgabe
  if (ledStatus)                                            // Bremse aktiviert?
  {
    digitalWrite(pin.bremsLicht, HIGH);
    digitalWrite(pin.bremsLichtPwm, HIGH);
  }
  else                                                      // keine Bremse
  {
    analogWrite(pin.bremsLichtPwm, rearLightPwm);          // Grundhelligkeit setzen...
    digitalWrite(pin.bremsLicht, LOW);                     // ... anderen ganz aus
  }
#ifdef DEBUG
  static bool lastState = false;
  if (lastState != digitalRead(pin.bremsLicht))
  {
    lastState = !lastState;
    Serial.print(F("Bremslicht: "));
    Serial.println(lastState ? "ein" : "aus");
  }
#endif
}
//
void printSerialChInput()
{
  for (byte b = 0; b < numCh; b++)
  {
    if (abs(int(altChTime[b] - aktChTime[b])) > 10)
    {
      DEBUG_P(myType[b]);
      DEBUG_P(": ");
      DEBUG_P(aktChTime[b]);
      DEBUG_Pln('\t');
      altChTime[b] = aktChTime[b];
    }
  }
}
//
ISR (PCINT1_vect)  // Port C Interrupt occured
{
  for (byte b = 0; b < numCh; b++)
  {
    aktChStatus[b] = digitalRead(chInputPin[b]);
    if (altChStatus[b] != aktChStatus[b])
    {
      altChStatus[b] = aktChStatus[b];
      if (aktChStatus[b])
      { altChInput[b] = micros(); }
      else
      { aktChTime[b] = micros() - altChInput[b]; }
    }
  }
}