Futaba S-Bus Protokoll
4. Juni 2017
Wie die NASA mit Voyager kommuniziert
6. Juni 2017
Alle anzeigen

Licht ins Modell – 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.
' * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
' 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
Deutsch