LED Fade funktioniert nicht in Projekt

Hallo, bin Anfänger :grinning_face:
habe die 'kleine' Aufgabe eine LED von hell nach dunkel und zurück leuchten zu lassen, das ganze eingebunden in ein relativ kleines Projekt.
Das mit dem Hell/Dunkel geht alleine wunderbar, nimm ich diesen Code aber ins Projekt blinkt die LED nur.
Vermutlich wird die Schleife mit dem +1 bzw -1 nicht abgearbeitet.
Kann jemand helfen?
Ist der Code notwendig oder hat schon so jemand ein Tipp?

Das Programm soll eine Schranke steuern.
Bei Tastendruck (Pin 4) 3 Sekunden warten, dann Schranke für 5 Sekunden auf (Servo an 8), diese 5 Sekunden werden mit Countdown an 7-Segment LED runtergezählt. Dann Schranke zu.
Während Schranke zu (Standard) soll LED (9) immer von hell auf dunkel auf hell leuchten.
Alles funktioniert - nur das mit der LED nicht, diese blinkt nur :-(

int ledPin = 9;

#include <Servo.h>
Servo meinservo;


void setup()
{
    meinservo.attach(8);
    pinMode(4, INPUT);
    pinMode(5, OUTPUT);
    pinMode(6, OUTPUT);
    pinMode(7, OUTPUT);
    //pinMode(9, OUTPUT);
    pinMode(10, OUTPUT);
    pinMode(11, OUTPUT);
    pinMode(12, OUTPUT);
    pinMode(13, OUTPUT);
}

void loop()
{
     // fade in from min to max in increments of 5 points:
  for (int fadeValue = 0; fadeValue <= 255; fadeValue += 5) {
    // sets the value (range from 0 to 255):
    analogWrite(ledPin, fadeValue);
    // wait for 30 milliseconds to see the dimming effect
    delay(30);
  }

  // fade out from max to min in increments of 5 points:
  for (int fadeValue = 255; fadeValue >= 0; fadeValue -= 5) {
    // sets the value (range from 0 to 255):
    analogWrite(ledPin, fadeValue);
    // wait for 30 milliseconds to see the dimming effect
    delay(30);
  }
if (digitalRead(4) == HIGH)
    {
        analogWrite(ledPin, 0);
        delay(3000);
        meinservo.write(90);
        Neun();
        delay(500);
        Acht();
        delay(500);
        Sieben();
        delay(500);
        Sechs();
        delay(500);
        Fuenf();
        delay(500);
        Vier();
        delay(500);
        Drei();
        delay(500);
        Zwei();
        delay(500);
        Eins();
        delay(500);
        Null();
        delay(500);
        Aus();
        delay(1);
        meinservo.write(0);
    }
    else
        {  
        meinservo.write(0);
        }
    
}

// Unterprogramme für Countdown

void Neun(){
    digitalWrite(13,HIGH); //OR
    digitalWrite(12,HIGH); //OM 
    digitalWrite(11,HIGH); //OL
    digitalWrite(10,HIGH); //M
    digitalWrite(7,HIGH); //UR
    digitalWrite(6,HIGH); //UM
}

void Acht(){
    digitalWrite(13,HIGH);
    digitalWrite(12,HIGH);
    digitalWrite(11,HIGH);
    digitalWrite(10,HIGH);
    digitalWrite(7,HIGH);
    digitalWrite(6,HIGH);
    digitalWrite(5,HIGH); //UL
}

void Sieben(){
    digitalWrite(13,HIGH);
    digitalWrite(12,HIGH);
    digitalWrite(11,LOW);
    digitalWrite(10,LOW);
    digitalWrite(7,HIGH);
    digitalWrite(6,LOW);
    digitalWrite(5,LOW); //UL
}

void Sechs(){
    digitalWrite(13,LOW);
    digitalWrite(12,HIGH);
    digitalWrite(11,HIGH);
    digitalWrite(10,HIGH);
    digitalWrite(7,HIGH);
    digitalWrite(6,HIGH);
    digitalWrite(5,HIGH); //UL
}

void Fuenf(){
    digitalWrite(13,LOW);
    digitalWrite(12,HIGH);
    digitalWrite(11,HIGH);
    digitalWrite(10,HIGH);
    digitalWrite(7,HIGH);
    digitalWrite(6,HIGH);
    digitalWrite(5,LOW); //UL
}

void Vier(){
    digitalWrite(13,HIGH);
    digitalWrite(12,LOW);
    digitalWrite(11,HIGH);
    digitalWrite(10,HIGH);
    digitalWrite(7,HIGH);
    digitalWrite(6,LOW);
    digitalWrite(5,LOW); //UL
}

void Drei(){
    digitalWrite(13,HIGH);
    digitalWrite(12,HIGH);
    digitalWrite(11,LOW);
    digitalWrite(10,HIGH);
    digitalWrite(7,HIGH);
    digitalWrite(6,HIGH);
    digitalWrite(5,LOW); //UL
}

void Zwei(){
    digitalWrite(13,HIGH);
    digitalWrite(12,HIGH);
    digitalWrite(11,LOW);
    digitalWrite(10,HIGH);
    digitalWrite(7,LOW);
    digitalWrite(6,HIGH);
    digitalWrite(5,HIGH); //UL
}

void Eins(){
    digitalWrite(13,HIGH);
    digitalWrite(12,LOW);
    digitalWrite(11,LOW);
    digitalWrite(10,LOW);
    digitalWrite(7,HIGH);
    digitalWrite(6,LOW);
    digitalWrite(5,LOW); //UL
}

void Null(){
    digitalWrite(13,HIGH);
    digitalWrite(12,HIGH);
    digitalWrite(11,HIGH);
    digitalWrite(10,LOW);
    digitalWrite(7,HIGH);
    digitalWrite(6,HIGH);
    digitalWrite(5,HIGH); //UL
}

void Aus(){
    digitalWrite(13,LOW);
    digitalWrite(12,LOW);
    digitalWrite(11,LOW);
    digitalWrite(10,LOW);
    digitalWrite(7,LOW);
    digitalWrite(6,LOW);
    digitalWrite(5,LOW); //UL
}

Wie soll jemand ohne Deinen Code hinweise dazu geben können?
Setze Deinen Code bitte in Codetags. Wie das geht, steht hier.

Gruß Tommy

Überprüfen Sie, ob der für die LED verwendete Arduino-Pin ein PWM-Pin ist.

wenn der Sketch neben dem LED auf und ab dimmen auch noch etwas anderes tun soll, dann sollst du für das dimmen kein delay verwenden sondern du sollst das ähnlich wie "Blink Without Delay" mit millis() aufbauen.

Genaueres kann man sagen wenn du deinen Code in Code Tags postest.

Ändere die LED mal auf PIN 3.

Meine Kristallkugel sagt:
Dein geheimes Board verwendet den gleichen Timer für den PWM Pin und für den Servo!

Wenn ich die Beschreibung richtig verstanden habe, sollte folgendes Programm machen was Du willst:

#include <Servo.h>
#include <Button_SL.hpp>

//------------------------------------------------------------------
// Typalias(es)
//------------------------------------------------------------------
using Millis_t = decltype(millis());
using SegmentPins_t = uint8_t[7];
using PwmDataTable_t = uint8_t[64];

//------------------------------------------------------------------
// Global Constants
//------------------------------------------------------------------

namespace gc {
// https://www.mikrocontroller.net/articles/LED-Fading
constexpr PwmDataTable_t PwmDataTable {0,  1,  1,  2,  2,   2,   2,   2,   2,   3,   3,   3,   3,   4,   4,   4,
                                       5,  5,  6,  6,  7,   7,   8,   8,   9,   10,  11,  12,  13,  14,  15,  17,
                                       18, 20, 22, 24, 26,  28,  30,  33,  36,  39,  43,  47,  51,  55,  60,  65,
                                       71, 78, 84, 92, 100, 109, 119, 129, 141, 153, 167, 181, 198, 215, 234, 255};

// Index = Ziffer 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
constexpr uint8_t SegmentMasks[] {0b1110111, 0b0010001, 0b1101011, 0b0111011, 0b0011101,
                                  0b0111110, 0b1111110, 0b0010011, 0b1111111, 0b0111111};
//                          Segment  B   A   F   G   C  D  E
constexpr SegmentPins_t SegmentPins {13, 12, 11, 10, 9, 8, 7};

constexpr uint8_t LedPin {6};
constexpr uint8_t ServoPin {5};
constexpr uint8_t ButtonPin {4};

constexpr Millis_t FadeDelay_ms {30};
constexpr Millis_t GateOpenDelay_ms {3000};
constexpr Millis_t CountDownDelay_ms {1000};   // One Second! SeconCounter depends on this value
constexpr int8_t SecondCounter {4};
}   // namespace gc

//
// Class for enabling non-blocking timing
//
class Timer {
public:
  Timer() : TimeStamp(0), Reached(true) {}

  void start() {
    TimeStamp = millis();
    Reached = false;
  }
  void reset() { Reached = true; }

  bool operator()(const Millis_t Duration) {
    if (!Reached) { Reached = millis() - TimeStamp >= Duration; }
    return Reached;
  }

private:
  Millis_t TimeStamp;
  bool Reached;
};

//
// Class for controlling the dimming of an LED
//
class Fader {
public:
  Fader(uint8_t Pin) : Pin {Pin} {}

  void operator()(const PwmDataTable_t& Data) {
    if (Idx > -1 && Idx < static_cast<int>(sizeof(PwmDataTable_t))) {
      analogWrite(Pin, Data[Idx]);
    } else {
      Step *= -1;
    }
    Idx += Step;
  }

  void reset() {
    Step = 1;
    Idx = 0;
    analogWrite(Pin, 0);
  }

private:
  uint8_t Pin;
  int Step {1};
  int Idx {0};
};

enum class GateStates : byte { Closed, Wait, Opened };

//------------------------------------------------------------------
// Global Objects/Variables
//------------------------------------------------------------------
Servo SDevice;
Btn::ButtonSL Button {gc::ButtonPin, 500};
Fader Fade(gc::LedPin);
Timer FadeTimer;
Timer CountDownTimer;

//------------------------------------------------------------------
// Functions
//------------------------------------------------------------------

//////////////////////////////////////////////////////////////////////////////
/// \brief Displaying a digit on a 7-segment display
///        The mask passed corresponds to the digit to be displayed
///
/// \param Mask  The bitmask specifies which pins are set to HIGH or LOW.
/// \param Pins  An array of pins connected to the display's segment LEDs.
//////////////////////////////////////////////////////////////////////////////
void switchSegments(uint8_t Mask, const SegmentPins_t& Pins) {
  for (size_t I {0}; I < sizeof(SegmentPins_t); ++I) { digitalWrite(Pins[I], bit_is_set(Mask, I)); }
}

//////////////////////////////////////////////////////////////////////////////
/// \brief  Main function for controlling the gate
/// Control is handled by a finite-state machine https://www.mikrocontroller.net/articles/Statemachine
/// 
//////////////////////////////////////////////////////////////////////////////
void gateControl() {
  static GateStates States {GateStates::Closed};
  static int8_t Counter {gc::SecondCounter};

  Btn::ButtonState BtnState = Button.tick();
  if (BtnState == Btn::ButtonState::shortPressed || BtnState == Btn::ButtonState::longPressed) {
    States = GateStates::Wait;
    Fade.reset();   // Switch LED off
    CountDownTimer.start();
  }

  switch (States) {
    case GateStates::Closed:
      if (FadeTimer(gc::FadeDelay_ms)) {
        FadeTimer.start();
        Fade(gc::PwmDataTable);   // Fade LED by one step
      }
      break;
    case GateStates::Wait:        // Button was pressed, wait for "GateOpenDelay_ms" before open the gate
      if (CountDownTimer(gc::GateOpenDelay_ms)) {
        SDevice.write(90);
        States = GateStates::Opened;
      }
      break;
    case GateStates::Opened:                 // Gate is open for gc::SecondCounter * gc::CountDownDelay_ms millisconds
      if (CountDownTimer(gc::CountDownDelay_ms)) {
        CountDownTimer.start();
        if (Counter < 0) {
          switchSegments(0, gc::SegmentPins);  // 0 switches all segments off
          States = GateStates::Closed;
          Counter = gc::SecondCounter;
          SDevice.write(0);
        } else {
          switchSegments(gc::SegmentMasks[Counter + 1],
                         gc::SegmentPins);   // Counter+1 because 0 should not be displayed
          --Counter;
        }
      }
      break;
  }
}

void setup() {
  // Serial.begin(115200);
  for (const auto& Pin : gc::SegmentPins) { pinMode(Pin, OUTPUT); }
  SDevice.attach(gc::ServoPin);
  SDevice.write(0);
  Button.begin();
  Button.releaseOn();   // https://github.com/DoImant/Button_SL#methods
  switchSegments(0, gc::SegmentPins);
}


void loop() { gateControl(); }

Zum online Ausprobieren:

Der Code ist für einen Einsteiger sicher nicht einfach zu verstehen. Darum kann man das entweder verwerfen weil zu schwer verständlich oder es als Herausforderung sehen, die einzelnen Mechanismen zu verstehen...

Die Pin-Nutzung wurde verändert und stimmt nicht mehr mit Deinem Code überein.

Danke für das Beispiel. Ich nehm die 'Herausforderung' an :grinning_face:
Vielen Dank an alle für Infos und Tipps!

Ich würde vielleicht noch den zweiten Eintrag in SegmentMasks[] von 0b1000100 auf 0b0010001 ändern, da die "1" auf dem Display doch ungewohnt aussieht.

image image

Habe es geändert.

Im ersten Beispiel öffnet sich die Schranke ja sehr schnell, weil die 90° vom Servo in einem Schritt angefahren werden. Ich habe noch eine kleine Variation eingebaut, bei der die drei Sekunden Wartezeit in eine drei Sekunden "Öffnungszeit" umgewandelt werden.

Die Servobewegung auf 90° und zurück auf 0° dauert in diesem Beispiel also jeweils drei Sekunden. Das entspricht eher einer "Schrankenbewegung".

Edit:
Beide Beispiele haben noch einen kleinen Bug. Wenn der Taster während der Schrankenbewegung noch einmal gedrückt wird, so gerät alles durcheinander, weil der Tastendruck bei jedem Status ausgewertet wird. Darum empfiehlt es sich, die Tastenabfrage wie folgt zu ändern:

Btn::ButtonState BtnState = Button.tick();
  if (States == GateStates::Closed &&
      (BtnState == Btn::ButtonState::shortPressed || BtnState == Btn::ButtonState::longPressed)) {
    States = GateStates::MoveGate;
    Fade.reset();   // Switch LED off
  }