home     Inhaltsverzeichnis
erste Version am 05.12.2017
letzte Änderung am 15.12.2017

LED-Streifen als Nachtlicht - Seite 2


Anpassung des Testaufbaus

Zuerst habe ich das 25 Meter lange Kabel von Netzteil zum Breadboard und das 10 Meter lange Kabel vom Breadboard zu den LEDs durch sehr viel kürzere Versionen ersetzt. Das hat schon mal nix gebracht.
Dann habe ich den NPN-Leistungstransistor MJE3055 durch einen Logic-Level-MOSFET IRLZ34N ersetzt. Ebenfalls keine relevante Änderung.
Schließlich habe ich den MOSFET aus dem Breadboard gezogen und eine Brücke zwischen Drain und Source eingebaut.
Weil auch das nicht zu 12V über den LEDs geführt hat, deute ich es mal so, dass das Breadboard und die Drahtbrücken darauf den Spannungsverlust verursachen.
Und als Beweis dieser Deutung führt eine kurze Drahtbrücke zwischen GND vom 12V-Eingang zum GND vom LED-Streifen zu sichtbar helleren LEDs.

Deshalb könnte es Sinn machen, den MOSFET direkt am LED-Streifen zu platzieren. Die 12V aus dem Netzteil werden dann mit zwei dicken Strippen zum LED-Streifen geführt. Von da aus geht es mit drei dünnen Strippen weiter zum ATmega328 bzw. zum 5V-Regler. Zwei Strippen für die 12V, die dritte Strippe wäre quasi der Rückweg für das PWM-Signal zum Gate des MOSFETs.

Der Kühlkörper des IRLZ34N ist mit Drain verbunden. Ich könnte ihn also ggf. an die jeweilige Alu-Leiste schrauben, in der die LED-Streifen reingeklebt werden.
Beschaltung IRLZ34N     Anschluß MOSFET

Oder ich baue die Lochrasterplatte für die komplette Schaltung gleich derart auf, dass sie direkt an der Alu-Leiste montiert werden kann - nur der Bewegungssensor würde mittels dreipoliger Strippe frei positionierbar ausgelegt. Zwecks Test über Arduino bräuchte es dann einen Adapter-Sockel, der statt des ATmega328 in dessen Sockel gesteckt werden könnte. Lediglich die Pins GND, A0, D2 und D11 müssten auf den Arduino gepatched werden.

Eben habe ich mir zehn 5V-Regler LF50CV und zwei 12V-Netzteile bestellt.
Der 5V-Regler soll einen Leerlaufstrom von 0,5mA haben, das Netzteil soll 3A bzw. 35W liefern und die "No load power consumption" ist mit "<0.075W" angegeben.
Damit brauche ich dann keinen Kabelkanal im Flur. Jede Treppe bekommt ihr eigenes Netzteil und ihren eigenen 5V-Regler.


Fototransistor statt Fotowiderstand

Gestern Abend habe ich mir überlegt, dass das Licht an der Treppe sicher häufiger mal kurz nach dem automatischen Einschalten des LED-Streifens eingeschaltet werden wird. Diesen Fall würde meine derzeitige Firmware komplett ignorieren, weil der LDR nur einmalig vor dem Einschalten abgefragt wird.
Der Grund dafür war, dass ich die Umgebungs-Helligkeit bei eingeschalteten LEDs nur dann korrekt messen könnte, wenn der LDR jenseits des von den LEDs beleuchteten Bereiches montiert wäre. Wegen der Trägheit der LDRs kann ich die LEDs nicht einfach ausschalten, 100 Mikrosekunden lang auf den analogRead() warten und sie danach wieder einschalten. Hier steht was von "mehreren Sekunden Dunkelheit", bis der Widerstand zur Helligkeit passt.

Aber es gibt neben Fotowiderständen ja auch noch Fototransistoren und Fotodioden. Die sollten schneller sein.
Drei Fototransistoren vom Typ BPW40 habe ich in meiner Bastelkiste.
BPW40
Erste Tests damit zeigen einen unerwartet stark gerichteten Messbereich.
Im Datenblatt findet sich dann auch eine Kennlinien-Grafik, die wohl so zu deuten ist, dass nur ein 40°-Winkel erfasst wird.

Meine Testschaltung sieht nun so aus, dass der BPW40 mit einem 100KΩ-Widerstand als Spannungsteiler geschaltet ist. Der Widerstand geht gegen Masse.
Weiterhin habe ich eine LED vor dem BPW40 positioniert.
Bei ausgeschalteter LED liefert der analogRead() einen Wert um 30, bei eingeschalteter LED ziemlich konstant 993.
Wird die LED jedoch erst unmittelbar vor dem analogRead() umgeschaltet, ändern sich diese Werte extrem.

Das hier ist der Test-Sketch:
/* -------------------------------------------------------------------
* Messung zwischen Fototransistor und 100KOhm gegen Masse über A0.
* LED an D3.
*
*/

void setup() {
Serial.begin(115200);
pinMode(3, OUTPUT);
}

void loop() {
static int val, toggle=0, std=0, del=0;

digitalWrite(3, toggle);
if(del>0) delay(del);
val=analogRead(0);
Serial.println(val);

toggle^=1;
digitalWrite(3, std);
delay(1000);
}

Folgende Werte werden entsprechend Initialisierung der Variablen std und del geliefert:
std del Wert aus Wert ein
003060
10985993
0130993
0230993
01030993
11400993
12130993
1440993
1535993
1631993
11030993

Ergebnis: auch beim Fototransistor braucht es mindestens sechs Millisekunden, bevor Dunkelheit korrekt erkannt wird. Helligkeit braucht nur eine Millisekunde.
Leider ist es quasi als nervöses Zucken wahrnehmbar, wenn die eingeschaltete LED einmal pro Sekunde für 6mS abgeschaltet wird.
Somit taugt der Ansatz in dieser Form leider nix.

Vorsichtshalber habe ich die Test-Schaltung nochmal auf einem anderen Breadboard zusammengesteckt und dabei möglichst kurze Drahtbrücken verwendet. Also für den Fall, dass sich beim ersten Aufbau irgendwo Kapazitäten eingeschlichen haben sollten. Jedoch haben sich die Werte-Verhältnisse durch den geänderten Aufbau nicht verändert.
Ersetze ich den 100KΩ-Widerstand durch einen mit 10KΩ, reicht in beiden Fällen eine Millisekunde Wartezeit. Leider spielt sich bei diesem Widerstand sämtliche Helligkeit (die mich interessiert) im Wertebereich unterhalb von 10 ab. Ich will hier aber eine möglichst hohe Auflösung bei Dunkelheit haben.


Ein anderer Ansatz könnte sein, von vorne herein die Helligkeit des Umgebungslichts und die der LEDs in Summe zu betrachten. Es ist ja ohnehin geplant, die LEDs nicht schlagartig auszuschalten, sondern sie langsam runter zu dimmen. Daher könnte einfach solange gedimmt werden, bis eine Mindesthelligkeit übrig bleibt. Allerdings darf dann nicht erst 30 Sekunden nach der letzten Bewegungserkennung mit dem dimmen begonnen werden.
In diesem Fall müsste wohl berücksichtigt werden, dass die Frequenz des PWM-Signals nur 500Hz beträgt. Also eine Periodendauer von 2mS. Der analogRead() braucht 100µS = 0,1mS pro Messung. Würden die LEDs z.B. mit 50% angesteuert, wären sie 1mS lang an und 1mS lang aus. Bei einem zu wenig trägen Fototransistor könnte es theoretisch passieren, dass die Messung mehrmals hintereinander komplett in einer Dunkel- oder komplett in einer Hell-Phase läge.
Dementsprechend sollte die Helligkeitsmessung mindestens zwei Millisekunden lang Werte holen, die einzelnen Werte aufaddieren und als Rückgabe den Mittelwert liefern.

Analog zum manuellen Einschalten des Treppenlichts muss auch das manuelle Ausschalten des Lichts im Flur betrachtet werden. Einer der Schalter für die Flurbeleuchtung befindet sich direkt an der Treppe zum ersten Stockwerk und somit im Erkennungsbereich des (zukünftigen) Bewegungsmelders. Damit wird es häufig mal vorkommen, dass das Flurlicht an diesem Schalter ausgeschaltet wird, der Bewegungsmelder den ATmega328 aber schon kurz vorher aus dem Tiefschlaf geweckt hatte. Dieser hätte dann voraussichtlich erkannt, dass die Treppe hell genug beleuchtet ist und sich direkt wieder schlafen gelegt. Weil vom Bewegungsmelder jedoch keine erneute LOW-HIGH-Flanke käme, blieben die LEDs aus - auch dann, wenn es nach Abschalten der Flurbeleuchtung nun zappenduster auf der Treppe wäre.
Daher darf der Tiefschlaf nicht sofort eingeleitet werden, nachdem ausreichende Helligkeit detektiert wurde.
Beim Bewegungsmelder wäre gemäß dieser Seite die obere Jumperstellung zu wählen, damit er bei Bewegung sekündlich Signale an den ATmega328 sendet.


Bewegungsmelder - die Zweite

Leider verhalten sich meine Bewegungsmelder aber nicht so, wie auf der o.g. Seite angegeben (bzw. ich den Text deute....):
Dieser Code:
#define PIN 2
unsigned long tm1, tm2;

void setup() {
Serial.begin(115200);
pinMode(PIN, INPUT);
tm1=millis();
attachInterrupt(digitalPinToInterrupt(PIN), isr, CHANGE);
}

void isr() {
tm2=millis();
if(digitalRead(PIN)==LOW) {
Serial.print("HIGH-LOW war HIGH für ");
} else {
Serial.print("LOW-HIGH war LOW für ");
}
Serial.print(tm2-tm1);
Serial.println(" Millisekunden");
tm1=tm2;
}

void loop() {
}

...liefert bei konstanter Bewegung in der unteren (oder auch äußeren) Jumperstellung:
LOW-HIGH   war LOW  für 2640 Millisekunden
HIGH-LOW   war HIGH für 2756 Millisekunden
LOW-HIGH   war LOW  für 6679 Millisekunden
HIGH-LOW   war HIGH für 2755 Millisekunden
LOW-HIGH   war LOW  für 5952 Millisekunden
HIGH-LOW   war HIGH für 2754 Millisekunden
LOW-HIGH   war LOW  für 6168 Millisekunden
HIGH-LOW   war HIGH für 2754 Millisekunden

In der oberen (oder auch inneren) Jumperstellung wird bei konstanter Bewegung dies geliefert:
LOW-HIGH   war LOW  für 6154 Millisekunden
HIGH-LOW   war HIGH für 11071 Millisekunden
LOW-HIGH   war LOW  für 6068 Millisekunden
HIGH-LOW   war HIGH für 12120 Millisekunden
LOW-HIGH   war LOW  für 6503 Millisekunden
HIGH-LOW   war HIGH für 32937 Millisekunden

Bem.: Oben/unten, links/rechts bezieht sich auf die Ansicht von der Sensor-Seite, Stecker oben.

Bei der unteren Jumperstellung kommt bei erkannter Bewegung unmittelbar eine LOW-HIGH-Flanke. Der Pegel bleibt solange HIGH, wie vom linken Poti vorgegeben (hier also 2,75 Sekunden). Danach gibt es trotz konstanter Bewegung eine HIGH-LOW-Flanke. Dann dauert es sechs bis sieben Sekunden, bevor wieder Bewegung gemeldet wird. Diese sechs bis sieben Sekunden gelten (natürlich nur bei durchgängiger Bewegung) auch dann, wenn das linke Poti auf längere Haltezeit eingestellt ist.

Bei der oberen Jumperstellung kommt bei konstanter Bewegung genau eine LOW-HIGH-Flanke. Der Pegel bleibt auf HIGH, solange Bewegung erkannt wird. Allerdings meint dieses blöde Teil gelegentlich, keine Bewegung erkannt zu haben - obwohl ich dem Sensor durchgängig wildeste Akrobatik geboten habe.....
Daher wird zwischendurch immer mal wieder für sechs/sieben Sekunden LOW gemeldet.

Aber was solls. Erkannte Bewegung wird mittels LOW-HIGH-Flanke gemeldet. Wenn sich der ATmega328 erst dann wieder in den Tiefschlaf versetzt, nachdem er für mindestens 30 Sekunden lang einen LOW-Pegel am Bewegungsmelder gesehen hat, sollte es egal sein, wie der Jumper eingestellt ist.
Pegel bleiben für mindestens zwei Sekunden lang stabil. Damit sollte genug Zeit sein, Pin2 zu pollen und trotzdem keinen Wechsel zu verpassen. Alternativ könnte die isr()-Funktion so erweitert werden, dass sie neben dem Aufwachen aus dem Tiefschlaf bei LOW-HIGH-Flanke zusätzlich eine globale Nachlaufzeit-Variable auf "Jetzt + 30 Sekunden" setzt.

In der Software kann also davon ausgegangen werden, dass der ATmega328 bei Bewegung auf der Treppe garantiert wach ist.
Damit ist das Problem jetzt nur noch die Bestimmung der LED-Helligkeit anhand der LDR- oder Fototransistor-Helligkeit.


Helligkeits-Beziehung

Wobei es mit dem nur noch so eine Sache ist. Die Idee ist schließlich, dass die LEDs bei Schummerlicht mit ihrer maximalen Helligkeit leuchten. Bei absoluter Dunkelheit sollen sie hingegen gerade soviel Licht liefern, dass man die Treppe noch sicher benutzen kann - und niemand [Anderes] durch unnötig helles Licht belästigt wird.
Folglich wird es etwas schwierig mit der oben angedachten Helligkeits-Summe aus LED- und Umgebungs-Licht. Erfasst der Helligkeitssensor auch den von den LEDs ausgeleuchteten Bereich, hat man einen Regelkreis mit Rückkopplung. Es soll auf jeden Fall ein Schwingen oder Aufschaukeln der Helligkeit verhindert werden.

Vielleicht könnten zwei initiale Helligkeitsmessungen helfen: eine unmittelbar vor dem Einschalten der LEDs und eine unmittelbar danach.
Anhand der ersten Messung wird die einzustellende LED-Helligkeit bestimmt. Die zweite Messung dient der Änderungserkennung, auf die sich ab der dritten Messung bezogen wird. Also folgender Ablauf:
Die Software sollte also wohl mindestens zwei statische Helligkeitswerte kennen:
  1. die Helligkeit, ab der die LEDs nicht eingeschaltet werden müssen
  2. die minimale Helligkeit, die bei absoluter Dunkelheit durch die LEDs bereitgestellt wird


Aufbau der Schaltung

Heute soll endlich das Paket von Reichelt ankommen. Damit habe ich dann zehn sparsame 5V-Regler, zwei sparsame 12V-Netzteile und vier von diesen Gehäusen.
Die Gehäuse sind für die Bewegungsmelder gedacht. Wahrscheinlich werde ich auch noch den Fototransistor darin unterbringen. Der Fototransistor hat gegenüber dem Fotowiderstand zwar den Vorteil, schneller auf Helligkeitsänderungen zu reagieren - jedoch den Nachteil des engen Erfassungsbereiches. Bei Einbau in ein rechteckiges Gehäuse kann ich ihn also nur nach vorne oder nach unten gucken lassen.

Gerade habe ich einen Test mit Laptop + ArduinoUNO + Fototransistor auf der Treppe gemacht.
Ergebnis: ein 10KΩ-Widerstand gegen Masse scheidet definitiv aus. Damit liefert der analogRead() für die Helligkeit, ab der die LEDs gerade so eingeschaltet werden sollen, einen Wert von 6. Und beim Wert 0 kann man seine Umgebung noch halbwegs gut erkennen.
Mit einem 100KΩ-Widerstand gegen Masse liefert der analogRead() den Wert 60, wo der 10KΩ den Wert 6 geliefert hat.


Eine Anfrage im Mikrocontroller-Forum hat zwei potentielle Verbesserungsmöglichkeiten ergeben:
  1. ich könnte analogReference(INTERNAL) nutzen, um die Referenzspannung von 5V auf 1,1V umzuschalten ... und damit die Auflösung im unteren Bereich verbessern.
  2. ich könnte die eingestellte LED-Helligkeit (die an analogWrite() übergeben wurde) verwenden, um damit von der gemessenen Gesamthelligkeit auf die real vorhandene Umgebungshelligkeit schließen zu können.

Mittlerweile ist die Schaltung auf Lochrasterplatte aufgebaut. Die Sensoren fehlen zwar noch, aber die sollen ja ohnehin in ein eigenes Gehäuse.
Sonderlich stabil lief der ATmega328 zunächst nicht.
Konkret hat er sich mit dieser Test-Firmware regelmäßig aufgehängt:
/* -------------------------------------------------------------------
* Erster Test zur Ansteuerung eines LED-Streifens als Nachtlicht.
*
* Detlev Ahlgrimm, Dez. 2017
*/

#define LED_POWER_PIN 11

void setup() {
pinMode(LED_POWER_PIN, OUTPUT); // LEDs
analogWrite(LED_POWER_PIN, 0); // LEDs aus
}

void fadeOut(int led_val) {
int cur_led;

for(cur_led=led_val; cur_led>=0; cur_led--) {
analogWrite(LED_POWER_PIN, cur_led);
if(cur_led>128) delay(5);
else delay(20);
}
}
void fadeIn(int led_val) {
int cur_led;

for(cur_led=led_val; cur_led<=255; cur_led++) {
analogWrite(LED_POWER_PIN, cur_led);
if(cur_led<=128) delay(5);
else delay(20);
}
}

void loop() {
fadeIn(0);
delay(2000); // jetzt sollte 12V an den LEDs anliegen
fadeOut(255);

delay(1000);

for(int i=0; i<10; i++) { // etwas quälen....
analogWrite(LED_POWER_PIN, 255);
delay(10);
analogWrite(LED_POWER_PIN, 0);
delay(10);
}
}

Ein zusätzlicher 2200µF-Elko hinter dem 5V-Regler scheint das Problem behoben zu haben.
Die zwei Meter LEDs pulsieren jetzt bereits seit über einer Viertelstunde gleichmäßig vor sich hin... und so sieht es derzeit aus:
Nachtlicht mit LED-Streifen: erste Version auf Lochraster
Nicht schön, aber selten ;-)
Und schließlich verschwindet die Leiterplatte sowieso hinter dem Handlauf der Treppe.

Den Schaltplan habe ich etwas erweitert:
LED-Streifen als Nachtlicht: Schaltplan

Neben den bereits genannten Änderungen (zusätzlicher Elko, BPW40 statt LDR und MOSFET statt NPN-Transistor) ist jetzt noch eine LED für Statusmeldungen dazugekommen.
Weiterhin habe ich die Idee mit dem Laptop + Arduino als temporärer Ersatz für den ATmega328 wieder verworfen.
Stattdessen ist nun eine sechspolige Buchsenleiste vorgesehen, über die während der Einmess-Phase diese vor einem Jahr mal gebaute ESP-01-Leiterplatte angeschlossen werden kann.
Leiterplatte mit ESP-01

Mit der können die Messwerte samt LED-Ansteuerungs-Parameter per WLAN an einen SocketServer übertragen werden.
Anhand dessen Logfile soll anschließend die Feinjustage der Firmware erfolgen.

Damit geht es auf der nächsten Seite weiter.