Hallo zusammen
Ich versuche eine Flugzeugbeleuchtung nach dem Aircraft Recognition
Lighting System (ARLS) nachzubilden.
Die Antikollisionslichter leuchten im Sekundentakt von Triebwerkstart
bis Triebwerkstop, d.h. wenn Schalter 1 'on' ist. Diese Lichter sind mit
PWM über Timer1 realisiert, sodass die LEDS ein rotierendes Licht
simulieren.
Sobald das Flugzeug in Bewegung kommt sind zusätzlich die
Positionslichter und Strobelichter dazugeschaltet, d.h. bei Schalter 2
'on'. Die Positionslichter (rot und grün) sind dauernd an und die
Stobelichter blitzen nach Vorschrift. Die zeitliche Abfolge ist mit
Timer0 realisiert.
Ich habe einen nahezu funktionierenden Code geschrieben. Das Problem
ist, dass beim Zuschalten, bzw. Abschalten der zusätzlichen Lichter
(über Schalter 2) der Sekundentakt der Antikollisionslichter nicht
eingehalten wird. Die Funktion für die Antikollisionslichter wird an 2
Orten aufgerufen, bei if-Bedingung 'Schalter 1 on' und bei if-Bedingung
'Schalter 1 und 2 on'.
Versuchsaufbau läuft auf einem ATmega8.
Gibt es eine Möglichkeit die Antikollisionslichter bei wechselnder
if-Bedingung im Takt zu halten?
Danke und Gruss
Firebird
Firebird schrieb:> Die Funktion für die Antikollisionslichter wird an 2> Orten aufgerufen, bei if-Bedingung 'Schalter 1 on' und bei if-Bedingung> 'Schalter 1 und 2 on'.
Dann ruf sie eben nur an einer Stelle auf. Dazu mußt Du natürlich den
Programmcode entsprechend umschreiben.
Nop schrieb:> Dann ruf sie eben nur an einer Stelle auf. Dazu mußt Du natürlich den> Programmcode entsprechend umschreiben.
Danke für den Tipp, ich war in Gedanken bei den Timern festgefahren.
Den Programmcode habe ich umgeschrieben. Zudem noch die PWM Funktion
invertiert (damit die LEDS auch dunkel sind) und noch die Werte
angepasst.
Funktioniert wunderbar bis auf ein neues Problem.
Sobald ich den Reset-Knopf drücke leuchten die LEDS an PB1/OC1A und
PB2/OC1B, auch nachdem ich den Versuchsaufbau vom Strom genommen und
wieder angeschlossen habe. Nach Betätigung von Schalter 1 funktioniert
alles wieder.
Woran kann das liegen?
Firebird schrieb:> Gibt es eine Möglichkeit die Antikollisionslichter bei wechselnder> if-Bedingung im Takt zu halten?
Setze den Timer auf den GgT-Wert der beiden Frequenzen und zähle danach
entsprechend.
Bsp.: 800ms und 1000ms blinken: Timer auf 200ms einstellen.
Nebenbei:
Wenn du schon einen Timer verwendest, dann benutze bitte keine delays.
Dieser blockiert nur.
TM F. schrieb:> Wenn du schon einen Timer verwendest, dann benutze bitte keine delays.> Dieser blockiert nur.
Das wäre natürlich super, diesen Leuchtturm-Effekt ohne delays zu
realisieren. Leider habe ich im Forum und auch im Internet keine
weiterführenden Informationen gefunden wie man das machen könnte.
Darum habe ich diese Funktion mal so stehen gelassen:
Firebird schrieb:> Zuerst möchte ich das Problem betreffend LEDs an PB1 und PB2 lösen:> Firebird schrieb:>> Sobald ich den Reset-Knopf drücke leuchten die LEDS an PB1/OC1A
dann initialisierst du nicht richtig nach dem Reset!
Ports auf Ausgang und low/high?
PWM auf 0 oder 1 je nachdem wie deine LEDs angeschlossen sind.
LED nach GND oder nach +V mit Rv?
Firebird schrieb:> Der Input Compare> Register Eintrag ICR1 war in der Funktion 'main' eingetragen:
Das reicht doch. Ich sehe nirgends Code, der ICR1 auf einen anderen Wert
setzt und von selbst kann ICR1 sich nicht ändern.
Unnütze Mehrfachzuweisungen sollte man vermeiden.
Es schadet auch nichts, bei jeder Änderung den neuen kompletten Code als
Anhang zu posten. Nur mit Schnipseln lassen sich die Änderungen sonst
kaum nachvollziehen.
Peter D. schrieb:> Das reicht doch. Ich sehe nirgends Code, der ICR1 auf einen anderen Wert> setzt und von selbst kann ICR1 sich nicht ändern.> Unnütze Mehrfachzuweisungen sollte man vermeiden.
ICR1 habe ich aus der Funktion 'main' entfernt und zur Funktion
'BeaconLeds()' hinzugefügt. Vermutlich ist mein vorangegangener Beitrag
unglücklich formuliert.
Im Anhang ist der komplete Code.
> Peter D. schrieb:> Das reicht doch. Ich sehe nirgends Code, der ICR1 auf einen anderen Wert> setzt und von selbst kann ICR1 sich nicht ändern.> Unnütze Mehrfachzuweisungen sollte man vermeiden.Firebird schrieb:> ICR1 habe ich aus der Funktion 'main' entfernt und zur Funktion> 'BeaconLeds()' hinzugefügt. Vermutlich ist mein vorangegangener Beitrag> unglücklich formuliert.>> Im Anhang ist der komplete Code.
Das würde schon richtig verstanden.
Wenn ICR1 einmal gesetzt wurde, braucht man es nicht wieder neu setzen.
Aber genau das tust du jetzt.
Nico W. schrieb:> Wenn ICR1 einmal gesetzt wurde, braucht man es nicht wieder neu setzen.> Aber genau das tust du jetzt.
Ok, jetzt hab ich's verstanden.
Wenn ICR1 wieder im 'main' drin steht, dann ist das Problem wieder da.
Die LEDs an PB1/OC1A und PB2/OC2A leuchten sobald der Versuchsaufbau an
Strom angeschlossen wird und auch wenn der Reset-Knopf gedrückt wird.
Sie sollten aus bleiben bis mit Schalter 1 eingeschaltet wird.
Ich habe echt keine Ahnung woran das liegt.
Firebird schrieb:> Wenn ICR1 wieder im 'main' drin steht, dann ist das Problem wieder da.
Vermutlich stimmt dann die Reihenfolge nicht.
ICR1 ist erst beschreibbar, wenn ein Mode gesetzt wurde, wo es als
TOP-Wert verwendet wird.
In Mode 0 (nach Reset) übernimmt es bei einer Flanke an ICP1 den Wert
des TCNT1.
Firebird schrieb:> Das wäre natürlich super, diesen Leuchtturm-Effekt ohne delays zu> realisieren. Leider habe ich im Forum und auch im Internet keine> weiterführenden Informationen gefunden wie man das machen könnte.
Such mal nach dem Stichwort "Statemachine"...
So etwas könnte hier hilfreich sein...
Peter D. schrieb:> ICR1 = 255; steht aber immer noch an der falschen Stelle.> Es muß nach Setzen von TCCR1A, TCCR1B stehen.
Danke für den Hinweis. Ich hoffe, dass jetzt alles passt.
TM F. schrieb:> Wenn du schon einen Timer verwendest, dann benutze bitte keine delays.> Dieser blockiert nur.
Ich habe jetzt den Code umgeschrieben und die delays durch die Funktion
delay_milliseconds() mit ATOMIC_BLOCK ersetzt. Der Timer0 ist auf 1ms
eingestellt.
1
voiddelay_milliseconds(int8_tmilliseconds)
2
{
3
ATOMIC_BLOCK(ATOMIC_FORCEON)
4
{
5
current_time=counter1;
6
}
7
target_time=current_time+milliseconds;
8
do
9
{
10
ATOMIC_BLOCK(ATOMIC_FORCEON)
11
{
12
current_time=counter1;
13
}
14
}
15
while(current_time<=target_time);
16
}
Die Software läuft soweit, d.h. visuell. Ich bin mir aber nicht sicher
ob das so stimmt was ich gemacht habe.
Zudem suche ich eine Möglichkeit die Funktion BeaconLeds() unabhängig
von den Tail- und StrobeLeds laufen zu lassen. Sobald ich die Zeiten in
der Funktion BeaconLeds() verlängere (für einen besseren Effekt) werden
die TailLed und StrobeLeds ausgebremmst, d.h. die TailLed leuchtet nicht
mehr und die StrobeLeds blitzen nur einmal statt zweimal.
Firebird schrieb:>> Wenn du schon einen Timer verwendest, dann benutze bitte keine delays.>> Dieser blockiert nur.>> Ich habe jetzt den Code umgeschrieben und die delays durch die Funktion> delay_milliseconds() mit ATOMIC_BLOCK ersetzt. Der Timer0 ist auf 1ms> eingestellt.
Also nur die vordefinierten delays durch selbstgeschriebene ersetzt.
Auch die blockieren und führen also nicht zum Erfolg.
Firebird schrieb:> Ich habe jetzt den Code umgeschrieben und die delays durch die Funktion> delay_milliseconds() mit ATOMIC_BLOCK ersetzt.
und WARUM?
eine blockierende Funktion durch eine andere ersetzt?
Irgendwie ist dir Programmierung nicht blockierend noch nicht klar.
Wenn du Kuchen backst, sitzt du dann die ganze Zeit vor dem Herd oder
merkst dir nur die Uhrzeit wann du ausschalten sollst um sinnvolleres zu
machen als dem Kuchen beim Backen zuzusehen?
Eric B. schrieb:> Also nur die vordefinierten delays durch selbstgeschriebene ersetzt.> Auch die blockieren und führen also nicht zum Erfolg.Joachim B. schrieb:> und WARUM?> eine blockierende Funktion durch eine andere ersetzt?>> Irgendwie ist dir Programmierung nicht blockierend noch nicht klar.
Stimmt, das war mir nicht klar. Unterdessen habe ich viel gelesen und
auch praktisch ausprobiert. Ich denke, ich komme der Sache langsam
näher.
Zuerst habe ich timer2 mit Interrupt 1ms konfiguriert und dazu einen
Timer Compare Match.
TIMSK|=(1<<OCIE2);// Compare Match Interrupt aktivieren
11
}
1
ISR(TIMER2_COMP_vect)
2
{
3
if(timeCount>0)
4
timeCount--;
5
}
Dann habe ich die Funktion BeaconLeds() so angepasst, dass die
Zeitabfrage mit if-Anweisungen, ohne warten erfolgt. Bei den
for-Schleifen mit if-else Anweisungen habe ich meine Kreativität walten
lassen. Vielleicht gibt es bessere Lösungen.
1
voidBeaconLeds(void)
2
{
3
inti=0;
4
5
for(i=255;i>=235;i--)
6
{
7
if(timeCount==0)
8
{
9
OCR1A=i;
10
OCR1B=i;
11
timeCount=5;
12
}
13
else
14
{
15
i++;// Wenn if Bedingung nicht erfüllt ...
16
}// dann Leerlauf i um 1 erhöhen
17
}
18
19
timeCount=80;
20
21
while(timeCount>0)
22
{
23
OCR1A=0;
24
OCR1B=0;
25
}
26
27
for(i=235;i<=255;i++)
28
{
29
if(timeCount==0)
30
{
31
OCR1A=i;
32
OCR1B=i;
33
timeCount=5;
34
}
35
else
36
{
37
i--;// Wenn if Bedingung nicht erfüllt ...
38
}// dann Leerlauf i um 1 reduzieren
39
}
Ich denke, dass ich einen grossen Schritt weiter gekommen bin. Auf Tipps
und Tricks bin ich gespannt ;-)
du hattes mal delay(4) und delay(80)
also würde sich doch anbieten den IRQ auf 4ms zu setzen das gäbe einen
Sprung zu delay(4) und einen 80/4 zu 20
weil 80 und 4 so schön ineinander passen, aber OK 1ms als Timer für
anderes geht auch.
Damit du nicht in den Registern rechnen musst empfehle ich dir mal den
Quellcode von IRMP anzusehen, dort wird einfach gerechnet aus F_CPU und
gewünschte IRQ.
Joachim B. schrieb:> Damit du nicht in den Registern rechnen musst empfehle ich dir mal den> Quellcode von IRMP anzusehen, dort wird einfach gerechnet aus F_CPU und> gewünschte IRQ.
Meinst du das, z.B. für Timer2 ?