Go Down

Topic: Neuling hat ne Frage Projekt Leuchtturm-Karte (Read 5970 times) previous topic - next topic

twoll065

Es funktioniert XD XD XD

Du bist ein Held

Danke

jurs


Es funktioniert XD XD XD

Du bist ein Held

Danke


Bitte, gern geschehen!
In lichten Momenten schreibe ich sowas hin und es funktioniert praktisch auf Anhieb.

Zwei kleine Code-Korrekturen habe ich aber trotzdem noch:

Das  "Serial.begin(9600);" ist natürlich überflüssig in einem Programm, das nichts über Serial ausgibt.
Schadet aber auch nicht weiter.

Gewichtiger ist die leicht falsche Abbruchbedingung, es muss in dieser Zeile ">=" statt "=" heißen,
korrekt wäre:
while (onoffCount>0 && inCycleTime-Turmdata[3+Turmdata[2]-onoffCount]>=0)

Dann wird das Timing auch nicht " ca. +/- zwei Millisekunden " sondern "besser als  +/- eine Millisekunde" eingehalten.
Das habe ich gerade mal mit ein paar Timing-Tests festgestellt.

Wenn ich mich nicht verrechnet habe, dauert es 51660 Sekunden, bis sich ein identischer Blinkzyklus wiederholt, man kann also kaum zweimal pro Tag absolut identische Blinkfolgen beobachten.

Der Quellcode ist so gestaltet, dass sich mehr blinkende Türme in einer größeren Karte leicht auch nachträglich einbauen lassen. Und die "Drehzahl" der loop()-Funktion liegt momentan mit 6 Türmen bei weit über 2000 pro Sekunde, so daß jeder Turmstatus in jeder Millisekunde mehr als zweimal aktualisiert wird, da sind also noch Reserven vorhanden.

Viel Spaß beim Basteln Deiner blinkenden Landkarte!

Udo Klein

Eine andere Variante wäre z.B. so:

Code: [Select]
//
//  www.blinkenlight.net
//
//  Copyright 2013 Udo Klein
//
//  This program is free software: you can redistribute it and/or modify
//  it under the terms of the GNU General Public License as published by
//  the Free Software Foundation, either version 3 of the License, or
//  (at your option) any later version.
//
//  This program is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
//  GNU General Public License for more details.
//
//  You should have received a copy of the GNU General Public License
//  along with this program. If not, see http://www.gnu.org/licenses/

#include <MsTimer2.h>

const uint8_t pins = 6;

template <uint8_t led, uint16_t d1, uint16_t d2, uint16_t d3, uint16_t d4,
                      uint16_t d5, uint16_t d6, uint16_t d7, uint16_t d8>
void light_my_fire() {  
   static uint16_t phase = 0;
   
   phase = phase < d1+d2+d3+d4+d5+d6+d7+d8-1? phase+1: 0;

   digitalWrite(led, phase < d1                  ? HIGH:
                     phase < d1+d2               ? LOW:
                     phase < d1+d2+d3            ? HIGH:
                     phase < d1+d2+d3+d4         ? LOW:
                     phase < d1+d2+d3+d4+d5      ? HIGH:
                     phase < d1+d2+d3+d4+d5+d6   ? LOW:
                     phase < d1+d2+d3+d4+d5+d6+d7? HIGH:
                                                   LOW);                                                  
}

void blink() {
   light_my_fire<0,  200, 2800,  200, 2800,  200, 5800,    0,    0>();
   light_my_fire<1, 3000, 3000, 3000, 3000,    0, 8500,    0,    0>();
   light_my_fire<2,  700, 2300,  700, 2300,  700, 2300,  700, 5300>();
   light_my_fire<3, 6000, 6000,    0,    0,    0,    0,    0,    0>();
   light_my_fire<4, 6000, 3000,    0,    0,    0,    0,    0,    0>();
   light_my_fire<5, 6000, 1000,    0,    0,    0,    0,    0,    0>();


}

void setup() {
   for (uint8_t pin=0; pin<pins; ++pin) {
       pinMode(pin, OUTPUT);
   }

   MsTimer2::set(1, blink);
   MsTimer2::start();
}

void loop() {}


Und wenn gewünscht ist, daß die Leuchtfeuer nicht 100% gleich in der Phase laufen, dann einfach bei der letzten Pause immer 1ms draufhauen. Also so:

Code: [Select]
//
//  www.blinkenlight.net
//
//  Copyright 2013 Udo Klein
//
//  This program is free software: you can redistribute it and/or modify
//  it under the terms of the GNU General Public License as published by
//  the Free Software Foundation, either version 3 of the License, or
//  (at your option) any later version.
//
//  This program is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
//  GNU General Public License for more details.
//
//  You should have received a copy of the GNU General Public License
//  along with this program. If not, see http://www.gnu.org/licenses/

#include <MsTimer2.h>

const uint8_t pins = 6;

template <uint8_t led, uint16_t d1, uint16_t d2, uint16_t d3, uint16_t d4,
                      uint16_t d5, uint16_t d6, uint16_t d7, uint16_t d8>
void light_my_fire() {  
   static uint16_t phase = 0;
   
   phase = phase < d1+d2+d3+d4+d5+d6+d7+d8-1? phase+1: 0;

   digitalWrite(led, phase < d1                  ? HIGH:
                     phase < d1+d2               ? LOW:
                     phase < d1+d2+d3            ? HIGH:
                     phase < d1+d2+d3+d4         ? LOW:
                     phase < d1+d2+d3+d4+d5      ? HIGH:
                     phase < d1+d2+d3+d4+d5+d6   ? LOW:
                     phase < d1+d2+d3+d4+d5+d6+d7? HIGH:
                                                   LOW);                                                  
}

void blink() {
   light_my_fire<0,  200, 2800,  200, 2800,  200, 5801,    0,    0>();
   light_my_fire<1, 3000, 3000, 3000, 3000,    0, 8501,    0,    0>();
   light_my_fire<2,  700, 2300,  700, 2300,  700, 2300,  700, 5301>();
   light_my_fire<3, 6000, 6001,    0,    0,    0,    0,    0,    0>();
   light_my_fire<4, 6000, 3001,    0,    0,    0,    0,    0,    0>();
   light_my_fire<5, 6000, 1001,    0,    0,    0,    0,    0,    0>();


}

void setup() {
   for (uint8_t pin=0; pin<pins; ++pin) {
       pinMode(pin, OUTPUT);
   }

   MsTimer2::set(1, blink);
   MsTimer2::start();
}

void loop() {}
Check out my experiments http://blog.blinkenlight.net

jurs


Eine andere Variante wäre z.B. so:


Das habe ich mir gedacht, dass Dein Programm ganz anders wird als meins.
Und vom Mikrosekunden-Timing her noch viel akkurater als meins, das die Timings nur mit millis() macht.

Sehr schöner Programm-Sketch!

sth77


Sehr schöner Programm-Sketch!

Dem möchte ich nur bedingt zustimmen, ich denke nämlich, dass das so manchen Anfänger überfordern wird. Auf jeden Fall ist er sehr effektiv programmiert und aus meiner Sicht eine sehr gute Leistung. :)
Mein Arduino-Blog: http://www.sth77.de/ - letzte Einträge: Teensy 3.0 - Teensyduino unter Window 7 - Teensyduino unter Windows 8

Udo Klein

So wie ich das sehe ist Meins nicht genauer als Deins. Das Hauptproblem ist wie immer die Genauigkeit des Hardware Taktes. Das Einzige wo Deine Lösung ein bischen daneben haut ist alle 50 Tage beim millis overflow. Ansonsten sehe ich nicht wieso Deine Lösung weniger genau sein sollte. Wieso denkst Du, daß Deine Lösung nicht so genau ist?

Anmerkung: durch das Pollen von "millis" fängst Du Dir zwar Phasenjitter ein, aber den hat meine Lösung auch. Wenn ich den nicht haben wollte müsste ich Timer 0 stoppen. Aber genauer wird es dadurch auch nicht. Nur der Jitter nimmt dann ab.

Hauptunterschied ist der deutlich geringere Speicherverbrauch und die geringere Prozessorlast bei meiner Lösung. Und loop() bleibt frei ;) Aber am Ende zählt immer nur ob die Anforderungen erfüllt sind und da ist Deine Lösung gleich gut. Und sie war schneller verfügbar.


Knobelfrage: warum funktioniert mein Programm überhaupt?

D.h. wo hält es eigentlich den Phasenzustand der Leuchttürme? Betonung auf "mehr als ein Turm" ;)
Check out my experiments http://blog.blinkenlight.net

Udo Klein

@sth77: wieso überfordert das Anfänger? Copy + Paste kann jeder ;) Die Lösung von Jurs ist auch nicht leichter zu verstehen wenn man nicht programmieren kann.
Check out my experiments http://blog.blinkenlight.net

jurs


Dem möchte ich nur bedingt zustimmen, ich denke nämlich, dass das so manchen Anfänger überfordern wird.


Ja, von meinem Programm-Sketch werden Anfänger auf Anhieb vermutlich mehr Codeteile verstehen als von Udos Code.

Aber andererseits ist Copy-and-Paste bei einem fertigen Programm so oder so nicht allzu schwierig.

Das mit den "Templates" gehört beispielsweise so überhaupt nicht zu meinen Programmiertechniken und selbst ich mußte eben erstmal googeln, was Templates bei C++-Code überhaupt sind und was die machen. Also bei Udos Code mußte ich auch erstmal Tante Google bemühen, um den Code überhaupt zu verstehen, was der macht.

Interrupts und Nicht-Standard-Libraries sind auch nicht das allererste Thema für Anfänger, aber wenigstens damit habe ich schon was gemacht und die MsTimer-Library auch schon mal früher gesehen als ich mir Udos DCF-Empfangsfilter angesehen habe.

jurs


Das Einzige wo Deine Lösung ein bischen daneben haut ist alle 50 Tage beim millis overflow.


Ja, wobei man das 50-Tage-Problem mit einer Subtraktions-Arithmetik statt Modulo-Arithmetik und einigen Zusatzvariablen auch in meinem Programm beseitigen könnte und das Programm damit wohl auch noch schneller machen könnte.


Ansonsten sehe ich nicht wieso Deine Lösung weniger genau sein sollte. Wieso denkst Du, daß Deine Lösung nicht so genau ist? Anmerkung: durch das Pollen von "millis" fängst Du Dir zwar Phasenjitter ein, aber den hat meine Lösung auch. Wenn ich den nicht haben wollte müsste ich Timer 0 stoppen. Aber genauer wird es dadurch auch nicht. Nur der Jitter nimmt dann ab.


Ich habe zum Testen mal eine Interrupt-0 Behandlungsroutine für Pin-2 eingeklinkt, in der die High- und Low-Pegel vom micros()-Timing her genau ausgemessen und in der Loop per Serial ausgegeben werden. Bei meinem Programm jittert es, und bei den Timings mit Deinem Programm-Sketch sind keine Differenzen zum Soll-Timing feststellbar.

Quote

Hauptunterschied ist der deutlich geringere Speicherverbrauch und die geringere Prozessorlast bei meiner Lösung. Und loop() bleibt frei ;)


Prozessorlast und freie loop() OK, da gebe ich Dir Recht.

Aber lasse bei meinem Programm mal die nicht benötigte Initialisierung mit "Serial.begin(9600)" im Programm-Sketch weg! Also die kompilierte Programmdatei von meinem Programm ist dann DEUTLICH kleiner als die von Deinem. Mit auskommentierter Serial-Initialisierung hat mein Programm unter Arduino 1.0.1 nur eine angezeigte Binäre Sketchgröße von 1254 Bytes.

Quote

Knobelfrage: warum funktioniert mein Programm überhaupt?

D.h. wo hält es eigentlich den Phasenzustand der Leuchttürme? Betonung auf "mehr als ein Turm" ;)


Der Phasenzustand der Leuchttürme wird doch in Deinem wie auch in meinem Sketch nur im LED-Pin gespeichert und vor dem Setzen des Pins jedesmal zur Laufzeit neu ermittelt: In meinem Sketch in den Zeilen unmittelbar vor dem Setzen des Zustands mit digitalWrite, und bei Deinem Sketch direkt im digitalWrite-Funktionsaufruf per Verzweigungslogik.

@twoll065: Die MsTimer2-Library mußt Du vor dem Kompilieren schon noch herunterladen und im Libraries-Verzeichnis installieren, Udo verwendet nämlich nicht nur erweiterte Programmiertechniken, sondern auch eine externe Nicht-Standard Library in seinem Sketch.

twoll065

Habe ich gemacht

ausgegeben wird:

avrdude: stk500_getsync(): not in sync: resp=0xf0


Was heißt das?

jurs


ausgegeben wird:

avrdude: stk500_getsync(): not in sync: resp=0xf0

Was heißt das?


Manchmal verhaspeln sich Compiler und Uploader, einfach nochmal probieren!
Funktioniert's auch nach mehrmaligen Versuchen nicht?


jurs


Alles neu gestartet aber geht nicht


Merkwürdig.
Nimm in Udos Sketch mal andere Pins für die LEDs als die Hardware-Serial RX/TX Pins an 0 und 1!

Vielleicht ist Udos Programm ja so schnell, dass es schon Ausgaben an 0 und 1 macht, während der Upload noch gar nicht abgeschlossen ist.

Vorschlag: Nimm die Pins 2 bis 7 als LED-Pins statt 0 bis 5!

Statt:
Code: [Select]

light_my_fire<0,  200, 2800,  200, 2800,  200, 5800,    0,    0>();
light_my_fire<1, 3000, 3000, 3000, 3000,    0, 8500,    0,    0>();

Setze
Code: [Select]

light_my_fire<6,  200, 2800,  200, 2800,  200, 5800,    0,    0>();
light_my_fire<7, 3000, 3000, 3000, 3000,    0, 8500,    0,    0>();


Und statt:
Code: [Select]

for (uint8_t pin=0; pin<pins; ++pin) {
        pinMode(pin, OUTPUT);
    }

Setze:
Code: [Select]

for (uint8_t pin=2; pin<pins+2; ++pin) {
        pinMode(pin, OUTPUT);
    }

Addi

Hast du den korrekten Com-Port und das richtige Board ausgwählt, bzw.
überhaupt einen Arduino angeschloßen?

Addi
/ \    _|  _| o
 /--\ (_| (_| |

twoll065

Hab ich gemacht, umgesteckt auf 2-7, Code geändert, 2-5 leuchten normal und 6+7 glimmen nur im Takt.

Go Up