Frage eines Anfängers zu einem LCD Display 16x2 oder so

Hallo,

als blutiger Anfänger habe ich bezüglich LCD Display eine Frage.

Ich habe einen Sketch, der läuft soweit auch bestens. Nun möchte ich ein paar Werte in ein LCD Display schreiben., Ich weiß nur nicht, wie ich das ansteuern soll.

Der geamte Sketch läuft je Sekunde etwa 3 mal durch. Er ist also recht langsam.

Wenn ich nun die Werte nur 3 mal je Sekunde in das Display schreibe, dann wird das arg flackern.

Aus dem Grund habe ich bisher nie Displays verbaut. Schneller bekomme ich den Sketch auch nicht mehr, das ist schon ziemlich ausgereizt.

Eine Überlegung war, einfach zwischen jeder Zeile und der jeweils nächsten, immer wieder dasDisplay neu zu beschreiben, damit am Ende min so 25 Hz rauskommen, damit das Auge das als Schrift, und nicht als Geflacker wahrnimmt.

Bedenken machen mir da aber z.B. Befehle, wie Sensorabfragen, wo Daten hin und her fliessen, und allein dieser Schritt ja ein wenig dauern. Da kann man ja auch nicht zwischenfunken.
Waitstates wie z.B. 20000µs beim Einlesen eines Impulses von RC-Kanälen machen auch Todzeit, hat man meghrere davon, sammelt sich das.
Manchmal dauern berechnungen ja auch unterschiedlich lang, so das nie eine stabile Frequenz zu Stande kommt beim beschreiben des Displays.

Daher die Frage, wie bekommt ihr eure Programme so schnell, das die Displays genügent oft gefüttert werden, ohne das es ein Geflacker gibt. 25Hz ist ja so die untere Grenze, die das Auge noch als Dauernd an erkennt. Mehr wäre besser.
Laufen alle eure Programme in der praxis mehr als 25 mal die Sekunde komplett durch?

Bevor ich nun in ein Display investere, hätte ich gern gewussst, ob sich das lohnt.
Bisher reichen meine Programmierkenntnisse nicht recht weit.
Es ist halt nur blöd, sich durch Zählen von Tastendrücken, die aktuell eingegebenen Werte zu merken, die hätte ich gern auf dem Diplay.
Im konkreten Fall geht es um ein Thermostat, wo ich den Sollwert in °C ablesen können möchte.
Der soll dort angezeigt werden, auf ein Grad genau würde reichen, also eigentlich nur zwei Stellen.
Das °C braucht nicht, ich weiß ja das es eine Temperatur ist.
Vielleicht ist das auch einfacher mit einem simplen zweistelligen Sieben-Segment Baustein, aber ... keine Ahnung.
Vielleicht weiß jemand, wie ich das am besten löse.

Du hast eine falsche Vorstellung davon, wie diese 16x2 LCD's funktiomieren.

Wenn Du da was drauf schreibst, zeigen die das selbständig dauerhaft an. Dass musst Du nicht dauernd refreshen. Es ist im Gegenteil eher nachteilig, wenn man da zu oft drauf schreibt. Das sollte man nur machen, wenn sich an dem angezeigten Text wirklich was ändert.

Ich wüsste kein LCD - weder rein Text noch Grafik - dass Du über den Ardino 'refreshen' müsstest.

skyfox60:
[Geflacker]

Seit meinem ersten LC-Display in den 90ern habe ich nie eins gesehen, das geflackert hätte. Du Siehst einen Wechsel des Inhalts normalerweise nur, wenn es von Dir gewollt ist, ganz ohne Geflacker. Du aktualisierst den Inhalt und fertig.

Gruß

Gregor

skyfox60:
Aus dem Grund habe ich bisher nie Displays verbaut. Schneller bekomme ich den Sketch auch nicht mehr, das ist schon ziemlich ausgereizt.
.....
Bevor ich nun in ein Display investere, hätte ich gern gewussst, ob sich das lohnt.
.....

Diese Invesatition lohnt sich bestimmt.

Wenn du mit den Beispielen der zugehörigne Library das dann aufbaust, wirst du sehen, da flackert nix.

Wernn doch, hast du etwas falsch programmiert und da können wir sicher helfen.

skyfox60:
Bedenken machen mir da aber z.B. Befehle, wie Sensorabfragen, wo Daten hin und her fliessen, und allein dieser Schritt ja ein wenig dauern. Da kann man ja auch nicht zwischenfunken.
Waitstates wie z.B. 20000µs beim Einlesen eines Impulses von RC-Kanälen machen auch Todzeit, hat man meghrere davon, sammelt sich das.

Man kann das (fast immer) auch so programmieren, dass loop dennoch sehr schnell wiederholt wird.
Würdest du deinen Kode posten, könnte man mehr dazu sagen.

skyfox60:
Bevor ich nun in ein Display investere, hätte ich gern gewussst, ob sich das lohnt.

Ich schenk dir mal ein 'i', das hast du wohl verloren. :wink:

i2c1602.png

2,81 € (freier Versand) für ein 16x2 LCD mit I2C Interface empfindest du als Investition?

i2c1602.png

Hallo zusammen,

erst einmal vielen Dank für die schnelle Hilfe.

Das heißt also, die Dinger haben einen Zwischenspeicher, der diese Aufgabe erledigt.

Das läßt vieles für mich jetzt in einem ganz anderen Licht erscheinen.

Ich beschäftige mich erst seit einem Monat mit dem Arduino überhaupt.
Bis dahin waren alle Dinge rund um ihn für mich Neuland.

Und vieles verstehe ich immer noch nicht.

Als Modellflieger dreht sich meine Programmiererei hauptsächlich um alles, was in, am, um um das Flugzeug passiert.

Das Thermostat soll einen Heizkoffer beflügeln. Die kann man zwar auch fertig für 1,99 in China kaufen, aber das ist ja langweilig. :slight_smile:

Momentan versuche ich, die Sache mit den Timern zu verstehen, aber da tue ich mich echt schwer.
Werd mal einfach was damit programmieren, und experimentieren.

Ich brauche da was Ineinandergeschachteltes, was quasi im Hintergrund läuft.
Einfacher Timer, ok, das hab ich soweit gerafft.
ich möchte aber:

1 - 1,5 Sek. Aus
50µS an
50µS aus
50µS an
50µS aus
50µS an
50µ aus
50µS an
50µS aus
dann von Vorne, also wieder 1,5S Pause, und 4 mal 50µS an-aus usw.

Dazwischen kommen Dinge, wie Servopuls abfragen und andere Aus und Eingänge schalte.
Und ein Loop, der ca. 1,5 Sek. eh schon dauert für ein schwellendes Licht ( PWM steigt, fällt kontinuierlich. ) Möglicherweise kann man das sogar ebenfalls über einen zweiten Timer laufen lassen.
Ich weiß nicht.

Konventionell habe ich das gelößt, und es läuft auch Prima,
aber der Sketch ist dadurch sehr lang und unübersichtlich.
Geht, aber ist weit entfernt von auch nur annähernd professionell.

Hallo Whandall,

danke für das "I", hatte ich übersehen beim Korrekturlesen.

Nun ja, es geht nicht um die ~3€.
Ich empfinde eine Investition dann als schlecht, wenn ich anschliessend nichts damit machen kann.

Da geht es weniger um die Höhe des Betrages, als um den zu erwartenden Erfolg der Aktion.
Die Erwartungshaltung hat sich ja durch die schnellen Antworten gerade deutlich nach oben bewegt.

Sogar so weit, das ich mehr ausgegeben habe, und eines gekauft hab, das von Deutschland versandt wird, um es schneller zu haben, und das hiesige Bruttosozialprodukt zu unterstützen. :slight_smile:

skyfox60:
Der geamte Sketch läuft je Sekunde etwa 3 mal durch. Er ist also recht langsam.

Wenn ich nun die Werte nur 3 mal je Sekunde in das Display schreibe, dann wird das arg flackern.

Sooo extrem langsam sind die Displays auch nicht. Außerdem soll man das ja auch noch als Mensch lesen können.

Wodurch viele Anfänger Flackern produzieren ist indem sie das Display immer komplett löschen und dann neu beschreiben. Oder indem sie einzelne Zeilen komplett mit Leerzeichen überschreiben und dann den neuen Inhalt.
Richt macht man es wenn man seinen Text auf eine konstante Breite formatiert, alten Text direkt überschreibt und nur den Rest mit Leerzeichen auffüllt

skyfox60:
Ich beschäftige mich erst seit einem Monat mit dem Arduino überhaupt.
Bis dahin waren alle Dinge rund um ihn für mich Neuland.

Wenn Du auch Programmierneuling bist, solltest Du Dich vom Start weg darum kümmern, dass Dein Code gut aussieht. Wie sehr sowas bei der Fehlersuche hilft, lernst Du noch :-)))

Gruß

Gregor

Hallo Gregor,

ich geb mir ja schon Mühe. Hier mal mein Sketch für die Originalgetreue Beleuchtung eines Flugzeuges.

/*
  Scale like anticollision-light, strobe-light, NAV-lights and landing-light for RC-Aircraft

  Digital Channels Output
  NAV_light    = D5  ( Left = red, Right = green, Back = white ) digital out
  ACL          = D6  PWM _ Channel for intensity regulation ( ACL = Anticollision Light )
  Landinglight = D7  digital out
  Strobe       = D8  digital out
 
  Receiverchannel Inputs:
  Input a Servochannel from Receiver to D10, Try-State Switch is recommended ( 1000µs, >1500µs, 2000µs )
 
  In normal ( out ) condition ( a > 1400 a <2100 ) only the mainloop and ACL_only-routine is ruinning. 
  This makes the ACL ( anticollision-light ) running as soon as the battery is plugged on and the lamp-test ist finished.
  I made this because in real aircraft the first action after switching the main switch on, is to activate the ACL, there should be no need to activate a switch at the transmitter for that.
  Also, the ACL remains Fading up and down, until battery is unplugged and aircraft save.
  If you have a transmitter that allowes the switch-position-test at the beginning, set it so that the light switch has to be in 2000µs position before transmitter starts.
  When switch in appx mid position ( a <1400 ) the ACL_NAV_Strobe-Loop runs. You find at first a similar routine like in ACL_only.
  This was required due to the need of some other values to have the same visiual appearence of ACL the and nearly continuing as it was.
  there is a Lamptest to check all lamps. 10 flashes wake up for you, followed by single test and finally 10 flashes to finish and exit to Mainloop.
  
*/

  int NAV_light = 5;
  int ACL = 6;                     // the PWM pin the LED is attached to
  int Landinglight = 7;
  int Strobelight = 8;
  int brightness = 7;              // how bright the LED is, 0 at startup
  int brightness_increment = 7;    // How many points increment or decrement per step to fade the LED, if you change this value ( default is 7 ), you have also to change the counter1 steps ( default is 68 ), just for the case you changed it and do not remember 
                                   // Also max Brightness has to be altered, if you cange any of the values. ( default is 231 )

                                 
  int counter1 = 1;
  int counter2 = 0;


void setup()
{

  pinMode(5, OUTPUT);              // NAV_light
  pinMode(6, OUTPUT);              // output ACL
  pinMode(7, OUTPUT);              // output Landinglight 
  pinMode(8, OUTPUT);              // putput Strobelight
  pinMode(10, INPUT);              // reads a and cycles ACL and Strobelight 
}


// the loop routine runs over and over again forever:
void  loop() {
Serial.begin(9600);
goto Mainloop;
// Lamptest to check all lamps. 10 flashes wake up for you, then single test and then 10 flashes finish and exit to Mainloop

  for ( int L1 = 0; L1 <= 10; L1++ )
{
  digitalWrite (Strobelight,HIGH); ; digitalWrite(NAV_light, HIGH);  digitalWrite(ACL, HIGH);  digitalWrite(Landinglight, HIGH); delay(50);
  digitalWrite (Strobelight,LOW); digitalWrite(NAV_light, LOW);  digitalWrite(ACL, LOW);  digitalWrite(Landinglight, LOW);delay(50);
}
  for ( int L = 0; L <= 1; L++) { digitalWrite (NAV_light, HIGH); delay(300);  digitalWrite (NAV_light, LOW);delay(300); digitalWrite ( ACL, HIGH ); delay(300); digitalWrite ( ACL, LOW );delay(300); digitalWrite (Landinglight,HIGH);
  delay(300); digitalWrite (Landinglight,LOW);delay(300);  digitalWrite (Strobelight,HIGH);delay(300);digitalWrite (Strobelight,LOW);delay(300);
}
  for ( int L1 = 0; L1 <= 10; L1++ )
{
  digitalWrite (Strobelight,HIGH); ; digitalWrite(NAV_light, HIGH);  digitalWrite(ACL, HIGH);  digitalWrite(Landinglight, HIGH); delay(50);
  digitalWrite (Strobelight,LOW); digitalWrite(NAV_light, LOW);  digitalWrite(ACL, LOW);  digitalWrite(Landinglight, LOW);delay(50);
  
}


  Mainloop:;    
  
 // digitalWrite(ACL,brightness);
  counter1 = 1;
  counter2 = 0;
 
  int    a = pulseIn(10,HIGH,25000);        // Read in pulse lenght, 3rd parameter has to be finetuned with receiver behavior
  
  if ( a >=1600 & a <=2100 ) { digitalWrite (NAV_light, LOW);  digitalWrite (Landinglight, LOW); goto ACL_only; }
  if ( a >950 & a <1200 ) { digitalWrite (Landinglight, HIGH); } 
  if ( a >1200 ) { digitalWrite (Landinglight, LOW);  } 
  if ( a >=950 & a <=1600) { digitalWrite (NAV_light, HIGH); goto ACL_NAV_Strobe; }
 
  
       
  ACL_only:;  
  
   analogWrite(brightness, 7);
   for (brightness <=7; brightness <252; brightness = brightness + brightness_increment){ analogWrite(ACL, brightness); delay(20); Serial.println(brightness); }   
   for (brightness <=253; brightness >=7; brightness = brightness - brightness_increment){ analogWrite(ACL, brightness); delay(30); Serial.println(brightness); }
      
   delay(400); // this delay is importand to have not jump in the brightness of ACL when switching NAV-lights and strobe on and of. do not change this value.
  
  goto Mainloop;
  

  
  ACL_NAV_Strobe:;
  
  counter1 = counter1+1;
  
  analogWrite(brightness, 7); // brightness = 7; // for synchronisation, to have small remaining brightness at the lower end, like a downgoing bulb at the ACL 
   for (brightness <=7; brightness <252; brightness = brightness + brightness_increment){ analogWrite(ACL, brightness); delay(20); Serial.println(brightness); }   
   for (brightness <=253; brightness >=7; brightness = brightness - brightness_increment){ analogWrite(ACL, brightness); delay(30); Serial.println(brightness); }
    // this two lines became necessary to synchronize the status of the ACL brightness when switching NAV lights and strobe on and off.
    //without the repeat of that two lines, a small jump occures, that is visible. Took me time to find out:)  
  
  
  
// the loop function Strobe runs 4 times ( 4 flashes ) and returns to Mainloop to check again the switch ( pulse ) status.

  Strobe:;
 
  counter2 = counter2+1;  
  digitalWrite(Strobelight, HIGH);         // turn the LED on by making voltge HIG
  delay(40);                               // wait for 50ms on time
  digitalWrite(Strobelight, LOW);          // turn the LED off by making the voltage LOW
  delay(60);   // wait for a second        // Wait for 50ms off time
  if ( counter2 == 4 ) { goto Mainloop; }  // the 4 is the number of flashes in each cycle
  { goto Strobe; }  

}

Goto solltest du dir sofort abgewöhnen. Es gibt ein paar Nischen-Anwendung dafür, aber nicht hier

Und so viele Anweisungen in einer Zeile ist auch nicht gut. Eine oder zwei kurze danach sind ok, aber so ist das unübersichtlich. Und eine Anweisung direkt dahinter macht man eigentlich um sich die Klammern zu sparen:

if ( a >950 & a <1200 ) { digitalWrite (Landinglight, HIGH); }

Wenn dann so:

if ( a >950 & a <1200 ) digitalWrite (Landinglight, HIGH);

Oder:

if ( a >950 & a <1200 ) 
  digitalWrite (Landinglight, HIGH);

vereinfacht gesagt:

STRG-T drücken in der IDE, damit man die Einrückungen besser sieht.
kein Delay verwenden.
kein Goto verwenden.

alle int überprüfen ob sie int sein müssen.

Sonst noch Fragen?

Lege deinen Sketch zur Seite, mach eine klare Aufstellung, welche Lampe in welchem Rhytmus blinken soll und wie die Lampen zueinander in Beziehung stehen. Mit Delay und Goto wird das nix.

Hallo Fuchs des Himmels :wink:

Da hat man dir ja schon so allerhand von deinem Sketch zerrissen :wink: . Aber es stimmt schon - so einige grundsätzliche Fehler sollte man von Anfang an vermeiden, damit man sie sich garnicht erst angewöhnt.

Vielleicht kannst Du auch meine MobaTools gebrauchen. Damit ist z.B. das Faden von Leds genauso einfach wie das harte Ein- und Ausschalten. Auch das Vermeiden von delay's geht damit ein wenig einfacher und übersichtlicher als die direkte und 'harte' Tour mit den millis().
Installieren kannst Du die direkt über den Bibliotheksverwalter in der IDE (Strg+Shift+I und dann im Suchfeld mobatools eingeben ).

Auch musst Du dir genauer überlegen, was inn setup(), und was in loop() gehört. Alles was nur zum Start des Sketches einmalig gemacht werden soll/muss gehört ins setup() - z.B. auch das Serial.begin(). Auch die Testroutine für deine Beleuchtung solltesr Du dahin verschieben. Das wird dann bei jedem Start des Sketches einmal gemacht, und dann geht's erst los mit der eigentlichen Funktionalität.

Yep, da simmer schon beim Thema.

Hab mal was mit millis probiert.
Erwartungsgemäß funktioniert das nicht so, wie ich das gerne hätte.

Anbei das Beispiel:

Die intere LED flasht mit 50 mills, also ein Bltzlicht.

Code kopiert und hochgeladen, und läuft.

Sobald aber daneben andere Dinge laufen, passt das nicht mehr. Die Led geht jetzt ganz lansam, das "daneben" verzögert alles.
Frage??:
Wo ist da der Denkfehler?

unsigned long startMillis;  //some global variables available anywhere in the program
unsigned long currentMillis;
const unsigned long period = 50;  //the value is a number of milliseconds

const byte ledPin = 13;    //using the built in LED

void setup()
{
  
  Serial.begin(9600);  //start Serial in case we need to print debugging info
  pinMode(ledPin, OUTPUT);
  startMillis = millis();  //initial start time
}

void loop()
{
  currentMillis = millis();  //get the current "time" (actually the number of milliseconds since the program started)
  if (currentMillis - startMillis >= period)  //test whether the period has elapsed
  {
    digitalWrite(ledPin, !digitalRead(ledPin));  //if so, change the state of the LED.  Uses a neat trick to change the state
    startMillis = currentMillis;  //IMPORTANT to save the start time of the current LED state.
  }

 // Bis hier funktionierte das. Unten stehendes soll einen längeren Programablauf simulieren
 // währed dessen aber das Blitzen oben munter weiter laufen sollte.
 
   for (int a=1; a<200; a++)
  {
    Serial.println ("waiting");
  }
  
}

Deine for-Schleife ist praktisch ein 'delay'. Wenn das mit den millis funktionieren soll, muss der gesamte Ablauf im loop so geschrieben werden, dass nichts blockiert bzw wartet.

Edit: hast Du früher auch mal 'Eisenbahn' gespielt und Züge im Kreis fahren lassen? Für das Vermeiden von delay habe ich mal ein Tutorial geschrieben, wo das mit einer im Kreis fahrenden Lok erklärt wird.
Ansonsten gibt's noch die 'Nachtwächtererklärung'.

ich hab da was in der Bastelkiste.
Verschiede Leuchten mit verschiedenen Blink-Mustern.

Jede einzelne Leute macht nach dem Muster "BlinkWithoutDelay" ihr Ding.

du legst nur neue Objekte an wo du den Pin bekannt gibst, und im Loop gibst du jeder Leuchte eine Zeitscheibe.

/* Blink a LED in a specific rhythm

  Turns on and off light emitting diodes (LED) connected to a digital pin,
  without using the delay() function. This means that other code can run at the
  same time without being interrupted by the LED code.

  noiasca
  2019-05-05

*/

class BlinkLed {
    byte state = 1;       // 1 blink, 0 off
    unsigned long previousMillis;
    uint16_t on = 180;
    uint16_t off = 320;   // 180/320 is according ECE
    const byte ledPin;

  public:
    BlinkLed(byte attachTo):
      ledPin(attachTo)
    {}

    void begin()
    {
      pinMode(ledPin, OUTPUT);
    }

    void set(uint16_t _on, uint16_t _off)  // modify on/off times during runtime
    {
      on = _on;
      off = _off;
    }

    void setState(byte _state)            // 1 Switch on blinking; 0 switch off blinking
    {
      state = _state;
    }

    void tick()
    {
      if (state)
      {
        uint32_t currentMillis = millis();
        if (digitalRead(ledPin) && currentMillis - previousMillis >= on) {
          // save the last time you blinked the LED
          previousMillis = currentMillis;
          digitalWrite(ledPin, LOW);
        }
        if (!digitalRead(ledPin) && currentMillis - previousMillis >= off) {
          // save the last time you blinked the LED
          previousMillis = currentMillis;
          digitalWrite(ledPin, HIGH);
        }
      }
    }
};

class RhythmLed {
    byte state = 1;
    unsigned long previousMillis;
    const byte ledPin;
    uint8_t lengthOfPattern;
    // the intervall pattern
    //                          ON    OFF  ON   OFF
    //                          1     2    3    4
    uint16_t intervall[5] = {0, 150,  60, 20, 270};                  // ECE 2
    //uint16_t intervall[3] = {0, 180, 320};                         // ECE 1
    //uint16_t intervall[7] = {0, 25, 25, 25, 25, 25, 375};          // HELLA 3
    //uint16_t intervall[9] = {0, 40, 40, 40, 40, 40, 40, 40, 220 }; // HELLA 4
    //uint16_t intervall[5] = {0, 150,  60, 20, 400};                // wie gewünscht vom TO

  public:
    RhythmLed(byte attachTo):
      ledPin(attachTo)
    {}

    void begin()
    {
      pinMode(ledPin, OUTPUT);
      lengthOfPattern = sizeof(intervall) / sizeof(intervall[0]);
    }

    void setState(byte _state)
    {
      state = _state;
    }

    void setIntervall(uint16_t _intervall1, uint16_t _intervall2, uint16_t _intervall3, uint16_t _intervall4)       // Modify the intervalls to your needs
    {
      intervall[1] = _intervall1;
      intervall[2] = _intervall2;
      intervall[3] = _intervall3;
      if (lengthOfPattern>3) intervall[4] = _intervall4;   // if someone declares a dual-intervall, this line would crash the sketch, therefore this if on the index length ;-)
    }

    void tick()
    {
      uint32_t currentMillis = millis();
      if (state > 0)                            // iterate through the states 1 to n, we don't use state 0 because state 0 is reserved to "switch off" the light
      {
        if (currentMillis - previousMillis > intervall[state])
        {
          if (state % 2 == 1)  // all uneven states are ON, at the end of an intervall we switch to the oposite pin state
          {
            digitalWrite(ledPin, LOW);
          }
          else
          {
            digitalWrite(ledPin, HIGH);
          }
          state++;
          if (state > lengthOfPattern - 1) state = 1;
          previousMillis = currentMillis;
        }
      }
    }
};

BlinkLed myBlinkLed(5);       // a simple blink led
RhythmLed topRKL(13);         // define an output PIN for your LED
RhythmLed outOffSyncRKL(6);  // eine Rundumkennleuchte die wegen eines "Massefehlers" am Originalfahrzeugs eine leicht verschobene Blinkfrequenz hat ;-)

void setup()
{
  myBlinkLed.begin();
  topRKL.begin();
  outOffSyncRKL.begin();
  outOffSyncRKL.setIntervall(250,  90, 30, 400);  // Modify the intervalls for this LED
}

void loop()
{
  myBlinkLed.tick();  // each object has to be called once in the loop
  topRKL.tick();
  outOffSyncRKL.tick();

  // put here other code which needs to run:

}

ausschalten einfach mit .setState(0) bzw. ein mit .setState(1)

Wenn dir das Konzept behagt, dann sag was du an Mustern brauchst, ich denke das geht ziemlich einfach. Die nächsten 45min bin ich noch online.

Also es passiert folgendes:

Fall 1:
Nach dem einschalten geht zwangsweise eine LED in den Lampenmodus. Anschwellen, Abschwellen.
Das soll auch so bleiben, bis zum Ausschalten.

Daneben wird ständig ein Impuls abgefragt, der zwischen 1000 und 2000µS lang sein kann.
Default aus ist bei mir alles was >1800&<2100 z.B. ist ( man braucht da ein wenig Luft, weil es schon mal ein parr µS mehr oder weniger sein können, die übertragen werden. pulseIn(x, HIGH, 25000)
die 25000 müssen sein, weil der Impulse nicht öfter kommt.

Geht der Impuls etwa in die Mitte ( 1400µS - 1600µS ), dann passieren 2 Dinge.

Fall 2:
-1. Ein Ausgang wird auf Dauer EIN gesetzt ( NAV-Lichter ).
-2. Ein weiterer Ausgang geht jetzt auf Strobe.
Das heißt 4 mal hintereinander 50mS an, 50mS aus( 40 an, 60 aus ist auch ok ). Danach hat er eine Pause von 1 - 1,5 Sek.

Nun gibt es 3 Möglichkeiten

  1. Der Puls bleibt so, es läuft also Fall 1 ( ist ja immer an, und Fall 2 )

  2. Der Puls geht zurück auf 2000> es läuft wieder nur Fall 1

  3. Der Puls geht auf 1000 ( also 950 bis 1050 )

Dann laufen Fall 1 ( immer an ), Fall 2 läuft weiter
Aber es kommt in weiterer statischer Ausgang hinzu, nämlich der Landescheinwerfer.

Dann ist also alles an.

Üblicherweise soll nach der Landung zunächst der Landescheinwerfer abgeschaltet werden,
also von etwa 1000µS zurück nach 1500µS. Danach erst NAV und Strobe, während das ACL ( Fall 1 ) weiterläuft bis zur Stromlosigkeit.

Dazu soll es aber auch möglich sein, von Fall 1 direkt zu Fall 3 zu springen.
Impulse von 2000 auf 1000µS ( Dann laufen wieder alle 3 Fälle )
Und natürlich von 1000µS zurück auf 2000µS so das dann Fall 3 und Fall 2 abgeschaltet werden und wiederum nur Fall 1 läuft.

Und btw. Das macht mein vorhin geposteter Spagetthi-Code vom allerfeinsten.

Das schwierigste daran war, das man im Auf- und Abschwellen keinen Sprung sehen kann, egal, ob gerade der Puls abgefragt und umgeschaltet wird oder nicht. Dafür sorgt z. B: das an der einen Stelle eingefügte delay von 400mS ist genau die Zeit, die ansonsten die Strobes brauchen, wenn sie zugeschaltet sind.

Sind die ausgeschaltet, gilt das delay, sind sie eingeschaltet, brauchen sie genau diese Zeit, daher blitzt es immer in der Pause, die sowieso da ist. Das hat Kaffee verbraucht, bis das so geschmeidig lief.

Ja, das mit dem Code sieht noch so aus, wie früher Basic auf dem C-64, ich weiß, da war ich aber auch noch jung aund aufnahmefähig, das hat sich so also eingebrannt. Alles Versuche, den Spagetthi-Code ohne Goto hinzukriegen schlugen fehl, und ich war happy, als das nachher alles lief.

Er sieht halt nur nicht schön aus :slight_smile: :slight_smile: :slight_smile:
Das war für mich schon eine Leistung, nach einem halben Monat, so tolle Spagetthi zaubern zu können.

Deinen Vorschlag habe ich mir gerade runtergeladen und probiere damit rum.
Richtig verstehen tu ich ihn aber keineswegs, nur Ansatzweise.

Und die Beschreibung vom MoBahner lese ich auch gerade mit Interesse.
Das ist schon verständlich, und die Library hab ich auch schon installiert.

Das mit den Gleisen ist bildlich nachvollziehbar. Und eine Idee, was ich genau daraus machen könnte hab ich auch schon, verbunden mit einer Passage aus dem Vorschlag von dir.
Den müsste ich nur noch passend separieren, und da tue ich mich halt schwer.

Wenn ich also nicht gleich wieder antworte, dann lese ich, mache Versteh-Versuche oder probiere gerade wieder rum.

@ Microbahner:

jetzt hab ich den kompletten Thread mit dem Wechselblinker und der Kreuzung gelesen.
Und tatsächlich, ich konnte das nachvollziehen. Ich könnte ihn jetzt nicht selbst programmieren, aber ich hab einigermassen verstanden, worum es da geht.

Da läßt sich einiges draus anpassen für andere Dinge.

Einzige Bauchschmerzen, die ich da grad habe sind folgende:

Die BueBelegt Abfrage ist hier "nur" das Einlesen eines Kontaktes.

Wenn ich das mittels einer Fersteuerung machen will, dann wird ja per Schalter am Sender z.B. ein Impuls von 1000 auf 2000µS geschaltet. Der Impuls wird alle 20mS ( etwa ) wiederholt.

Dazu verwendet man etwa Wert = pulseIn(x, HIGH, 25000)

Die Todzeit von 25mS benötigt man, um Sicher einen Impulse-rise zu erwischen, wonach die Pulslänge dann gemessen wird.

Da bremse ich doch durch die Todzeit das System um 25mS aus, oder verstehe ich das falsch?
Da ich ja ständig darauf schauen muss, ob der Schalter umgelegt, sprich, der Puls sich verändert hat, muss das bei jedem Loop-Durchlauf einmal abgefragt werden. Das summiert sich.

Da es sich jedoch nicht um eine Ampel handelt, sondern lediglich um schnöde Licht an- Licht aus abfragen, die nicht eben Zeitkritisch sind, handelt, könnte man ja vielleicht ( ich nur mal wieder nicht wie ) die Pulseabfrage auch mit einem Timer steuern, und nur alle 1 - bis 2 Sekunden mal fragen, wie der Puls ausschaut. Wenn ich schalte, und der Landescheinwerfer geht erst nach ein bis zwei Sekunden an, ist das nicht schlimm. Wenn ich meinem Flugschüler sage, Landing light on, braucht der jedenfalls mindestens genauso lang.

Wie würdest du das Wert = pulsIn(x,y,z) da rein schleusen?
Also in den Wechselblinker, Ampeln gibt es ja in der Luft nicht.

Hi

Lese Dir die Nachtwächtererklärung durch.

Hat dann doch länger gedauert, als ich vermutet habe ...
Der Sketch lässt die Strope-Blitz-Leuchten ... äh ... blitzen :wink:
Der benutzte Pin, wie die Zeiten für an/aus/Pause lassen sich im Code ändern.

//Forensketch, Nachtwächer für Strope-Blitzleuchten an Flugzeug

bool stropeaktiv = true;     //Hierdurch lässt sich das Strope-Licht an/aus schalten
const byte _pinStrope = 13; //Pin der Strope-LED

//Das heißt 4 mal hintereinander 50mS an, 50mS aus( 40 an, 60 aus ist auch ok ). Danach hat er eine Pause von 1 - 1,5 Sek.
const uint32_t StropeAN = 50; //wie lange ist der Blitz an?
const uint32_t StropeAUS = 50; //wie lange ist der Blitz aus? (denke 10/90 sieht besser aus)
const uint32_t StropePause = 1500; //die Pause zwischen den Blitzfolgen
const byte StropeCount = 4;   //Anzahl der Blitzfolgen vor Pause

void setup() {
  Serial.begin(9600);
  pinMode(_pinStrope, OUTPUT);
  Serial.println("Start");
}

void loop() {
  checkStrope();  //Strope-Light aufblitzen lassen, wenn erwünscht

  //Folgende Zeilen schalten 'nur' Strope an und aus - alle 15 Sekunden
  static uint32_t lastmillis = 0;
  const uint32_t changestrope = 15000;
  if (millis() - lastmillis >= changestrope) {
    stropeaktiv = !stropeaktiv;
    Serial.print("Strope:");
    Serial.println(stropeaktiv);
    lastmillis = millis();
  }
}

void checkStrope() {
  boolean _set = false;   //Merker, daß Ausgangspin gesetzt werden soll
  static byte statusStrope = 0; //bei welchem Impuls sind wir gerade?
  static uint32_t laststrope = millis(); //mit aktueller Uhrzeit initialisieren

  if (stropeaktiv) {
    //soll geblitzt werden?
    //Außer beim ersten Aufruf (Null) die Wartezeit warten
    //AN, AUS, Pausenzeit kann separat angegeben werden
    uint32_t wartezeit = (statusStrope == StropeCount * 2) ? StropePause : (statusStrope % 2) ? StropeAN : StropeAUS;
    if (millis() - laststrope > wartezeit || !statusStrope) {
      statusStrope++; //nach Warten, Status erhöhen
      if (statusStrope > StropeCount * 2) statusStrope = 1; //und über Maximum umbrechen
      _set = true;  //wir haben die LED umzuschalten
      laststrope = millis();  //und merken uns, wann wir Das gemacht haben
    }
  } else if (statusStrope % 2) {
    //Strope ist AUS, deshalb hier ausschalten, wenn die LES gerade an ist.
    statusStrope = 0; //beim nächsten Aktivieren fangen wir wieder vorne an
    _set = true;      //wir haben den Pin umzuschalten
  }
  if (_set) {
    digitalWrite(_pinStrope, statusStrope % 2); //aus dem Status wird der Zustand der LED berechnet
    Serial.println(statusStrope);
    _set = false;   //LED ist umgeschaltet, also den Merker auf false zurück
  }
}

Das mit PulseIn ist schon etwas schwierig.
Man müsste 'schauen', ob die Zeit gekommen ist, daß man auf den Impuls wartet.
Da der Impuls alle ca. 25ms wiederholt wird, sollte sich Das auch per millis() erschlagen lassen, wann man auf den Impuls wartet.
Dann aber mit einem TimeOut von maximal 2000ns - der maximal zu erwartenden Länge.
Wir wollen einen Impuls einlesen, nicht den Rest des Winters hier festsitzen!

Der Sketch hier rast 1,7 Millionen Mal beim Blinken durch loop() und fast 2,7 Millionen Mal, wenn Das nicht gefragt ist.
Trotz der seriellen Ausgaben mit 9600 Baud !! (jedes Zeichen braucht eine ms Zeit)

Das sollte ausreichen, um sich auch auf das regelmäßig wiederkehrende Sender-Signal einzuschießen.

MfG

skyfox60:
Da bremse ich doch durch die Todzeit das System um 25mS aus, oder verstehe ich das falsch?

Das verstehts Du schon richtig - pulseIn ist blockierend, eigentlich auch sowas wie ein delay().
Damit dreht die 'Lok' :wink: ihre Kreise natürlich erheblich langsamer. Wenn Du mit den langsameren Reaktionszeiten auskommst, sollte das aber trotzdem funktionieren. Du kannst dann halt keinerlei Aktionen machen, die in einem schnelleren Takt als diese 25ms ablaufen.

skyfox60:
Da es sich jedoch nicht um eine Ampel handelt, sondern lediglich um schnöde Licht an- Licht aus abfragen, die nicht eben Zeitkritisch sind, handelt, könnte man ja vielleicht ( ich nur mal wieder nicht wie ) die Pulseabfrage auch mit einem Timer steuern, und nur alle 1 - bis 2 Sekunden mal fragen, wie der Puls ausschaut.

Grundsätzlich kann man so eine pulsIn-Messung auch nicht blockierend machen. Wenn dein loop schnell genug ist, dann einfach durch Abfrage des PinStatus, und mit micros() die Zeit zwischen steigender und fallender Flanke messen ( wobei Du den loop zwischen den Flanken natürlich weiterlaufen lässt - sonst ist es ja wieder blockierend). Deine Pulsmessung ist dann eben auch wieder so ein Abschnitt im loop wie die anderen auch: Bei der steigenden Flanke merkst Du dir die micros(). Wenn sich am Pin nichts ändert, geht es einfach durchs 'leere Gleis'. Bei der fallenden Flanke liest Du wieder die micros() und bildest die Differenz.
Je nachdem, was Du noch im loop machst, könnte da die Auswertegenauigkeit aber schon knapp werden. Ansonsten über einen Interrupt-Eingang, der die Pulsflanken erkennt, und dann in der ISR mit micros() die Zeit dazwischen bestimmen.

Die Frage ist, ob das für dich notwendig ist, oder ob du mit deinem 25ms-Raster im loop auskommst. Wenn ja, bestimmst Du am Anfang des loop deine Pulslänge mit pulsIn, und setzt dem entsprechend eine Variable ( so wie im Tutorial das 'bueBelegt'), die Du dann an den jeweiligen Stellen im loop auswerten kannst.