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. |

|
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.
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 |
0 | 0 | 30 | 60 |
1 | 0 | 985 | 993 |
0 | 1 | 30 | 993 |
0 | 2 | 30 | 993 |
0 | 10 | 30 | 993 |
1 | 1 | 400 | 993 |
1 | 2 | 130 | 993 |
1 | 4 | 40 | 993 |
1 | 5 | 35 | 993 |
1 | 6 | 31 | 993 |
1 | 10 | 30 | 993 |
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:
- 1.) Bewegung wurde erkannt, ATmega328 ist wach
- 2.) Helligkeit(A) messen
- 3.a.) es ist hell genug auf der Treppe
- 3.a.1.) 30 Sekunden lang sekündlich prüfen, ob aktuelle Helligkeit != Helligkeit(A)
- 3.a.2.) wenn es dunkler geworden ist -> zurück zu 2.)
- 3.b.) es ist nicht hell genug auf der Treppe
- 3.b.1.) LED-Helligkeit bestimmen, LEDs entsprechend ansteuern bzw. einschalten
- 3.b.2.) Helligkeit(B) messen
- 3.b.3.) 30 Sekunden lang sekündlich prüfen, ob aktuelle Helligkeit != Helligkeit(B)
- 3.b.4.) wenn es heller geworden ist
- 3.b.4.a.)
LEDs raufdimmen bis ist das egal
- 3.b.5.) wenn es dunkler geworden ist
- 3.b.5.a.) LEDs runterdimmen bis Minimal-Helligkeit erreicht ist
Die Software sollte also wohl mindestens zwei statische Helligkeitswerte kennen:
- die Helligkeit, ab der die LEDs nicht eingeschaltet werden müssen
- 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:
- ich könnte analogReference(INTERNAL) nutzen, um die Referenzspannung von 5V auf 1,1V umzuschalten ... und damit die Auflösung im unteren Bereich verbessern.
- 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:
Nicht schön, aber selten ;-)
Und schließlich verschwindet die Leiterplatte sowieso hinter dem Handlauf der Treppe.
Den Schaltplan habe ich etwas erweitert:
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.
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.