Blink without delay ... theoretischer Terror für Anfänger

Tach zusammen,

als blutiger Anfänger komme ich einfach nicht auf die Lösung und ich hoffe, mir erbarmt sich hier jemand. Ich such schon 2 Tage und ich kann es nicht mehr sehen, dieses delay(xy) überall. ... es geht um das gute alte Blink without Delay Beispiel und ich weiß, hier wird sich immer schwer getan, Code zu "herzugeben". Vermutlich fehlt mir noch das Wissen, welche Befehle und Variablen es sonst noch so gibt, daher versuche ich es mal theoretisch mit dieser einen, verdammten Led, die ich Flashen will:

Blink without delay schaltet doch die Led ein nach nem Interval von sagen wir mal 1000 Wie bekomm ich denn die Led dazu, dann nur 100 aktiv zu sein und wieder 1000 zu warten, bis sie wieder aktiv wird? int warten = 1000: int ledAn = 100; ledstate = false; Ich denk mir gerade: ich müsste in einem Wert speichern, dass die Led gerade geschaltet wurde im Sinne von

ledstate=true

und dann in irgend einer Form sagen: wenn ledstate = false, warte 1000 wenn ledstate = true, warte nur 100

wenn das der Weg sein sollte: sind das mehrere IF, While, For oder was für Schleifen, Argumente???

edit: weil so tut sich ... garnix

int strobes = 5;

boolean ledon = false;

unsigned long timetowait=2500;
unsigned long flashtime=100;
unsigned long previousMillis = 0;
int strobestate=0;

void setup() {
}

void loop(){
  
  unsigned long currentMillis = millis();
  
  if(currentMillis - previousMillis > timetowait){
    previousMillis = currentMillis;
    ledon = true;
    if(strobestate == 0)
    strobestate = 100;
    else
    ledon = false;
    strobestate = 0;
    
    analogWrite(strobes,strobestate);
  
  if((ledon=true)&& currentMillis - previousMillis > flashtime){
    previousMillis=currentMillis;
    if (strobestate==100)
    strobestate=0;
    ledon = false;
    analogWrite(strobes,strobestate);
  }
}
}

summ:
Wie bekomm ich denn die Led dazu, dann nur 100 aktiv zu sein und wieder 1000 zu warten, bis sie wieder aktiv wird?

Du schreibst einfach ein Programm, das genau das macht.

Zum Beispiel:

#define LEDPIN 13

void blinkWithoutDelay(int pin, int off, int on)
{
  int blinkPhase=millis()%(off+on);
  if (blinkPhase<off) digitalWrite(pin, LOW);
  else digitalWrite(pin, HIGH);
}

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

void loop(){
  blinkWithoutDelay(LEDPIN, 1000, 100);
}

In diesem Beispielsketch berechne ich ständig den Rest der ganzzahligen Division des millis() Zählers geteilt durch die gesamte Phasenlänge “off+on”. Mit off=1000 und on=100 und der gesamten Phasenlänge von 1100 ms ergibt sich dadurch als Modulo-Divisionsrest eine Blinkphase, die immer von 0 bis 1099 hochzählt. Wenn diese Blinkphase kleiner als 1000 (0…999)ist, wird die LED auf LOW geschaltet, sonst (1000…1099) auf HIGH.

Hallo summ

if((ledon=true)&& currentMillis - previousMillis > flashtime){ brauch ein dopeltes ==

Du sparst einige geschwungene Klammern und die vorhandenen setzt Du teilweise falsch.

Außerdem würde ich die beiden if durch ledon==true bzw ledon==false erweitern damit immer nur einen if wahr wird auch wenn bei einer längeren off-Zeit dies nicht notwendig ist. Wenn Du aber mal die Zeiten Änderst funktioniert es dann wieder nicht.

int strobes = 5;

boolean ledon = false;

unsigned long timetowait=2500;
unsigned long flashtime=100;
unsigned long previousMillis = 0;
unsigned long currentMillis ;
int strobestate=0;

void setup() {}

void loop()
  {  
  currentMillis = millis();
  
  if ((currentMillis - previousMillis > timetowait) && (ledon == false))
    {
    previousMillis = currentMillis;
    ledon = true;
    if(strobestate == 0)
      {
      strobestate = 100;
      }
    else
      {
      ledon = false;
      strobestate = 0;
      }
    
    analogWrite(strobes,strobestate);
    }
  
  if((ledon=true)&& (currentMillis - previousMillis > flashtime))
    {
    previousMillis=currentMillis;
    if (strobestate==100)
      {
      strobestate=0;
      ledon = false;
      analogWrite(strobes,strobestate);
      }
    }
  }

PS Sketch ist nicht getestet. Funktioniert theoretisch. Grüße Uwe

Du schreibst einfach ein Programm, das genau das macht.

Hey ... klar :) Wow ... so vereinfacht hab ich das noch nirgends gesehen. Hatte gerade damit begonnen, eine Led_Flasher lib auseinander zu nehmen ... völliger Schwachsinn, wenn ich Deine Lösung so sehe!!! Heftigsten Dank!!!!! Jetzt kann ich endlich über den Rest meines kleinen Projektes nachdenken ...

Da fällt mir ein Stein vom Herzen!!! Ehrlich!!!

PS Sketch ist nicht getestet. Funktioniert theoretisch.

Lieber Uwe ... praktisch tut sich immer noch nix. Led ist immer aus.

Hallo,

hast du bereits den Sketch von Jurs getestet? Sektch sieht plausibel aus, jedoch sollte in diesem Teil des Sketches LEDPIN durch pin ersetzt werden, denn sonst kann “void blinkWithoutDelay(int pin, int off, int on)” auch auf “void blinkWithoutDelay(int off, int on)” gekürzt werden. Die Lösung von Jurs so genial wie auch einfach :wink:

void blinkWithoutDelay(int pin, int off, int on)
{
  int blinkPhase=millis()%(off+on);
  if (blinkPhase<off) digitalWrite(LEDPIN, LOW);
  else digitalWrite(LEDPIN, HIGH);
}

summ:

PS Sketch ist nicht getestet. Funktioniert theoretisch.

Lieber Uwe ... praktisch tut sich immer noch nix. Led ist immer aus.

Dann gib einige Serielle Ausgaben in den Sketch um zu sehen ob diese Teile ausgeführt werden. Gib einfach mit Serial.print() die Werte von einigen Variablen aus. zB: vor if ((currentMillis - previousMillis > timetowait) && (ledon == false)) Serial.print("punkt1"); Serial.println(ledon); ecc https://www.inkling.com/read/arduino-cookbook-michael-margolis-2nd/chapter-4/recipe-4-1 Grüße Uwe

Falls Du Englisch kannst schau Dir mal meine Lösung an: http://blog.blinkenlight.net/experiments/basic-effects/lighthouses/. Klappt natürlich auch mit nur 1 LED und nur 2 Phasen.

hast du bereits den Sketch von Jurs getestet? Sektch sieht plausibel aus,

Ja der läuft wunderbar. Jetzt kommt aber die nächste Hürde: ich habe versucht, das mit meinem Sketch zu kombinieren, der noch eine Abfrage von Bluetooth Serial enthält und Switch cases beinhaltet. Da läuft der Code nicht, bzw. es Blitzt nicht. Da wäre meine Frage, ob die Switch Case Methode überhaupt die richtige ist, oder ob ich das anders organiesieren müsste.

Wie ihr seht, habe ich den kleinen Flash-Sketch schon in den loop zu packen, weil ich nach ersten Versuchen dachte, dass er vielleicht nicht läuft, wenn er in seinem eigenen void hängt. Aber das scheint nicht das Problem zu sein.

#define LEDPIN 5
#include <SoftwareSerial.h>
#include <SoftwareServo.h>

// Servo related stuff
SoftwareServo myServo;
int servostep = 30;
int pos =0;
//Bluetooth related stuff
int bluetoothTx = 2;  // TX-O pin of bluetooth mate
int bluetoothRx = 7;  // RX-I pin of bluetooth mate
SoftwareSerial bluetooth(bluetoothTx, bluetoothRx);
char val; // variable to receive data from the serial port
int pylonmode = 'a';

// set all other led outputs
int warp = 6;
int mains = 9;
int posi = 10;
int flood = 11;

// timer setups
int off = 2200;
int on = 50;

void setup(){
    pinMode(LEDPIN, OUTPUT);
    analogWrite(flood, 1);
    analogWrite(posi, 1);
    analogWrite(mains, 50);
    analogWrite(warp, 255);
    Serial.begin(115200);       // start serial communication at 9600bps  bluetooth.begin(115200);  // The Bluetooth Mate defaults to 115200bps
    myServo.attach(3);  
    myServo.write(pos);
}

void loop(){
  int blinkPhase=millis()%(off+on);
  if (blinkPhase<off) analogWrite(LEDPIN, 0);
  else analogWrite(LEDPIN, 20);
  
    if( bluetooth.available() )       // if data is available to read
    {
    val = bluetooth.read();         // read it and store it in 'val'
    }
    pylonmode=bluetooth.parseInt();
    switch(pylonmode){
    case 'a':
    myServo.write(0);
    SoftwareServo::refresh();
    break;
    case 'b':
    myServo.write(100);
    SoftwareServo::refresh();
    break;
  }
}
  int blinkPhase=millis()%(off+on);
  if (blinkPhase<off) analogWrite(LEDPIN, 0);
  else analogWrite(LEDPIN, 20);

analogWrite wird bei LEDs für PWM genutzt. Der Wert geht von 0 (0%) bis 255 (100%). Dein Wert von 20 ist zu wenig.

pylonmode=bluetooth.parseInt();

Lass das mal weg und mach stattdessen

pylonmode = bluetooth.read();

parseInt() liest eine LongInteger über seriell ein. Eigentlich musst du doch gar nicht den Servo in jeder Loop stellen, der Wert verändert sich ja nur, wenn über Seriell eine neue Eingabe kommt, kannst du also auch in die Schleife

 if( bluetooth.available() )       // if data is available to read
    {

einbauen. Bei switch() wird normal immer eine default Bedingung angehängt. Vielleicht kann man die auch weglassen, wenn da keine Befehle drinstehen.

sschultewolter: Sektch sieht plausibel aus, jedoch sollte in diesem Teil des Sketches LEDPIN durch pin ersetzt werden

Das stimmt! Ich habe das gleich nochmal oben im Code entsprechend geändert, damit die Funktion auch für verschiedene und gleichzeitig angesteuerte LED-Pins im selben Programm verwendbar ist.

summ: Da wäre meine Frage, ob die Switch Case Methode überhaupt die richtige ist, oder ob ich das anders organiesieren müsste.

Die Funktion "parseInt(); ist genau so eine unbrauchbare Arduino-Komfortfunktion wie delay();

Diese Funktion hält das Programm an der Stelle für eine bestimmte Zeit an und wartet auf den Empfang einer Zahl. Erst wenn die Zahl dann angekommen ist, macht die Funktion weiter. Erst falls die Zahl innerhalb einer bestimmten Timeout-Zeit (Standard: 1 Sekunde) nicht ankommt, bricht die Funktion mit Timeout ab und macht trotzdem weiter. Die Funktion ist also wie ein "delay(1000)" mit zusätzlichem Empfang einer Zahl auf der seriellen Schnittstelle, falls zwischendurch eine ankommt. Und falls keine Zahl ankommt, ist parseInt() vollkommen identisch zu delay(1000);.

Für ein flüssig ablaufendes Programm ist parseInt() genau so wie delay() völlig unbrauchbar. Du mußt Dir Deine serielle Empfangsroutine selberschreiben. Dazu müßtest Du am einigermaßen genau wissen, was gesendet wird und woraufhin im Sendeprotokoll das Ende einer zu empfangenden Zahl erkannt werden soll: - Zahl plus abschließendes ASCII-Zeichen hinter der Zahl (23;24;25;26;27;28;) - Zahl plus abschließendes Steuerzeichen z.B. Zeilenvorschub CRLF am Ende der Zeile - Zahl wird gesendet und danach folgt eine Sendepause (Timeout) Und je nachdem schreibst Du eine Empfangsroutine, die eine Zahl plus ASCII-Zeichen, Zahl plus Zeilenende-Steuerzeichen oder Zahl zwischen zwei Sendepausen empfängt. Und die immer erst dann, wenn die Zahl komplett empfangen wurde, auf den Empfang reagiert. Und zwar ohne zwischendrin einfach das Programm zu blockieren und zu warten.

Hallo,

sorry, dass ich den alten Post aufwärme und vielen Dank für die Funktion!!!

jurs:
Du schreibst einfach ein Programm, das genau das macht.

Zum Beispiel:

#define LEDPIN 13

void blinkWithoutDelay(int pin, int off, int on)
{
  int blinkPhase=millis()%(off+on);
  if (blinkPhase<off) digitalWrite(pin, LOW);
  else digitalWrite(pin, HIGH);
}

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

void loop(){
  blinkWithoutDelay(LEDPIN, 1000, 100);
}

Auf der Suche nach einer Lösung, Töne auszugeben, ohne das Programm zu blockieren bin ich auf diesen Beitrag gestoßen.
Die Funktion habe ich etwas umgeschrieben:

const int BuzzerPin = 6;
int frequenz = 0;

void setup() {
Serial.begin(9600);
}

void Buzzer(int TonAn, int TonAus, int Freq)
{
  int blinkPhase=millis()%(TonAn+TonAus);
  if (blinkPhase<TonAn) tone(BuzzerPin, Freq);
  else noTone(BuzzerPin);
}

void loop() {
//Serial.println(millis());
//Buzzer(300, 4000, 450);

  for (int i = 0; i < 7; i++){
  Serial.println(i);
  frequenz = (200 + (100 * i));
  Serial.println(frequenz);
  Buzzer(1000, 1000, frequenz);
  }
delay(2000);
}

Das auskommentierte Buzzer(300, 4000, 450); funktioniert wie es soll.
Das auskommentierte Serial.println(millis()); zeigt dabei auch, dass das Programm weiter läuft.

Jetzt wollte ich aber eine “Tonleiter” erzeugen.
Der Code mit der Schleife funktionierte ursprünglich mit delay() und noTone

Jetzt wird aber “nur” ein 800Hz-Tone erzeugt. Nach etwas nachdenken wurde mir klar, die Schleife läuft ja weiter, es kann also nicht anders sein.
Diese Tonleiter (in ihrer ursprünglichen Funktion) blockiert den Arduino für einige Zeit.

Bis jetzt läuft es so:

for (int i = 0; i < 7; i++){
tone(BuzzerPin, 200 + (100 * i));
delay(100);
noTone(BuzzerPin);
}

Die Funktion umgeschrieben zu:

void BuzzerLeiter(int TonAn, int TonAus)
{
  while (i << 7){
  frequenz = (200 + (100 * i));
  Serial.println(frequenz);
  int blinkPhase=millis()%(TonAn+TonAus);
  if (blinkPhase<TonAn) tone(BuzzerPin, frequenz);
  if (blinkPhase<TonAn) i++;
  else noTone(BuzzerPin);
  }
}

Funktioniert auch nicht.

Kann mir jemand helfen, einen anderen Lösungsansatz zu finden?

Vielen Dank

marco_78: Kann mir jemand helfen, einen anderen Lösungsansatz zu finden?

Ja, bestimmt. Wenn du nicht einen uralten Sketch kaperst, sondern mit deiner Frage einen neuen Thread öffnest.

(deleted)

Vielen Dank für die Hinweise.
Habe ich gemacht: https://forum.arduino.cc/index.php?topic=701251.0

Eingangs habe ich mich auch schon dafür entschuldigt, diesen Beitrag wieder aufzuwärmen.
Er erschloss sich mir aber nicht, dieses nicht zu tun, da hier alles vorhanden ist.