Anfängerfrage bezüglich Modellbahn-Hausbeleuchtung

Hallo zusammen,

vermutlich werden jetzt einige von euch nur meine Frage belächen, andere würden mich am liebsten steinigen, weil man sowas einfach zu wissen hat. Da ich aber totaler Anfänger bin und im Moment keine Lösung finde, stelle ich meine Frage trotzdem.

Ich möchte ein belebtes Haus für die Modellbahn realisieren. Das aktuelle Sketch sieht so aus und funktioniert auch problemlos.

int led0 = 10;
int led1 = 11;
int led2 = 12;
int led3 = 13;
int led4 = 9;

int del = 300;

void setup()  {
  pinMode(led0, OUTPUT);
  pinMode(led1, OUTPUT);
  pinMode(led2, OUTPUT);
  pinMode(led3, OUTPUT);
  pinMode(led4, OUTPUT);
  }

void loop()
{
  digitalWrite(led1, HIGH);
  delay(5000);
  digitalWrite(led2, HIGH);
  delay(5000);
  digitalWrite(led3, HIGH);
  delay(8000);
  digitalWrite(led4, HIGH);
  delay(4000);
  digitalWrite(led2, LOW);
  delay(3000);
  digitalWrite(led0, HIGH);
  delay(10000);
  digitalWrite(led4, LOW);
  delay(4000);
  digitalWrite(led1, LOW);
  delay(5000);
  digitalWrite(led0, LOW);
  delay(5000);
  digitalWrite(led3, LOW);
  delay(7000);
  digitalWrite(led1, LOW);
  delay(3000);
}

Jetzt würde ich gerne mit led0 das Flackern eines Fernsehers simulieren, was ich mit folgendem Sketch auch ganz gut hinbekommen habe.

int led0 = 10;

void setup()
{
pinMode(led0, OUTPUT);
}

void loop() {
analogWrite(led0, random(100)+220);
delay(random(200));
}

Aber nun zu meiner eigentlichen Frage!

Wie kann ich den Sketch für das Flackern in den ersten Sketch einbinden? Ich habe das digitalWrite für die led0 durch

analogWrite(led0, random(100)+220); delay(random(200));

ersetzt.

Sobald jedoch das nächste delay im Programm kommt, flackert led0 nicht mehr, sondern geht auf Dauerlicht.

Es gibt dafür mit Sicherheit eine ganz einfache Lösung, was aber wenig nützt, wenn man (ich) nicht genug Ahnung hat.

Es wäre schön, wenn ihr mir etwas auf die Sprünge helfen würdet.

Viele Grüße Herbert

Du darfst kein delay() verwenden da diese Funktion die Abarbeitung des Sketches für die Wartezeit anhält. Benutze millis(). http://arduino.cc/en/Tutorial/BlinkWithoutDelay Grüße Uwe

hi,

erstens: herzlich willkommen, keiner wird Dich steinigen.

ein delay hält den kompletten controller an, das heißt, in dieser zeit läuft auch nichts weiter, das an anderer stelle programmiert ist. dadurch Dein problem. Du mußt, wenn Du eine bestimmte sache warten lassen willst, die "uhrzeit" am anfang dieser "pause" messen (millis, die interne "uhr" des controllers). und dann immer wieder schauen, "wie spät" es ist und ob die erwünschte wartezeit schon vorbei ist. dadurch können andere prozesse weiterlaufen. das von uwe gepostete beispiel zeigt das. wenn Du noch probleme hast, einfach wieder melden...

gruß stefan

Hallo Uwe und Stefan,

vielen Dank für eure schnellen Antworten.

Da ich nicht das Programmiergenie bin, verstehe ich nicht ganz was ich wo in meinem sketch ändern muß.

Könnt ihr mir das vielleicht anhand meines sketches erklären, so daß auch ich es kappieren muß?

Viele Grüße Herbert

herbi39: Könnt ihr mir das vielleicht anhand meines sketches erklären, so daß auch ich es kappieren muß?

Ganz einfach: alle delay() rausschmeissen und mit millis() machen.

Wie das geht, wird hier beschrieben:

uwefed: Du darfst kein delay() verwenden da diese Funktion die Abarbeitung des Sketches für die Wartezeit anhält. Benutze millis(). http://arduino.cc/en/Tutorial/BlinkWithoutDelay Grüße Uwe

Eisebaer: erstens: herzlich willkommen, keiner wird Dich steinigen.

Sicher? :grin: Nein, natürlich wird hier niemand gesteinigt. Ich bin eher für Teeren und Federn nach guter alter Piratensitte! ;)

Die Kollegen haben ja bereits die bösen delays als Ursache benannt und auch den Sketch zur Vermeidung der delays genannt. Ich denke, wenn du den voll und ganz verstanden hast, kann man einen Schrit weitergehen. Mich erinnerte die Problemstellung an diesen Thread, wo es darum ging, unterschiedliche Blinksequenzen abzuspielen:

http://arduino.cc/forum/index.php/topic,146086.0.html

Ich denke, dass man darauf gut zurückgreifen kann.

hi,

naja, sth, das wurde dann bald von udo und jurs übernommen, ich glaube nicht, daß der threadstarter viel gelernt hat. und darum geht's auch bei Dir, herbert, es kommt darauf an, ob Du's lernen willst oder eine fertige lösung. wenn ersteres, mußt Du Dich ein wenig einlesen, im zweiten fall wartest Du auf jurs ;) . er programmiert und hilft gerne, und in zwei tagen steuert Deine modellbahn die klospülung (anerkennung, jurs, nicht spott, ehrlich). es kommt also auf Deine intention an...

gruß stefan

hallo stefan,

es ist nicht so, daß ich nicht lernen will!

Bevor ich hier gefragt habe, habe ich mir schon viele andere sketche angeschaut und versucht es selbst zu lösen. Da ich aber mehr der Handwerker und nicht der Denker bin, fühle ich mich im Moment etwas überfordert.

Hatte gehofft, daß mir jemand meinen sketch entsprechend korrigiert und mit entsprechenden Kommentarzeilen erklärt.

Dann muß ich wohl auf jurs warten, dann kann er sich und vorallem mir eine Freude machen ;o))

Grüße Herbert

Hallo Herbert,

hast die mal das Beispiel angesehen, welches Uwe verlinkt hat?

Gruß, Jürgen

Hallo Jürgen,

ja, habe ich, auch schon bevor ich hier gefragt habe, nur muß ich gestehen, daß ichs nicht wirklich verstanden habe.

Gibts denn irgendwo im Netz oder als Buch eine Anleitung, die auch jemand im reiferen Alter ohne gute Englischkenntnisse kappiert?

Ich möchte ja garnicht so tief in die Programmierung einsteigen, sondern nur daß die Häuschen auf der Modellbahn belebt wirken.

Der sketch wird dann in einen Attiny45 übertragen, damit in jedem Haus ein anderes Szenario abläuft. (Die Programmierung des Attiny habe ich schon hin bekommen)

Viele Grüße Herbert

Um zu wissen ob eine gewisse Zeit vergangen ist hast Du 2 Möglichkeiten: 1) die 1000/stel Sekunden zu zählen und nichts anderes dabei zu tun wei Du Dich ja darauf konzentrieren mußt = delay() 2) immer wieder auf die Uhr zu schauen ob die zu wartende zeit vorbei ist und zwischenzeitlich etwas anderes zu machen = millis()

Millis ist eine Funktion die Dir die Millisekunden zurückgibt, die seit em einschelten des Arduino vergangen ist. Um eine Verzögerung zu haben speicherst Du am Anfang die millis() in einer Variablen ab:

unsigned long previousMillis = millis();

dann kontrollierst Du ob die Wartezeit ( interval ) vorbei ist:

loop()
{ 
  if(millis() - previousMillis > interval) 
    {
    mach igendwas;
    }
  mach noch was anderes;
}

Grüße Uwe

Als Starthilfe mal eine kurze Erklärung:

Aufgabe: Schalte das Licht EIN und nach 10min wieder AUS und nach 10min wieder ein.

Es gibt zwei Möglichkeiten das zu tun: a) Licht einschalten. 10min neben dem Schalter stehen bleiben, nicht anderes tun. Licht ausschalten 10min neben dem Schalter stehen bleiben, nicht anderes tun. Licht einschalten (das die Variante mit delay())

b) Licht einschalten. Uhrzeit merken, zu der man eingeschaltet hat. Was anderes tun, dabei gelegentlich auf die Uhr schauen, wie spät es ist Wenn die 10min um sind, Licht ausschalten, neue Uhrzeit merken.

Die Programmtechnische Umsetzung von a) kennst du ja schon, die sieht so aus:

  digitalWrite(LED1, HIGH);
  delay(600000);
  digitalWrite(LED1, LOW);
  delay(600000);

Die Umsetzung von b) könnte so aussehen:

//zuerst die Variablen deklarieren:
unsigned long int Startzeit;
int LED1_Status = LOW;
define Schaltdauer  600000;  // das sind 10min in millisekunden

  if(millis()- Startzeit > Schaltdauer) {               //    Sind die 10min schon um?
    Startzeit = millis();                                      //    ja: "auf die Uhr schauen", die Zeit merken
    if (LED1_Status == LOW)                              //          Ist die Lampe gerade an oder aus?
      LED1_Status= HIGH;                                  //              Aus: Einschalten merken
    else                                                            //
      LED1_Status= LOW;                                  //               Ein: Ausschalten merken

    digitalWrite(LED1, LED1_Status);                 //         Lampe schalten.
}

edit: Uwe war wieder mal schneller.... :(

Eisebaer:
und darum geht’s auch bei Dir, herbert, es kommt darauf an, ob Du’s lernen willst oder eine fertige lösung.
wenn ersteres, mußt Du Dich ein wenig einlesen, im zweiten fall wartest Du auf jurs :wink: .

Meine Demoprogramme sind ganz normale Demoprogramme im Quelltext, die man an eigene Anforderungen anpassen kann und aus denen man lernen kann, wie man ein Problem lösen kann. Nichts anderes als die “fertigen Arduino-Demoprogramme”, vielleicht mit ein paar mehr Zeilen Code und ein wenig zusätzlicher Funktionalität.

Wenn man aus “fertigen” Demoprogrammen anderer nichts lernen könnte, dann würde hier nicht jedesmal wenn es ums Blinken geht, von einem oder gleich von mehreren Leuten der Verweis auf das Tutorial-Demoprogramm “BlinkWithoutDelay” kommen.

Hier also meine Version eines Demoprogramms im Stil von “BlinkWithoutDelay”:

  • Steuert im Gegensatz zu “BlinkWithoutDelay” gleich mehrere blinkende LEDs auf einmal
  • Steuert auch eine zufällig “flimmernde” LED

herbi39:
Hatte gehofft, daß mir jemand meinen sketch entsprechend korrigiert und mit entsprechenden Kommentarzeilen erklärt.

Wie andere schon festgestellt haben: Deinen Sketch hast Du mit dem allerersten “delay()” bereits total vergeigt, das Du in den Quellcode reingeschrieben hast. An dem Sketch gibt es nichts zu korrigieren, der muß komplett anders aufgebaut sein. Natürlich gibt es immer mehrere Möglichkeiten, so etwas zu machen. Aber alle Lösungen, um Dinge in einem Arduino-Sketch “quasi zeitlich parallel” ablaufen zu lassen, müssen ohne delay() auskommen, um praktikabel zu sein.

Das Jurs-Demoprogramm des Tages zum Thema “Blinken ohne Delay” wäre eine Möglichkeit, wie es funktionieren kann:

/*  Simulation "belebtes Haus für die Modellbahn" by jurs */
byte pwmFlimmerPin=10; // PWM Pin für das "analoge" Flimmern
// LED Pins für das normale Blinken deklarieren
byte leds[]   ={   8,    9,   11,   12,   13};
// LED Blinktakt in Millisekunden für diese Pins
long ledtakt[]={1500, 2200, 3333, 5000, 7100};
// Variablen zum Merken von millis()-Zeiten beim Schalten/Blinken
long ledtime[sizeof(leds)];

void setup() {
//  Serial.begin(9600);
  // Alle verwendeten Pins auf OUTPUT setzen
  pinMode(pwmFlimmerPin, OUTPUT);  
  for (int i=0;i<sizeof(leds);i++)
    pinMode(leds[i], OUTPUT);
}

boolean milliSekundenTakt(long dauer, long &alterWert) {
// Parameter "dauer": Dauer einer Blinkphase (an bzw. aus)
// Parameter "alterWert": Variable zum Speichern des millis() Timers
// Rückgabewert: true wenn die Zeit bis zum nächsten Umschalten abgelaufen ist, sonst false
  if (millis() - alterWert < dauer) return false;
  while (millis() - alterWert >= dauer) alterWert+=dauer;
  return true;  
}

void blinkenImTakt() {
// Alle gleichmäßig blinkenden LEDs in ihrem eigenen Takt blinken lassen  
  for (int i=0;i<sizeof(leds);i++) // alle LEDs in einer Schleife durchgehen
  {
    if (milliSekundenTakt(ledtakt[i],ledtime[i])) // Takt für diese LED abgelaufen?
    {
      digitalWrite(leds[i],!digitalRead(leds[i]));  // wenn ja ==> Umschalten
//      Serial.print("Pin ");Serial.print(leds[i]);Serial.print(" = ");Serial.println(digitalRead(leds[i]));
    }
  }
}

void flimmernPwmPin() {
// Die flimmernde LED im Zufallsmodus flimmern lassen
  static long alterWert;
  static int flimmerDauer=200;
  static byte flimmerHelligkeit;
  if (milliSekundenTakt(flimmerDauer,alterWert)) // Takt abgelaufen?
  {
    flimmerDauer=1+random(200); // neue Flimmerdauer als Zufallswert
    flimmerHelligkeit=random(256); // neue Flimmerhelligkeit als Zufallswert
    analogWrite(pwmFlimmerPin, flimmerHelligkeit); 
  }  
}

void loop() {
  blinkenImTakt();
  flimmernPwmPin();
}

Es ist mir schleierhaft, wie man der Meinung sein kann, aus einem Arduino-Demoprogramm wie “BlinkWithoutDelay” könne man “alles selbst lernen” und aus einem Jurs-Demoprogramm mit ein paar mehr Zeilen könne man vergleichsweise “nichts” bis “wenig” lernen.

P.S.: Verbesserte Codeversion mit “Flimmerpin”, der nach der Zimmerbeleuchtung ein-, aber früher wieder ausgeschaltet wird, in Reply #19

guntherb: edit: Uwe war wieder mal schneller.... :(

Entschuldige :roll_eyes:

Hallo zusammen,

erst mal danke an euch alle, ich denke was ihr geschrieben habt, bringt mich ein großes Stück weiter.

Ich werde mich dann heute Abend mal in Ruhe damit beschäftigen.

Sollte ich wieder Erwarten, doch nicht zurecht kommen, werde ich mich wieder melden.

Denn ich habe das Gefühl "Hier werden sie geholfen" ;o))

Danke nochmals und einen schönen Abend Herbert

hi, jurs,

alles hat auf Dich gewartet... 8) also es würde mir niemals einfallen, die art, wie Du hilfst, zu kritisieren. Du kommentierst sehr gut, stehst für erklärungen jederzeit zur verfügung, und vor allen imponiert mir, wie Du oft ohne die hardware eine softwarelösung rauswirfst. was dann jemand draus macht, ist seine sache. solange Dir das programmieren spaß macht...

gruß stefan

Es ist mir schleierhaft, wie man der Meinung sein kann, aus einem Arduino-Demoprogramm wie “BlinkWithoutDelay” könne man “alles selbst lernen” und aus einem Jurs-Demoprogramm mit ein paar mehr Zeilen könne man vergleichsweise “nichts” bis “wenig” lernen.

Eisbär Stefan hat schon recht.

Nur:

  • BlinkWithoutDelay ist “lehrreich”, weil es so primitiv ist, dass jeder es maximal als Start für eigene Versuche nimmt.
  • Eine typische jurs-Lösung ist hingegen perfekt und fertig, dass jeder sich hütet, eine Änderung vorzunehmen.
    (mehr überspitzen ging jetzt nicht)
    Im Unterschied zu anderen “gefundenen” Sketchen ist der Support natürlich bei jurs auch perfekt.
    Und weil die Lösung ja schon maßgeschneidert passt, ist das Verstehen auch weniger nötig.

Natürlich kann man von jurs sehr viel lernen, nur kann man es auch bleiben lassen :wink:

was dann jemand draus macht, ist seine sache

Richtig, ausserdem:
Der Erfolg der Arduinos beruht ja auch auf der immensen Menge an fertigen Sketchen, die überall fertig zum Kopieren rumschwirren.
So kann man auch mit “Programmieren ist nichts für mich” oder “Pointer sind mir zu kompliziert” zu tollen Ergebnissen kommen.
Und das ist gut so.

Hallo zusammen,

der sketch von jurs aus Reply #12 funktioniert einwandfrei, (auch auf dem Attiny45)! Vielen Dank dafür jurs!

Allerdings bin ich nun wieder an einem Punkt, an dem ich nicht weiter weiß.

Wie bekomme ich es hin, daß die "Flimmer LED" nicht dauernd flimmert, sondern nur zusammen mit LED13 an ist? Optimal wäre es, wenn die "Flimmer LED" erst einige Sekunden nach LED13 angeht und auch einige Sekunden vor LED13 wieder ausgeht.

Viele Grüße Herbert

dass jeder sich hütet, eine Änderung vorzunehmen

war gar nicht überspitzt ???

Wie bekomme ich es hin, daß die "Flimmer LED" nicht dauernd flimmert, sondern nur zusammen mit LED13 an ist?

Mach erst LED13 an, und rufe

  flimmernPwmPin();

erst auf, wenn seitdem deine Wartezeit vobei ist

Wo ist dein Problem ?

herbi39:
Wie bekomme ich es hin, daß die “Flimmer LED” nicht dauernd flimmert, sondern nur zusammen mit LED13 an ist?
Optimal wäre es, wenn die “Flimmer LED” erst einige Sekunden nach LED13 angeht und auch einige Sekunden vor LED13 wieder ausgeht.

Da gibt es natürlich wieder ganz viele Möglichkeiten.

So auf die Schnelle fällt mir ein:

  • Zwei globale Variablen (flimmerStart,flimmerEnd) für die Anfangs- und Endflimmerzeit deklarieren
  • Wenn die Pin-13 LED angeht, die Werte dieser beiden Variablen (flimmerStart,flimmerEnd) setzen
  • Und in der Flimmerfunktion außerhalb der Flimmerzeiten immer Helligkeit 0 beim Flimmern setzen
/*  Simulation "belebtes Haus für die Modellbahn" by jurs */
/*  Version "Flimmern nur wenn die Pin-13 LED an ist */
byte pwmFlimmerPin=10; // PWM Pin für das "analoge" Flimmern
long flimmerStart,flimmerEnd; // Anfangs- und Endzeiten für das Flimmern
// LED Pins für das normale Blinken deklarieren
byte leds[]   ={   8,    9,   11,   12,   13};
// LED Blinktakt in Millisekunden für diese Pins
long ledtakt[]={1500, 2200, 3333, 5000, 9100};
// Variablen zum Merken von millis()-Zeiten beim Schalten/Blinken
long ledtime[sizeof(leds)];

void setup() {
//  Serial.begin(9600);
  // Alle verwendeten Pins auf OUTPUT setzen
  pinMode(pwmFlimmerPin, OUTPUT);  
  for (int i=0;i<sizeof(leds);i++)
    pinMode(leds[i], OUTPUT);
}

boolean milliSekundenTakt(long dauer, long &alterWert) {
// Parameter "dauer": Dauer einer Blinkphase (an bzw. aus)
// Parameter "alterWert": Variable zum Speichern des millis() Timers
// Rückgabewert: true wenn die Zeit bis zum nächsten Umschalten abgelaufen ist, sonst false
  if (millis() - alterWert < dauer) return false;
  while (millis() - alterWert >= dauer) alterWert+=dauer;
  return true;  
}

void blinkenImTakt() {
  
// Alle gleichmäßig blinkenden LEDs in ihrem eigenen Takt blinken lassen  
  for (int i=0;i<sizeof(leds);i++) // alle LEDs in einer Schleife durchgehen
  {
    if (milliSekundenTakt(ledtakt[i],ledtime[i])) // Takt für diese LED abgelaufen?
    {
      digitalWrite(leds[i],!digitalRead(leds[i]));  // wenn ja ==> Umschalten
      if (leds[i]==13 && digitalRead(leds[i])) // Pin-13 LED wurde gerade eingeschaltet
      {
       flimmerStart=millis()+2000; // Anfangszeit für das Flimmern setzen
       flimmerEnd =millis()+8000;  // Endzeit für das Flimmern setzen
      }  
//      Serial.print("Pin ");Serial.print(leds[i]);Serial.print(" = ");Serial.println(digitalRead(leds[i]));
    }
  }
}

void flimmernPwmPin() {
// Die flimmernde LED im Zufallsmodus flimmern lassen
  static long alterWert;
  static int flimmerDauer=200;
  static byte flimmerHelligkeit;
  if (milliSekundenTakt(flimmerDauer,alterWert)) // Takt abgelaufen?
  {
    flimmerDauer=1+random(200); // neue Flimmerdauer als Zufallswert
    if (millis()>flimmerStart && millis()<flimmerEnd)
      flimmerHelligkeit=random(256); // neue Flimmerhelligkeit als Zufallswert
    else  
      flimmerHelligkeit=0; // Flimmern aus wenn falsche Zeit zum Flimmern
    analogWrite(pwmFlimmerPin, flimmerHelligkeit); 
  }  
}

void loop() {
  blinkenImTakt();
  flimmernPwmPin();
}

Das schöne an übersichtlichem und strukturiertem Code ist: Er läßt sich auch relativ leicht erweitern.