Wie auf Rückgabewert von LDR verzögert reagieren?

Ein LDR soll die Helligkeit einer 7 Segment Anzeige für eine Uhr steuern. Wenn es im Raum hell ist, soll die Anzeige heller sein als wenn es im Raum dunkel ist.
Damit sich die Helligkeit nicht gleich ändert nur weil jemand vorbei läuft oder etwas Licht vom TV auf den Sensor fällt, soll die Helligkeitsänderung verzögert statt finden. Dachte da an etwa 10 Sekunden.
Also der LDR misst eine Helligkeitsveränderung, dann wird 10 Sekunden gewartet, neu gemessen und wenn die Helligkeitsveränderung immer noch gemessen wird, dann wird die Helligkeit vom Display angepasst.

Wie könnte ich so etwas umsetzen? Hab da nicht wirklich eine Idee. Außer vielleicht das bei der ersten Helligkeitsveränderung ein 10 Sekunden Timer gestartet wird. Finden in dieser Zeit weitere Veränderungen statt, werden diese ignoriert. Sind die 10 Sekunden abgelaufen, dann wird neu gemessen und der Wert mit dem vorherigen verglichen. Ist die Veränderung größer oder kleiner als zB. 8, dann passt er das Display an. Ansonsten nicht und der 10 Sekunden Timer wird ausgeschaltet und es wird auf die nächste Veränderung gewartet.
8 ist momentan ein Phantasiewert, er dient einfach dazu das nicht auf jede minimale Veränderung reagiert wird.

Was meint ihr dazu? Gibt es vielleicht irgendwo Beispiele für so etwas? Oder habt ihr Vorschläge wie man es noch umsetzen könnte?

Die Idee ist doch erst mal nicht schlecht. Du solltest aber nicht auf den gleichen Wert, sondern auf Über-/Unterschreiten zweier Schwellen prüfen.
Da der Arduino sich auch noch mit der Anzueige beschäftigen soll, wäre es sinnvoll, ihn in den 10 Sekunden nicht zu blockieren.
Als Anleitung für die Zeitsteuerung solltest Du Dir das Beispiel BlinkWithoutDelay in der IDE anschauen.

Gruß Tommy

(deleted)

modi0:
Also der LDR misst eine Helligkeitsveränderung, dann wird 10 Sekunden gewartet, neu gemessen und wenn die Helligkeitsveränderung immer noch gemessen wird, dann wird die Helligkeit vom Display angepasst.

Von der Idee her machbar, aber nicht sinnvoll.

Wenn genau dann, wenn die 10 Sekunden(!) um sind, sich erneut die Veränderung auftut und sonst nicht, kommt es trotzdem zur Veränderung.
Mehr noch: Nehmen wir an, der LDR wird verdunkelt, nach 9 Sek. wird ein Licht angemacht.

Nach Deiner Annahme würde nur dann eine Änderung der Displayhelligkeit durchgeführt, wenn erneut 10 Sekunden dieser Wert Bestand hat.

Mein Ansatz:
Baue ein Array.
Messe wiederholt den LDR.
Schreibe die Werte in das Array.
Generiere aus den Werten im Array einen Durchschnitt.
Der Durchschnitt wird dann der Wert für die Helligkeit des Display.
Code ungetestet, aber mit seriellen Ausgaben und kleinen Erklärungen.

// Forumsketch Durchschnitt analogRead für analoWrite Backlight
// https://forum.arduino.cc/index.php?topic=713753.0
// PIN A0 LDR / PIN 9 PWM Output

byte Helligkeit[20]; // in dem Array werden die umgesetzten Werte des LDR gespeichert Grösse kann bis gutgehend 250 geändert werden ohne weitere Anpassungen!

void setup()
{
  Serial.begin(115200);
  Serial.println(F("Start.."));
  Serial.println(sizeof(Helligkeit));
  for (int i = 0; i < sizeof(Helligkeit) - 1; i++)
  {
    Helligkeit[i] = analogRead(A0);  // füllt Array mit initialen Werten.
  }
}

void loop()
{
  static int arrayposition = 0;
  if (millis() % 500 == 0) // Festsetzen der Aktualisierung
  {
    Serial.println(F("Hole aktuelle Helligkeit"));
    Helligkeit[arrayposition] = getLDR(); // Merken des ausgelesenen Wertes
    Serial.print(F("Wert gemerkt: "));
    Serial.println(Helligkeit[arrayposition]);
    arrayposition++;
    if (arrayposition >= sizeof(Helligkeit) - 1)
    {
      arrayposition = 0;
    }
    setBacklicht(); // Wird nur aufgerufen, wenn auch tatsächlich LDR gelesen wird!
  }
}

byte getLDR()
{
  return (map (analogRead(A0), 0, 1023, 0, 254));
}

void setBacklicht()
{
  const int LCD_PWM_PIN = 9; // Zuweisung BacklichtPIN
  unsigned int Ausgabe = 0;
  Serial.println(F("Ermittle Durchschnitt.."));
  for (int i = 0; i <= (sizeof(Helligkeit) - 1); i++)
  {
    Ausgabe += Helligkeit[i];
  }
  Ausgabe = Ausgabe / (sizeof(Helligkeit)-1);
  Serial.print(F("Gebe folgenden Wert aus: "));
  Serial.println(Ausgabe);
  analogWrite(LCD_PWM_PIN, Ausgabe);
}

um einzelne Ausreißer zu glätten würde ich den gelesenen ADC Wert langsam anpassen:
Ist es aktuell Heller als davor eins dazu zählen,
ist es dunkler - eins abziehen.

D.h der Wert pendelt/nähert sich langsam zum jeweiligen Zielwert. Einzelne Ausreißer wirken sich trotzdem nur um einen Schritt aus.

ungetestet

// Smooth analogRead für LDR
// https://forum.arduino.cc/index.php?topic=713753.0

const uint8_t ldrPin = A0;     // ein ADC pin mit LDR
uint16_t smooth;               // geglätteter ADC Wert

void setup()
{
  Serial.begin(115200);
  Serial.println(F("Start.."));
  smooth = analogRead(ldrPin);  // initial Wert
  setBrightness();
}

void loop()
{
  checkLDR();
}

void checkLDR()
{
  if (millis() % 500 == 0) // Aktualisierung im Halbsekundentakt
  {
    Serial.println(F("Lese Helligkeit "));
    uint16_t actual = analogRead(ldrPin);
    Serial.print(actual);
    if (actual > smooth) 
    {
      smooth++;
      setBrightness(); 
    }
    else if (actual < smooth) 
    {
      smooth--;
      setBrightness();
    }
    Serial.print("->"); Serial.println(smooth);
  }
}

void setBrightness()
{
  int newBrightness = map (smooth, 0, 1023, 0, 255);  // https://www.arduino.cc/reference/de/language/functions/math/map/
  Serial.print(F("Neue Helligkeit: "));
  Serial.println(newBrightness);

  // nur demo 
  const int LCD_PWM_PIN = 9; // Zuweisung BacklichtPIN
  analogWrite(LCD_PWM_PIN, newBrightness);
}

Aufpassen, der ADC Wert wird gemappt auf 0…255. Wenn du sowas wie LedControl verwendest, die haben einen range von 0…15 glaube ich.

Zum Sketch: man könnte noch auf ein Byte einkürzen, wenn man nicht den ADC Wert smoothed sondern den gemappten Wert (sofern der nur ein Byte ist…)

(deleted)

20201115_Durchschnitt_analogRead-201115a.zip (1.06 KB)

Danke für die Ideen. Den Code probiere ich morgen aus.
Meine Idee kam mir auch nicht so ganz richtig vor, daher frage ich hier.

setBacklicht(); // Wird nur aufgerufen, wenn auch tatsächlich LDR gelesen wird!

Da steht, dass setBacklicht nur aufgerufen wird wenn der LDR gelesen wurde. Aber es findet keine Abfrage darauf statt. So wie ich das sehe wird der Code alle 250ms ausgeführt. Oder übersehe ich was? Testen kann ich leider erst morgen.

Der smooth Code ist auch eine gute Idee.

In beiden Beispielen findet die Anpassung der Helligkeit aber doch quasi sofort statt. Wenn die Uhr zb. die Helligkeit von einem Fernseher abbekommt, dann passt sie die Helligkeit sehr oft an, oder? Wäre es nicht sinnvoller, wenn nicht auf jede Helligkeitsänderung sofort reagiert wird?
Dazu müsste ich eigentlich nur die Aktualisierung auf von 250 bzw 500ms auf z.B. 10 Sekunden setzen (oder vielleicht sogar 30 Sekunden). Es ist eigentlich nicht nötig das die Helligkeit in Echtzeit angepasst wird. Es geht nur darum dass die Anzeige Abends oder im Dunkeln nicht blendet und im Hellen gut lesbar ist.

(deleted)

modi0:

setBacklicht(); // Wird nur aufgerufen, wenn auch tatsächlich LDR gelesen wird!

Da steht, dass setBacklicht nur aufgerufen wird wenn der LDR gelesen wurde. Aber es findet keine Abfrage darauf statt. So wie ich das sehe wird der Code alle 250ms ausgeführt. Oder übersehe ich was? Testen kann ich leider erst morgen.

Durch die Modulo-Operation (%500) wird alle 500ms ein Wert am Analogpin ausgelesen und in das Array geschrieben.
Innerhalb des Funktionsblock ist auch die Funktion setBacklilicht() angesiegelt.
Sieht man schön an den Einrückungen - wenn Du meiner Klammersetzung nicht folgen kannst, drück mal STRG-T in der IDE. dann ist das Format auf Deine Einstellungen...

Ich habe den Hinweis extra da rein geschrieben, denn damit ist klar, das alle 500ms auch die Displayhelligkeit updatet wird.
Es gäbe auch noch eine weitere Variante.
Du könntest zum Beispiel prüfen, ob die Laufzeitvariable i == 0 ist und nur dann aktuallisieren.
In dieser Version würde somit 20 Werte gelesen, dann aktuallisiert. Damit wären Deine 10Sekunden annähernd dran. (20*500ms)

In beiden Beispielen findet die Anpassung der Helligkeit aber doch quasi sofort statt. Wenn die Uhr zb. die Helligkeit von einem Fernseher abbekommt, dann passt sie die Helligkeit sehr oft an, oder? Wäre es nicht sinnvoller, wenn nicht auf jede Helligkeitsänderung sofort reagiert wird?

Dafür lese ich ja die 20 Werte ein und bilde daraus den Durchschnitt.
Also 20 Werte a 155= 20155/20 -> 155 als Ausgabewert
Nehmen wir an, das nach dem dritten Wert mit einem Mal der Fernseher für 5 Werte einstrahlt und der Wert dann 200 ist
(3
155+5200+12150)/20-> 162
Du siehst, das sich der Wert recht langsam ändert.

Wenn Du das Array mit noch mehr Werten initialisierst UND/ODER die Abfrage des AnalogPin veränderst (z.B. %1000 für eine Sekunde) ist das Ganze noch langsamer.

Probier es aus. Versuche das durch ändern der Werte auf Deine Bedürfnisse anzupassen.

Hallo,

gleitender Mittelwert berechnen, bietet sich hier ebenfalls an. Das ist ein Dreizeiler.

Heinz

Ein meiner Meinung nach besserer Ansatz wäre, die Lib RunningMedian. Die hat eine Funktion, welche die äusseren Werte verwirft und aus den mittleren einen gleitenden Durchschnitt bildet. Diesen kannst du auf die Hellichkeit mappen.

Hallo,

für eine nicht hektische aber jederzeit sanfte Änderung sollte man permanent den gleitenden Mittelwert bilden. Den Faktor etwas höher wählen und mit leichter Verzögerung jeder neuen Mittelwertberechung, die ständig läuft, die Geschwindigkeit anpassen. Das wäre das Eine.

Der Basisbaukasten:

const byte FILTERFAKTOR = 50;   // Filterfaktor zur Mittelwerbildung
float Mittelwert;
const byte pinRead = A1;

void setup(void)
{ 
  Serial.begin(9600);
  Serial.println("\nStart");
  Serial.print("IN\t"); Serial.print("OUT\t\n");
}

void loop(void)
{   
  unsigned int Eingangswert = analogRead(pinRead);
  Serial.print(Eingangswert); Serial.print("\t");
  Filtern(Mittelwert, Eingangswert, FILTERFAKTOR);
  Serial.println(Mittelwert); 
  delay(1);
}

/*****************************************************************************************
** Funktion Filtern()  by GuntherB                                                      **
******************************************************************************************
** Bildet einen Tiefpassfilter (RC-Glied) nach.                                         **
** FF = Filterfaktor;  Tau = FF / Aufruffrequenz                                        **
**                                                                                      **
** Input: FiltVal der gefilterte Wert, NewVal der neue gelesene Wert; FF Filterfaktor   **
** Output: FiltVal                                                                      **
** genutzte Globale Variablen: Val  (call by Reference)                                 **
******************************************************************************************/

void Filtern(float &FiltVal, const unsigned int NewVal, const byte FF){
  FiltVal= ((FiltVal * FF) + NewVal) / (FF + 1); 
}

Spiele damit rum, ändere das delay in kleinen Werten, ändere den Filterfaktor und schau wie sich die Filterung verhält. Am Ende ersetzt du delay mit blockierfreier millis Programmierung.

Das andere wäre die Helligkeitsanpassung selbst. Deine 7 Segmentanzeige besteht doch bestimmt aus Leds? Hier gilt die gewünschte lineare Änderung dem Auge anzuspassen. Man erstellt sich ein PWM Wert Array, diese Werte werden vom Helligkeitssensor "ausgewählt" und der gleitenden Mittelwertbildung als aktuelles Endziel übergeben. LED-Fading – Mikrocontroller.net

Nochmal danke für die vielen Ideen und den Code.
Werde das alles ausprobieren und schauen was sich am besten eignet.

Als Anzeige verwende ich ein TM1637 Modul. In der Library gibt es eine Funktion display.setBrightness(x); zur Helligkeitsanpassung. Das Mappe ich dann mit dem Ergebnis der dimm Funktion. Falls es noch Probleme oder Rückfragen gibt, melde ich mich nochmal.