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

Drehlicht schnell

/

Drehlicht langsam

devboard.jpg ledkranz.jpg timings.jpg

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