Licht ins Modell - mit einem Drehlicht
Drehlichter werden auf Fahrzeugen und Flugzeugen zur Gefahrensignalisation verwendet. Basierend auf dem Arduino-Board wollte ich ein Drehlicht entwickeln, dass einem Original annähernd nahekommt. Der Hauptunterschied zum Original liegt in der Erzeugung der Rotationsbewegung des Lichtes. Richtige Drehlichter haben eine zentrale Glühbirne um die ein Hohlspiegel rotiert. Beim Modell behilft man sich gerne, in dem man einige LEDs im Kreis anordnet und als eine Art Lauflicht ansteuert.
Bei dem hier vorgestellten Typ handelt es sich um ein Zweistrahldrehlicht, wo der Lichtstrahl auf zwei Seiten entgegengesetzt abgestrahlt wird. Inspiriert durch kommerzielle Produkte wurden folgende Eckdaten festgelegt:
8 LEDs, jeweils zwei rote LEDs parallel/seriell geschalten
einfachste Ansteuerung ohne Leistungsstufe (geeignet für kleine Modelle, max. 20-30mA)
weicher Übergang durch PWM-Ansteuerung
Das Funktionsprinzip ist einfach. Die LEDs werden zeitlich versetzt linear von 0 auf 100% Helligkeit hochgefahren und in gleicher Weise wieder auf 0% abgesenkt. Während die eine LED seine Helligkeit verringert, steigert die nachfolgende LED die ihre. So entsteht der Eindruck, dass sich das Licht quasi nahtlos weiterbewegt. Einen wesentlichen Anteil am realistischen Eindruck haben Art und Anordnung der LEDs. Acht LEDs stehen im 45 Grad Winkel zueinander. LEDs mit einem Leuchtkegel von mehr als 45 Grad Öffnungswinkel sind dabei besser geeignet als LEDs mit lediglich 20 Grad . Ein schmalerer Leuchtkegel wird in weiterer Entfernung unbeleuchtete Bereiche zurücklassen und somit den Effekt unterbrechen. Am besten sind kleine LEDs mit kugelförmiger Abstrahlcharakteristika. Für PowerLEDs muss aber zwingend noch eine Leistungsstufe vorgeschalten werden. Kühlung unbedingt beachten.
Software
Für die PWM der LEDs wird aktuell ein Timerinterrupt mit 0.5ms Intervall verwendet. Ein Zähler startet mit 0 und wird mit jedem Interrupt um Eins erhöht. Ist der Zähler kleiner als die geforderte LED-Helligkeit (LEDxDutyCycle) wird die LED eingeschalten. Überschreitet der Zähler beim nächsten Interrupt diesen Wert, erlöscht die LED. Erreicht der Zähler das programmierte Maximum (20), wird der Zähler auf Null gesetzt und ein PWM-Zyklus startet von neuem.
Der Plan, die Helligkeit in 1% Schritten zu steuern scheiterte wegen Timingproblemen. Die Programmlänge der Interruptroutine ergibt sich konkret aus der Anzahl separat angesteuerter LEDs und den Plausibilitätschecks. Dauert die Verarbeitung zu lange, unterbricht sie das freilaufende Hauptprogramm immer mehr und führt damit zu Störungen. Da die Interruptroutine auch das Timing des Hauptprogramm steuert, sind zudem Interferrenzen aufgetreten. Als ersten Schritt habe ich die Anzahl der Helligkeitsstufen auf zwanzig reduziert. Das sollte für einen optisch weichen Helligkeitsverlauf noch ausreichen. Im Gegenzug konnte der Intervall der Interruptroutine ebenso um den Faktor fünf verlängert werden, Die Störungen im Hauptprogramm sind damit behoben. Diese Software lässt sich auch sehr gut in reinem Assembler programmieren.
Hardware
Weil die Hardware so einfach ist, habe ich kein Schema hinzugefügt. Es genügen vier normale I/O-Ausgänge eines ATMEL Prozessors. Je I/O Port werden die zwei, sich gegenüberliegenden LEDs angeschlossen. Ob in Serie oder parallel spielt keine grosse Rolle. Meine Ansteuerung arbeitet mit positiver Logik. Alle LEDs werden auf der Kathode zusammengefasst und mit einem 100 Ohm Widerstand gegen Masse geschalten. Ist zwar Quick&Dirty, aber ausreichend fürs Prinzip.
Natürlich sind im Bascom Programm die entsprechenden I/O Ports Euren Erfordernissen anzupassen. Auch sollte der Timer passend eingestellt werden.
Video / Bilder
/
Software
' * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
' Drehlicht
' copyright by flightronic.com 2009
' ' * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
'********** Configuration Settings **********
$regfile = "m328pdef.dat"
$crystal = 16000000
$hwstack = 16
$swstack = 16
$framesize = 16
Const False = 0
Const True = 1
Dim TickCounter as Long
Dim TickDutyCycle as Boolean
Dim adcCount as Word
Dim adcHigh as Byte at adcCount + 1 Overlay
Dim adcLow as Byte at adcCount Overlay
Dim PWMCounter as Byte
Dim Led1DutyCycle as Byte
Dim Led2DutyCycle as Byte
Dim Led3DutyCycle as Byte
Dim Led4DutyCycle as Byte
Dim DrehlichtState As Byte
Dim B as Byte
LedGelb Alias PORTB.5 'Arduino Onboard LED
Led1 Alias Portb.0
Led2 Alias Portb.1
Led3 Alias Portb.2
Led4 Alias Portb.3
Config PinB.0 = Output
Config PinB.1 = Output
Config PinB.2 = Output
Config PinB.3 = Output
Config PinB.5 = Output
Macro InitADC
'Init ADC with AVCC as Reference
ADMUX = &B01100000 ' Reference = ACVV, Channel = 0, ADLAR=1!!
ADCSRA = &B10000101 ' Enable Timer, Prescaler = 32
ADCSRB = &B00000000
End Macro
Macro ReadADC
ADCSRA.ADSC = 1 'Start Conversion
Do : Loop Until ADCSRA.ADSC = 0 'Wait until conversion is finished
adcLow = ADCL 'Read Lowbyte
adcHigh = ADCH 'Read Highbyte (Reading Highbyte clears Conversion ready bit)
End Macro
InitADC
ReadADC 'first convertion is crab
Config Timer1 = Timer , Prescale = 64 , Clear Timer = 1 'set timer
Compare1a = 125
Compare1b = 125
On Compare1A _Timer1
Enable Compare1A
Enable Interrupts
DrehlichtState = 1 ' set first state
Do
If TickDutyCycle = True Then 'if time has passed, do next step
TickDutyCycle = False
Select Case DrehlichtState
Case 1 'Set very first values
Led1DutyCycle = 20
Led2DutyCycle = 0
Led3DutyCycle = 0
Led4DutyCycle = 0
B = 1 'initial speed
DrehlichtState = 2 'goto next state
Case 2
Led1DutyCycle = Led1DutyCycle - B
Led2DutyCycle = Led2DutyCycle + B
If Led2DutyCycle > 20 Then
Led1DutyCycle = 0
Led2DutyCycle = 20
DrehLichtState = 3
End If
Case 3
Led2DutyCycle = Led2DutyCycle - B
Led3DutyCycle = Led3DutyCycle + B
If Led3DutyCycle > 20 Then
Led2DutyCycle = 0
Led3DutyCycle = 20
DrehLichtState = 4
End If
Case 4
Led3DutyCycle = Led3DutyCycle - B
Led4DutyCycle = Led4DutyCycle + B
If Led4DutyCycle > 20 Then
Led3DutyCycle = 0
Led4DutyCycle = 20
DrehLichtState = 5
End If
Case 5
Led4DutyCycle = Led4DutyCycle - B
Led1DutyCycle = Led1DutyCycle + B
If Led1DutyCycle > 20 Then
Led4DutyCycle = 0
Led1DutyCycle = 20
DrehLichtState = 6
End If
Case 6
ReadADC 'get poti position (0-1023)
B = adcHigh 'keep only highbyte
Shift B , Right , 5 'shift it to the right to decrease resolution
If B = 0 Then B = 1 'zero is not valid
DrehlichtState = 2 'start cycle again
End Select
End If
Loop
_Timer1:
If PWMCounter < LED1DutyCycle Then
Set Led1
Else
Reset Led1
End If
If PWMCounter < LED2DutyCycle Then
Set Led2
Else
Reset Led2
End If
If PWMCounter < LED3DutyCycle Then
Set Led3
Else
Reset Led3
End If
If PWMCounter < LED4DutyCycle Then
Set Led4
Else
Reset Led4
End If
If PWMCounter < 19 Then
Incr PWMCounter
Else
PWMCounter = 0
TickDutyCycle = True
End If
Return