Anfänger Code Problem if-Anweisung?

Hi, ich lerne gerade Programmieren und ich bin auf ein Problem gestoßen.

Ziel dieses Codes ist das, eine LED ähnlich einer Warnleuchte für Flugverkehr auf Hochhäusern etc. von voller Helligkeit langsam dunkler wird und wenn sie aus ist 1 Sek. aus bleibt und dann wieder von voller Helligkeit dunkler wird usw...

long timer1;
byte helligkeit;

void setup() {

 helligkeit = 255;
 timer1 = millis();

pinMode(10, OUTPUT);

}

void loop() {

  if((millis() - timer1) >10) 
    
   /* wenn helligkeit null ist sollte "millis() - timer1"  ca. 1 sek lang einen negativen Wert ausgeben
   und ist somit kleiner als 10 und müsste also "false" ausgeben?!.
   */
    
  {
    analogWrite(10, helligkeit);
    helligkeit--;
    
    	if (helligkeit == 0)
          timer1 = (millis() + 1000);
    	else
     	 timer1 = millis();
    
  }

}

die 1 Sek Pause wenn Helligkeit ==0 wird einfach übersprungen,
Hauptproblem ist glaube ich die erste if-Anweisung. Diese gibt aus irgend einem Grund "true" aus und ich vermute es hängt mit der Negativen Zahl zusammen.

Oder ich habe einen Denkfehler ^^

würde mich sehr über eine Erklärung freuen warum der Sketch nicht wie gewollt funktioniert.

die delay() funktion will ich vermeiden um auch noch andere Aufgaben ausführen zu können.
die 1 Sek. Pause soll von der Variable helligkeit und nicht über einen Zeitintervall ausgelöst werden.

Vielen Dank Schonmal

Hallo bene1231
Nimm ein paar Serial.println() und lasse dir die Werte der Variablen zur Laufzeit ausgeben.

Nicht mit der negativen Zahl, sondern mit dem Überlauf. Du darfst die Timer-Variable nicht beeinflussen. Du musst das Intervall, bei dir fest 10, beeinflussen. Setze dies in einer Variable und ändere es entsprechend von 10 zu 1000 und andersherum.

(mit dem Handy getippter)

unsigned long timer1;
byte helligkeit;
unsigned int intervall;

void setup() {
  helligkeit = 255;
  intervall = 10;
  timer1 = millis();
  pinMode(10, OUTPUT);
}

void loop() {
  if((millis() - timer1) > intervall) {
    helligkeit--;
    analogWrite(10, helligkeit);
    if (helligkeit == 0) {
      intervall = 1000; 
    }
    else {
      intervall = 10;
    }
    timer1 = millis();
  }
}

Eine Erklärung gab es schon. Ich will aber noch etwas beisteuern.
Deine Aufgabe besteht eigentlich aus drei Teilen, die sich immer wiederholen.
Erst ganz hell, dann langsam dunkler werden, dann aus, Und alles wieder von vorn.
Eine typische Schrittkette.
Das ganze in Code gegossen, sieht das dann u.a. so aus:

constexpr byte ledPin = 10;
constexpr byte maxBrigth = 255;
constexpr unsigned long fullBrightTime = 250; // Zeit in ms
constexpr unsigned long downBrightTime = 10;  //
constexpr unsigned long darkTime = 1000;
unsigned long lastMillis;
byte helligkeit = maxBrigth;

enum {bright, down, dark};
byte status = bright;
void setup()
{
  Serial.begin(115200);
  Serial.println(F("Start..."));
  lastMillis = millis();
  pinMode(ledPin, OUTPUT);
}

void loop()
{
  positionsLicht();
}

void positionsLicht()
{
  analogWrite(ledPin, helligkeit);
  switch (status)
  {
    case bright:
      if (millis() - lastMillis > fullBrightTime)
      {
        lastMillis = millis();
        status = down;
        Serial.println(F("werde dunkler..."));
      }
      break;
    case down:
      if (millis() - lastMillis > downBrightTime)
      {
        lastMillis = millis();
        helligkeit--;
        Serial.println(helligkeit);
      }
      if (helligkeit == 0)
      {
        lastMillis = millis();
        status = dark;
        Serial.println(F("Bin aus..."));
      }
      break;
    case dark:
      if (millis() - lastMillis > darkTime)
      {
        lastMillis = millis();
        helligkeit = 255;
        status = bright;
        Serial.println(F("Gehe an..."));
      }
      break;
  }
}

Ich habs mit 3 Zeilen für den SerMon versehen.

Wie Du auch merkst, gibt es oben eine Menge Konstanten/Variablen. Am Beipiel von Deinem PIN 10: Wenn Du den PIN ändern willst, machst Du das oben einmal. In deinem Code müsstest Du jede Stelle suchen, wo der PIN benutzt wird. :wink:
Gleiches auch für die Zeiten.
Bei einem Dreizeiler mag das vielleicht noch gehen, aber wenn der Code länger wird, suchst Du ewig und es birgt die Gefahr irgendwann nicht den richtigen Pin zu erwischen ....

Na denne viel Spass.

Sehr gut.

Wenn es mehr derartiger LEDs bedarf, dann zahlt sich aus Klassen und Arrays zu nutzen. Eine weitere LED ist dann nur mehr die Erweiterung um den LED Pin und die Zeit.

Ich greife da jetzt einfach auf meinen LED Toolkit zurück für 3 LEDs:

/*
  Smooth LED

  This LED will
  - get brighter slowly to the maximum and
  - dimm down slowly to 0

  you must connect the LED to a PWM enabled PIN

  by noiasca
  2022-11-24
*/

#include <Noiasca_led.h>               // download library from https://werner.rothschopf.net/microcontroller/202202_tools_led_en.htm
#include <Noiasca_timer.h>

SmoothPin smoothLed[] {10, 5, 6};               // UNO PWM pins 3, 5, 6, 9, 10, 11
constexpr size_t leds {sizeof(smoothLed) / sizeof(smoothLed[0])};
LittleTimer littleTimer[] {1000, 1500, 2000};

void setup() {
  Serial.begin(115200);
  for (byte i = 0; i < leds; i++)
  {
    smoothLed[i].begin();   // you have to call the .begin() method for the LED pair
    smoothLed[i].on();      // you can switch the LED on
    littleTimer[i].start();  // start the timer
  }
}

void loop() {
  for (byte i = 0; i < leds; i++)
  {
    smoothLed[i].update();              // you have to call update() for the LED
    if (littleTimer[i].hasTriggered())  // if the defined time is over, the timer will execude the following lines
    {
      Serial.print(i); Serial.println(F(" timer has triggered"));
      smoothLed[i].toggle();
    }
  }
}

@my_xy_projekt

bei

enum {brigth, down, dark};

soll vermutlich die erste Aufzählung bright heißen.

Oh ja. Aber wenn überall Typo ist, wirds kompiliert :wink:
Berichtigt.

Ja, aufpassen: millis() gibt unsigned long zurueck. So,

if (millis() - lastMillis > downBrightTime)

gibt die absolute Differenz (da unsigned, immer als positiven Wert) zurueck.
Da Du ja

timer1 = (millis() + 1000);

gemacht hast im ersten Original Code: war das sofort beim naechsten mal erfuellt.

Auch wuerde ich pruefen, ob in:

if (millis() - lastMillis > fullBrightTime)

Klammern fehlen: was wird zuerst gemacht? Das Minus oder den Test ob lastMillis > fullBrightTime ist.

if ( (millis() - lastMillis) > fullBrightTime)

waere sicherer.

Ich wuerde persoenlich bevorzugen, mit der naechsten Zeit zu operieren, statt mit der Differenz. Die Zeit einfach voranschreiten lassen wie im normalen Leben und die Zeit in der Zukunft als naechsten Trigger errechnen:

unsigned long nextTime;
byte helligkeit;

void setup() {
 helligkeit = 255;
 nextTime = millis() + 10;
pinMode(10, OUTPUT);
}

void loop() {
  if ( millis() >= nextTime ) 
  {
    analogWrite(10, helligkeit);
    helligkeit--;
    
    	if (helligkeit == 0)
          nextTime = millis() + 1000;
    	else
     	 nextTime = millis() + 10;
  }
}

Hat aber einen Schoenheitsfehler:
millis() laeuft nach 50 Tagen ueber: es rollt zurueck nach kleinen Werten, ueber 0 von vorne.
So, in meinem Beispiel kann nextTime = millis() + 10; sehr klein werden, kurz vor Ueberlauf kommt dann mit plus 10 etwas zwischen 0..9 heraus. Und der IF-Test wird dann groesser finden, da ja millis() noch nicht uebergerollt ist. Die nextTime ist kleiner als millis().
Mal ueberlegen, wie das "Ueberlaufen" behandeln...

Tipp:
Man koennte denken:

if ( millis() == nextTime ) 

wuerde den gleichen Job tun. Ist aber gefaehrlich: wenn Programm irgendwo etwas laenger dauert, so dass millis() genau ueber nextTime "springt", sodass keine Gleichheit gefunden wird - dann dauert es 50 Tage bis es wieder gleich sein kann.
Ich verwende immer >= auch wenn ich immer die Gleichheit als Ergebnis erwarte (bei solchen Countern, Zeitwerten usw.).
Macht es sicherer.

Der falsche Weg!
Ganz sicher und ohne jeden Zweifel.

Siehe hier

Tipp: C++ Operatoren Priorität

Na klar.

Wenn man mit absoluter Differenz operiert, als:

if (millis() - lastMillis > downBrightTime)

ist das besser: nun hat man die Differenz. 0x0010 - 0xFFF0 = 0x0020.
Stimmt: wenn ich die Zeit in Zukunft verwende, rollt die ueber (war zum Nachdenken gedacht).

Operator Precedence:
War auch zum Nachdenken:
Minus ist hoeher als >= :
Operator Precedence
Mit expliziten Klammern wird es klarer (und sicherer).

Klarer?
Vielleicht.... für so manchen, vielleicht.
Allerdings wird sich jemand, dem die Prioritäten geläufig sind evtl. fragen: Wozu?

Sicherer?
Ein klares nein!
Die Prioritäten purzeln nicht plötzlich durcheinander.

Hmmmm, ich denke nur mit Erfahrung: "Coding Rules" sind besser als ein "Super-Expert-Coding-Style". Mach es doch anderen einfacherer, den Code zu verstehen.
Und sicherer meint: wenn ich andauernd die Klammern weglasse, "weil ich ja um die Reihenfolge weiss" dann kann es doch auch mal daneben gehen?

Beispiel:
Ich will zwei Zahlen in ungerade verwandeln und dann deren Summe vergleichen:

if (a | 1 + b | 1 < c)

Geht das wie beabsichtigt? NEIN!
Es waere doch besser so, oder?:

if ( ( (a | 1) + (b | 1) ) < c)

Wenn man Klammern braucht, um das auszudrücken, was man ausdrücken möchte, dann sind Klammern notwendig!
Habe ich das jemals irgendwo bezweifelt?
Kann mich nicht erinnern.

Wenn Klammern überflüssig sind, sind sie überflüssig.
Machen Menschen manchmal überflüssiges Zeug?
Ja!
Von mir aus..... gerne.... es gibt viel schlimmere Entgleisungen als ein paar Klammern zuviel.
Aber als Empfehlung, möchte ich das nicht einfach so unkommentiert durchgehen lassen.

Danke euch für die vielen Antworten.

Ich bin dafuer, anderen das Leben leichter zu machen (und diese nicht als "bloed" zu erklaeren, wenn sie ein paar mehr Klammern benutzen als "fuer Experten" notwendig).

Ich verstehe diesen Ton im Internet nicht mehr...

Was ueberfluessing ist kann nur dem Empfaenger der Nachricht ueberlassen werden. Wenn es keine Info mehr ist, weil Du es schon weisst, gut fuer Dich. Aber wenn ein anderer meinen Code liest, weiss ich doch nicht, was er weiss. Vielleicht ist diese Info (und ein paar Klammern zu viel) genau die Info die er braucht.

Vielen Dank fuer "konstruktive Diskussion" Warum tummel ich mich hier noch...?
Was ist falsch auf meiner Seite, "hilfreich" zu sein? Mann ... Man wird heute von Unbekannten, im Internet dafuer gescholten, wenn man mehr als notwendig beitragen will. Jeder kann doch aus meinen Kommentaren entnehmen, was und ob er es braucht.
Wenn DU es nicht brauchst: kein Grund mich dafuer zu schelten "nett zu sein".

und bei Bedarf kannst du deine "Lieblinge" aus dem Forum ganz einfach auf die Ignorieren-Liste setzen.

Das sehe ich auch so.
Meine (selbst auferlegte) "Zuständigkeit" liegt bei den Fakten und bei der Unterstützung Lernwilliger. Manchmal gibts auch einen Schuss aus der Blickwinkelkanone.

Honig ums Maul schmieren und Zucker in den Hintern blasen, gehört nicht dazu.
Darin bin ich einfach nicht gut genug. Das liegt nicht in meinem Kompetenzbereich.

Ja, nee...
Da verwechselst du was!
@tjaekel hält die Leser seiner Software für zu blöd (ich hätte hier das Wort nicht verwendet), um die Operatoren Rangfolge zu kennen, oder in Erfahrung zu bringen.
Und genau das macht er mir zum Vorwurf, dass er selber seine "Kunden" für Blödiane erklärt.
Das empfinde ich als ein wenig wirr.

Im Gegensatz dazu, erwarte ich von meinen Lesern, dass sie sich eigenständig kundig machen wollen/können, wenn sie irgendwas nicht verstehen. Bei Nachfragen gibts auch mal ein Stichwort für die Suche, oder auch eine kleine Erklärung, wenn der Groschen nicht fallen möchte.