Ich habe das Problem, dass ich ein Programm für mein Arduino geschrieben habe, welches LEDs in einer speziellen Reihenfolge an- und ausschaltet. Doch ich möchte es an jedem beliebigen Punkt des Programms beenden neu starten und wieder zur if abfrage am anfang kommen. Kennt ihr irgent eine Programmirbare methode das zu schaffen?
Alter D. schrieb: > Kennt ihr irgent > eine Programmirbare methode das zu schaffen? Hmm... Auch wenn du es noch nicht weißt... Ich glaube, du möchtest einen einfachen endliche Automaten bauen. Eine Ablaufsteuerung. Übrigens: Ich sehe keine if Abfrage.
Hi Scheint sauber zu sein: https://virusscan.jotti.org/de-DE/filescanjob/rycbmzdrk4 https://www.virustotal.com/de/file/437ed5184be3102574e466598066d605753fffd90bc68e950c759cf9d6c54675/analysis/1509312607/ http://online4.drweb.com/cache/?i=4edd474dcbdfb14e804745d5681b8c63 MfG
:
Bearbeitet durch User
Wenn ich die Reset-taste nutze kann ich nicht mit dem gleichen Taster (extern) das programm starten.
Alter D. schrieb: > Wenn ich die Reset-taste nutze kann ich nicht mit dem gleichen Taster > (extern) das programm starten. Es ist jetzt an der Zeit, das Programm zu zeigen.
Hi Alter D. schrieb: > enn ich die Reset-taste nutze kann ich nicht mit dem gleichen Taster > (extern) das programm starten. Jain - man muß die Taste auch wieder los lassen. Denke, der Ansatz war eher ironisch gemeint, wenn die Funktion aber auch zu 100% gegeben ist. MfG
>einen einfachen endliche Automaten bauen Du benutzt niemals das delay(). Stattdessen hast eine Hauptschleife, die andauernd kontrolliert, ob irgend etwas gemacht werden muss. In deinem Fall kontrolliert die Hauptschleife 2 Dinge. 1) Sie kontrolliert ob die Taste gedrückt ist. 2) Mit millis() kontrolliert die Hauptschleife, ob die LEDs an/ausschaltet werden müssen. Dazu schreibst du am einfachsten einen endlichen Automaten. In die Automaten-Theorie einarbeiten lohnt sich sowieso. Das braucht man für alles mögliche immer wieder.
Patrick J. schrieb: > Denke, der Ansatz war eher ironisch gemeint, wenn die Funktion aber auch > zu 100% gegeben ist. Durchaus nicht. Er wollte Alter D. schrieb: > ich möchte es an jedem beliebigen Punkt des Programms beenden neu > starten und wieder zur if abfrage am anfang kommen. Genau das passiert doch mit Reset. Wenn die Funktion eine andere sein soll, dann muss er näher beschreiben, was unter welchen Bedingungen passieren soll, speziell die genannte IF-Abfrage. Das Programm zu kennen, wäre hilfreich.
> Wenn ich die Reset-taste nutze kann ich nicht mit dem gleichen Taster > (extern) das programm starten. Nimm einen Druckschalter am Reset-Eingang. 1x Drücken = Dauer-Reset nochmal Drücken = Programm läuft wieder
Beitrag #5191382 wurde von einem Moderator gelöscht.
Alter D. schrieb: > welches LEDs in einer speziellen Reihenfolge an- und ausschaltet. Meinst Du sowas: Beitrag "AVR Sleep Mode / Knight Rider"
> Nimm einen Druckschalter am Reset-Eingang.
Was gebt ihr denn hier für Tipps?
Zeitgesteuerte Aufgaben erledigen und zusätzlich Eingaben abarbeiten -
das hat man in nahezu jedem Mikrocontroller Programm.
Wer MCs programmieren will, muss sowieso lernen, wie man Ablaufsteuerung
und Eingabeverarbeitung "gleichzeitig" macht.
HildeK schrieb: > Da brauchst du nichts programmieren: nimm die Reset-Taste! Ich weis nicht wie rum du gestrickt bist, aber für ne Frau bist du ganz schön taff! Oder hast du am Ende nur den Namen von deiner Frau ausgeliehen, weil dein Vorname nichts hergibt wie z.B. Sepperl oder Hanserl ;-)
il Conte schrieb: > Ich weis nicht wie rum du gestrickt bist, > aber für ne Frau bist du ganz schön taff! Was willst du Flitzpiepe denn? Kleiner Rotzlöffel, der sich hier als Ober-Macho aufspielen will? il Conte schrieb: > Oder hast du am Ende nur den Namen von deiner Frau ausgeliehen, > weil dein Vorname nichts hergibt wie z.B. Sepperl oder Hanserl ;-) Und wie nennt man dich im richtigen Leben, daß du dich hier als italienische Adliger aufspielen musst: Dummbold, Froschauge...
die if abfrage startet das programm. ich habe es zwar schon mit dem switch befehl versucht aber anscheinend verstehe ich den befehl nicht ganz den es hat nicht funktionirt. int ledPin1 = 1; int ledPin2 = 2; int ledPin3 = 3; int ledPin4 = 4; int tasterPin = 0; int zeit = 750; void setup() { pinMode(ledPin1,OUTPUT); pinMode(ledPin2,OUTPUT); pinMode(ledPin3,OUTPUT); pinMode(ledPin4,OUTPUT); pinMode(tasterPin,INPUT); } void loop() { case 0; if (digitalRead(tasterPin)==HIGH){ while( digitalWrite(ledPin2, HIGH); delay(zeit); if (digitalRead(tasterPin)==HIGH) switch (2); digitalWrite(ledPin3, HIGH); if (digitalRead(tasterPin)==HIGH) switch (2); digitalWrite(ledPin4, HIGH); if (digitalRead(tasterPin)==HIGH) switch (2); delay(zeit); if (digitalRead(tasterPin)==HIGH) switch (2); digitalWrite(ledPin1, HIGH); if (digitalRead(tasterPin)==HIGH) switch (2); digitalWrite(ledPin3, LOW); if (digitalRead(tasterPin)==HIGH) switch (2); delay(zeit); if (digitalRead(tasterPin)==HIGH) switch (2); digitalWrite(ledPin3, HIGH); if (digitalRead(tasterPin)==HIGH) switch (2); digitalWrite(ledPin2, LOW); if (digitalRead(tasterPin)==HIGH) switch (2); delay(zeit); if (digitalRead(tasterPin)==HIGH) switch (2); digitalWrite(ledPin2, HIGH); if (digitalRead(tasterPin)==HIGH) switch (2); digitalWrite(ledPin4, LOW); if (digitalRead(tasterPin)==HIGH) switch (2); delay(zeit); if (digitalRead(tasterPin)==HIGH) switch (2); digitalWrite(ledPin4, HIGH); if (digitalRead(tasterPin)==HIGH) switch (2); digitalWrite(ledPin1, LOW); if (digitalRead(tasterPin)==HIGH) switch (2); delay(zeit); if (digitalRead(tasterPin)==HIGH) switch (2); digitalWrite(ledPin1, HIGH); if (digitalRead(tasterPin)==HIGH) switch (2); digitalWrite(ledPin3, LOW); if (digitalRead(tasterPin)==HIGH) switch (2); delay(zeit); if (digitalRead(tasterPin)==HIGH) switch (2); digitalWrite(ledPin3, HIGH); if (digitalRead(tasterPin)==HIGH) switch (2); digitalWrite(ledPin2, LOW); if (digitalRead(tasterPin)==HIGH) switch (2); delay(zeit); if (digitalRead(tasterPin)==HIGH) switch (2); digitalWrite(ledPin2, HIGH); if (digitalRead(tasterPin)==HIGH) switch (2); digitalWrite(ledPin4, LOW); if (digitalRead(tasterPin)==HIGH) switch (2); delay(zeit); if (digitalRead(tasterPin)==HIGH) switch (2); digitalWrite(ledPin4, HIGH); if (digitalRead(tasterPin)==HIGH) switch (2); digitalWrite(ledPin1, LOW); if (digitalRead(tasterPin)==HIGH) switch (2); ); break; case 2; while( digitalWrite(ledPin1, LOW); digitalWrite(ledPin2, LOW); digitalWrite(ledPin3, LOW); digitalWrite(ledPin4, LOW); if (digitalRead(tasterPin)==HIGH){ switch (val); } } }
Ja, du hast den switch/case Befehl völlig sinnlos verwendet. Schau nochmal in ein C Tutorial.
il Conte schrieb: > HildeK schrieb: >> Da brauchst du nichts programmieren: nimm die Reset-Taste! > > Ich weis nicht wie rum du gestrickt bist, > aber für ne Frau bist du ganz schön taff! Dein Nick ist weder schlechter noch besser als meiner. Welches Geschlecht du daraus ableiten willst, ist deine Sache. Ich habe auf die genannten Anforderungen die einfachst mögliche Antwort gegeben. > Oder hast du am Ende nur den Namen von deiner Frau ausgeliehen, > weil dein Vorname nichts hergibt wie z.B. Sepperl oder Hanserl ;-) Ich habe mir gar nichts ausgeliehen, den habe ich mal zugeteilt bekommen. Dieser Nick war mein erster Benutzername auf einer UNIX Workstation. Ich hab trotzdem nicht verstanden, was du für ein Problem mit mir hast und was mein Nickname mit meinen Aussagen zu tun hat.
Oh! Da hast du 2 Probleme. Zum einen, wie Stefan bereits sagte, das switch funktioniert anders. Zum andern musst du deinen Taster 750 Millisekunden lang drücken, bis dein Programm endlich reagiert. Und dann diese Kopien der Tastaturabfrage ... wenn du mal mehr programmiert hast, empfindest du so etwas als unerträglich hässlich. Und vor allem zu unübersichtlich. Auch wenn es am Anfang einfacher wirkt, als die kompakten Beispiele. Eigentlich braucht man so etwas: https://playground.arduino.cc/Learning/BlinkWithoutDelayDe Wird bei dir aber etwas komplizierter, das "boolean value" reicht für deine LEDs nicht aus. (Den Tipp von Peter Dannengger solltest du auf nächstes Jahr verschieben. Zusätzlich noch um den Power-Down-Mode kümmern? Das ist etwas zu viel auf einmal.)
Noch einer schrieb: > (Den Tipp von Peter Dannengger solltest du auf nächstes Jahr > verschieben. Zusätzlich noch um den Power-Down-Mode kümmern? Das ist > etwas zu viel auf einmal.) Falls man den Text im Link auch mal liest, wird einem ein Seifensieder aufgehen, daß man zuerst die Funktion implementiert und danach bei Bedarf das Sleep. Die erste Codevariante "Without_Sleep.zip" enthält also die Funktion ohne Sleep.
ich wollte doch blos das sprogramm an jedem punkt des brogramms mit dem tasster mit dem ich das programm auch starte unterbrechen und wieder zur if abfrage kommen und den knopf noch mal zu drücken und den loop wieder zu starten. (ICH BIN ANFÄNGER.)
Hi State-Maschine Wenn Status = 0 UND Knopf gedrückt -> Status = 1 Wenn Status = 1 UND Knopf nicht gedrückt -> Status = 2 Wenn Status = 2 UND Knopf gedrückt -> Status = 3 Wenn Status = 3 UND Knopf nicht gedrückt -> Status = 0 Wenn Status=0 PAUSE Wenn Status=2 LAUFEN 1 und 3 warten nur auf das Lösen des Taster MfG
Der Punkt, ein Taster kann das Programm nicht ohne weiteres Unterbrechen. Jedenfalls nicht, um es direkt danach wieder fortzusetzen. Anders herum muss das Programm den Taster abfragen und sich selbst ggf. beenden. Aber was heißt beenden? Welchen Code soll der Mikrocontroller nach dem Beenden ausführen? Wenn du ihn wirklich anhalten willst, musst du in die Programmierung der Power-Management Funktionen einsteigen. Wenn du das Programm auf Tastendruck wirklich unterbrechen willst, musst du dich mit Interrupts beschäftigen. Ich kann Dir aber jetzt schon verraten, dass die Kombination aus Interrupts und Taster tückisch ist. Das kriegst du ohne Interrupts sicher schneller und zuverlässiger hin. Die bisherigen Hinweise zum Zustandsautomaten führen in die richtige Richtung. Wenn du das drauf hast, kannst du noch viel komplexere Sachen bis hin zum Multitasking machen. Das ist didaktisch betrachtet der richtige weg. Schau Dir mein Buch an (http://stefanfrings.de/mikrocontroller_buch/index.html) oder den Assembler Workshop (http://stefanfrings.de/avr_workshop/index.html), da werden die Sachen thematisiert, die du brauchst. Wenn Dir das momentan zu mühsam ist, dann mach es mit einem Druckschalter am Reset Pin. Dazu musst du gar nichts weiter programmieren.
Beitrag #5192217 wurde vom Autor gelöscht.
Einen Taster in einem Interrupt, womit man dann an den Programmanfang springt, ist kein Hexenwerk. Den braucht man nicht mal entprellen.
> Einen Taster in einem Interrupt, womit man dann an den > Programmanfang springt, ist kein Hexenwerk. Dann mach das mal in C, ohne den Stack durcheinander zu bringen. Und ohne Reset natürlich, denn diesen zu vermeiden, darum ging es ja gerade. Und um den Schwierigkeitsgrad noch ein bisschen zu erhöhen: Es geht um Arduino, also C++ mit Objekten und intensiver Heap Nutzung. Fängt schon bei der String Klasse an. Das ist wirklich nichts für Anfänger.
Prinzipiell kann man einen Programmteil mit setjmp() and longjmp() geordnet abwürgen. Erfahrene Programmierer machen allerdings einen großen Bogen darum und bevorzugen die Rückkehr zur Mainloop nach jedem Schritt. Inbesondere beim Lauflicht geht das sehr einfach, da man den Index der LED-Muster ganz einfach hochzählen kann. Das macht nicht nur den Code einfach, sondern erlaubt auch die einfache Änderung und Hinzufügen von Mustern.
Peter D. schrieb: > Inbesondere beim Lauflicht geht das sehr einfach, da man den Index der > LED-Muster ganz einfach hochzählen kann. Das macht nicht nur den Code > einfach, sondern erlaubt auch die einfache Änderung und Hinzufügen von > Mustern. So ist es! Hier mal eine Variante, grob aus Fragmenten meiner Wühlkiste zusammengestoppelt. Da ist sicherlich noch ein erhebliches Optimierungspotential vorhanden. Aber hier wohl nicht nötig. Zumindest: Es tut, was es soll. Wenn Taster gedrückt, macht es ein Lauflicht. Taster losgelassen, Lauflicht sofort aus. Intern bestehend aus drei miteinander verschränkten einfachen endlichen Automaten. 1: Ein einfacher Timer (wird mehrfach verwendet) 2. Tasten entprellen 3. Lauflicht Die Pins habe ich anders zugeordnet. Denn Pin 0 und 1 sind bei mir von der Seriellen belegt.
1 | /*
|
2 | * Verwendung findet ein Arduino UNO
|
3 | * Also ein ATMega328P
|
4 | *
|
5 | * Der Taster zwischen Pin 3 und GND
|
6 | * interner Pullup aktiviert
|
7 | *
|
8 | * Die LED sind an den AnalogPins angeschlossen.
|
9 | * A0 bis A3
|
10 | *
|
11 | * Der Zugriff erfolgt über die Portregister
|
12 | * Hier: PORTC, DDRC
|
13 | *
|
14 | */
|
15 | |
16 | class SimpleTimer |
17 | {
|
18 | private:
|
19 | unsigned long timeStamp = 0; |
20 | bool abgelaufenStatus = true; |
21 | |
22 | public:
|
23 | void start() |
24 | {
|
25 | timeStamp = millis(); |
26 | abgelaufenStatus = false; |
27 | }
|
28 | |
29 | void stop() |
30 | {
|
31 | abgelaufenStatus = true; |
32 | }
|
33 | |
34 | bool operator() (const unsigned long ablaufZeit) |
35 | {
|
36 | return abgelaufenStatus?true:abgelaufenStatus=millis()-timeStamp>ablaufZeit; |
37 | }
|
38 | };
|
39 | |
40 | class Taster |
41 | {
|
42 | private:
|
43 | const byte pin; |
44 | const unsigned long entprellzeit; |
45 | const bool invers; |
46 | SimpleTimer timer; |
47 | bool status = false; |
48 | |
49 | public:
|
50 | Taster(byte pin,unsigned long entprellzeit,bool invers = false): |
51 | pin(pin),entprellzeit(entprellzeit),invers(invers) {} |
52 | |
53 | void init() |
54 | {
|
55 | pinMode(pin,invers?INPUT_PULLUP:INPUT); |
56 | }
|
57 | |
58 | bool operator () () |
59 | {
|
60 | bool druck = invers?!digitalRead(pin):digitalRead(pin); |
61 | if(druck == status) timer.start(); |
62 | if(druck != status && timer(entprellzeit)) |
63 | {
|
64 | timer.start(); |
65 | status = druck; |
66 | }
|
67 | return status; |
68 | }
|
69 | };
|
70 | |
71 | |
72 | const byte tasterPin = 3; |
73 | const unsigned long enprellzeit = 50; |
74 | |
75 | |
76 | const unsigned long zeit = 750; |
77 | const byte maske = 0b1111; |
78 | const byte muster[] = { |
79 | 0b0001, |
80 | 0b0010, |
81 | 0b0100, |
82 | 0b1000, |
83 | 0b0100, |
84 | 0b0010, |
85 | };
|
86 | |
87 | |
88 | void leuchtdingen(bool anforderung); |
89 | |
90 | Taster taster(tasterPin,enprellzeit,true); |
91 | |
92 | void setup() |
93 | {
|
94 | PORTC &= ~maske; // led aus |
95 | DDRC |= maske; // Output |
96 | pinMode(LED_BUILTIN,OUTPUT); |
97 | taster.init(); |
98 | }
|
99 | |
100 | void loop() |
101 | {
|
102 | leuchtdingen(taster()); |
103 | }
|
104 | |
105 | |
106 | |
107 | void leuchtdingen(bool anforderung) |
108 | {
|
109 | static SimpleTimer timer; |
110 | static byte index = 0; |
111 | |
112 | if(!anforderung) |
113 | {
|
114 | index = 0; |
115 | PORTC &= ~maske; |
116 | timer.stop(); |
117 | return; |
118 | }
|
119 | |
120 | if(timer(zeit)) |
121 | {
|
122 | PORTC = (PORTC & ~maske) | muster[index]; |
123 | digitalWrite(LED_BUILTIN,!digitalRead(LED_BUILTIN)); |
124 | timer.start(); |
125 | if(++index>=sizeof(muster)) index = 0; |
126 | }
|
127 | }
|
> Erfahrene Programmierer machen allerdings einen großen Bogen darum und > bevorzugen die Rückkehr zur Mainloop nach jedem Schritt. Etwas deutlicher formulieren? Mikrocontroller-programme legt man grundsätzlich immer so an. Die Mainloop ruft reihum Funktionen auf, die nur einen einzigen Schritt ausführen und sofort wieder zur Mainloop zurückkehren. Wenn man eine Funktion mitten drinnen abbrechen will, ist das Programm falsch angelegt.
Stefan U. schrieb: >> Einen Taster in einem Interrupt, womit man dann an den >> Programmanfang springt, ist kein Hexenwerk. > > Dann mach das mal in C, ohne den Stack durcheinander zu bringen. Weiß ich nicht. In Assembler einfach vor die Initialisierung springen. Da ist dann alles wieder frisch und neu.
Hier mal ein Programmiervorschlag. Hab das aber nicht getestet, nur mal so eingetippt. Tatsächlich sind das zwei Zustandsautomaten. Der äußere Automat zur Abfrage der Taste und der Start/Stopp-Steuerung. Der innere Automat entspricht hoffentlich dem, was gewollt wurde. Kann man aber entsprechend verändern.
1 | void loop () |
2 | {
|
3 | startStoppAuswahl(); |
4 | }
|
5 | void startStoppAuswahl () |
6 | {
|
7 | static tasterStatus = 0; // initialier Zustand, Programm läuft |
8 | static tasterWarteZeit = 5; // Wartezeit wg. Entprellung |
9 | switch(tasterStatus) |
10 | {
|
11 | case 0: // Programm läuft, abfragen auf Unterbrechung |
12 | if (digitalRead(tasterPin)==HIGH) |
13 | {
|
14 | programmStopp(); |
15 | delay(tasterWarteZeit); |
16 | tasterStatus = 1; |
17 | }
|
18 | else
|
19 | {
|
20 | programmSchritt(); |
21 | }
|
22 | break; |
23 | |
24 | case 1: // Programm gestoppt, Taste muss losgelassen werden |
25 | if (digitalRead(tasterPin)==LOW) |
26 | {
|
27 | delay(tasterWarteZeit); |
28 | tasterStatus = 2; |
29 | }
|
30 | break; |
31 | |
32 | case 2: // Programm gestoppt, Taste zum Weiterlaufen gedrückt |
33 | if (digitalRead(tasterPin)==HIGH) |
34 | {
|
35 | delay(tasterWarteZeit); |
36 | tasterStatus = 3; |
37 | }
|
38 | break; |
39 | |
40 | case 3: // Programm vor dem weiterlaufen, Taste muss losgelassen werden |
41 | if (digitalRead(tasterPin)==LOW) |
42 | {
|
43 | delay(tasterWarteZeit); |
44 | tasterStatus = 0; |
45 | }
|
46 | break; |
47 | }
|
48 | }
|
49 | |
50 | void programmStopp () |
51 | { // es müssen nur die LED abgeschaltet werden |
52 | digitalWrite(ledPin1, LOW); |
53 | digitalWrite(ledPin2, LOW); |
54 | digitalWrite(ledPin3, LOW); |
55 | digitalWrite(ledPin4, LOW); |
56 | }
|
57 | |
58 | void programmSchritt () |
59 | { // globale Variabel, aber von außen nicht "sichtbar" |
60 | static int schritt = 0; |
61 | // einen Schritt weiter setzen
|
62 | schritt++; |
63 | // der erste Schritt ist immer die Nr. 1
|
64 | // am Ende der Schrittfolge, wird er wieder zurückgesetzt
|
65 | switch (schritt) |
66 | {
|
67 | case 1: digitalWrite(ledPin2, HIGH); break; |
68 | case 2: delay(zeit); break; |
69 | case 3: digitalWrite(ledPin3, HIGH); break; |
70 | case 4: digitalWrite(ledPin4, HIGH); break; |
71 | case 5: delay(zeit); break; |
72 | case 6: digitalWrite(ledPin1, HIGH); break; |
73 | case 7: digitalWrite(ledPin3, LOW); break; |
74 | case 8: delay(zeit); break; |
75 | case 9: digitalWrite(ledPin3, HIGH); break; |
76 | case 10: digitalWrite(ledPin2, LOW); break; |
77 | case 11: delay(zeit); break; |
78 | case 12: digitalWrite(ledPin2, HIGH); break; |
79 | case 13: digitalWrite(ledPin4, LOW); break; |
80 | case 14: delay(zeit); break; |
81 | case 15: digitalWrite(ledPin4, HIGH); break; |
82 | case 16: digitalWrite(ledPin1, LOW); break; |
83 | case 17: delay(zeit); break; |
84 | case 18: digitalWrite(ledPin1, HIGH); break; |
85 | case 19: digitalWrite(ledPin3, LOW); break; |
86 | case 20: delay(zeit); break; |
87 | case 21: digitalWrite(ledPin3, HIGH); break; |
88 | case 22: digitalWrite(ledPin2, LOW); break; |
89 | case 23: delay(zeit); break; |
90 | case 24: digitalWrite(ledPin2, HIGH); break; |
91 | case 25: digitalWrite(ledPin4, LOW); break; |
92 | case 26: delay(zeit); break; |
93 | case 27: digitalWrite(ledPin4, HIGH); break; |
94 | case 28: digitalWrite(ledPin1, LOW); |
95 | // schritt wird auf 0 gesetzt, weil beim Start
|
96 | // der Prozedure immer um 1 erhöht wird.
|
97 | schritt=0; |
98 | break; |
99 | }
|
100 | }
|
:
Bearbeitet durch User
... schrieb: > il Conte schrieb: > Ich weis nicht wie rum du gestrickt bist, > aber für ne Frau bist du ganz schön taff! > > Was willst du Flitzpiepe denn? Kleiner Rotzlöffel, der sich hier als > Ober-Macho aufspielen will? > > il Conte schrieb: > Oder hast du am Ende nur den Namen von deiner Frau ausgeliehen, > weil dein Vorname nichts hergibt wie z.B. Sepperl oder Hanserl ;-) > > Und wie nennt man dich im richtigen Leben, daß du dich hier als > italienische Adliger aufspielen musst: Dummbold, Froschauge... So schwafelt nur ein Mann mit Fakeaccount!!
:
Bearbeitet durch User
Rolf H. schrieb: > Der innere Automat entspricht hoffentlich dem, was gewollt wurde. Habe ich jetzt nicht getestet... Sieht recht plausibel aus... Aber da sind delay() drin. Und genau die wollten/sollten wir doch weg lassen. Bei dir stören die Delay die Tastenauswertung. Die Alternative, um während des Delay noch Tasten auswerten zu können, wäre diese Auswertung in yield() zu machen. ------ michael_ schrieb: > In Assembler einfach vor die Initialisierung springen. Da sind wir aber nicht... Wir sind in C++. Und in dessen Geltungsbereich gibts kein Lable vor der Initialisierung.
Arduino F. schrieb: > Aber da sind delay() drin. > Und genau die wollten/sollten wir doch weg lassen. Jain, das delay ist auch im Originalcode schon drin. Kann man anders machen, aber das ist dann eine andere Sache. Wenn während der delay-Wertezeit auch eine Testenauswertung erfolgen soll, muss die Warte-Zeit natürlich entsprechend umgeschrieben werden. Die Funktion "programmSchritt" könnte z.B. false liefern, falls die Taste (1x) gedrückt wurde. Das würde im umgebenden Automaten abgeprüft und ein entsprechender Tastenzustand eingestellt werden.
> das delay ist auch im Originalcode schon drin Wahrscheinlich liegt genau hier das zentrale Problem aller Arduino Programmierer. Das Arduino Tutorial beginnt mit LED blinken mit delay(). Sieht auf den ersten Blick einfach aus, hat aber verheerende Auswirkungen. Wer das Arduino-Tutorial durchgearbeitet hat, will das Beispiel mit delay() erweitern und stösst auf alle Arten unlösbarer Probleme. Wer das AVR-Tutorial durcharbeitet, steht anfangs vor einer riesigen Hürde. Er muss zunächst Timerinterrups verstehen, bevor er überhaupt ein einfaches Blinkprogramm schreiben kann. Dafür werden danach alle Erweiterungen einfach. Wir sollten ein neues Arduino-Tutorial schreiben. Eines, das mit millis() statt mit delay() beginnt.
Noch einer schrieb: > Wahrscheinlich liegt genau hier das zentrale Problem aller Arduino > Programmierer. Ach, das kannste so nicht sagen... Ok, sagen schon, aber wie alle Verallgemeinerungen, ist auch diese falsch. Auf dem Weg vom totalen Anfänger, bis zum Genie, gilt es tausende von Hürden zu überwinden. Delay ist nur eine davon. Delay kann man erst vermeiden, wenn man in Nebenläufigkeiten denken und auch so Programmieren lernt. Ich behaupte, das muss mit einer Umstrukturierung des Gehirns einhergehen. Gleiches gilt für Rekursionen, Bäume, usw. Es ist ein Prozess, welcher Jahre in Anspruch nimmt. Vielleicht gibts auch eine Art Programmierer Gen.... Menschen mit diesem Gen fällt es leicht. Menschen ohne das Gen tun sich schwer. Werden vielleicht gute Fleiß Programmierer, aber die wirklich genialen Lösungen bleiben ihnen eher verborgen.
> Delay kann man erst vermeiden, wenn man in Nebenläufigkeiten denken > und auch so Programmieren lernt. Hmmm... die Qt ist da schon recht weit. Als Anwendungsprogrammierer denkst du nicht in Nebenläufigkeiten. Du denkst in Signalen und Slots. Alle 750ms soll ein Signal die LEDs weiter zählen und bei einem Tastendruck soll ein Signal den Zähler zurücksetzen. Mit den 32bit MCs wäre ein Konzept vorstellbar; so einfach wie die Arduino-Library, bei dem aber Nebenläufigkeiten einfach so funktionieren, ohne dass man darüber nachdenken muss.
Bei Qt darfst du genau wie bei Zustandsautomaten weder Endlosschleifen noch Delays verwenden. Dann friert die GUI ein. Auch Qt nimmt Dir nicht die Arbeit ab, lange laufende Prozesse in Tasks zu zerlegen und dann schrittweise einen nach dem anderen abzuarbeiten. Das mit den Signalen und Slots ist nur dann einfach, wenn du überhaupt Signale hast die 1:1 am Stück abgearbeitet werden sollen. 1 Signal = 1 Reaktion. Was bei GUIs natürlich der Normalfall ist. Aber lass doch mal zwei LEDs den Rhytmus von zwei unterschieldlichen Liedern abspielen/anzeigen. Dabei helfen Dir Signale und Slots wenig. Ich will Qt nicht schlecht reden. Nur halte ich Zustandsautomaten didaktisch für wichtiger. Die sollte man zuerst lernen, danach kommt man mit dem Signal/Slot Modell von Qt auch gut klar. Aber dann eher auf 'nem PC, statt auf µC.
Für alle Freunde der Quasi-Nebenläufigkeit, hier eine Zusatzfunktion:
1 | unsigned long timeDelay (int delay, unsigned long limit) |
2 | {
|
3 | unsigned long now = millis(); |
4 | if (limit == 0L) |
5 | {
|
6 | return now+delay; |
7 | }
|
8 | else
|
9 | {
|
10 | if (limit < now) |
11 | {
|
12 | return 0L; |
13 | }
|
14 | else
|
15 | {
|
16 | return limit; |
17 | }
|
18 | }
|
19 | }
|
... und in der Deklaration der Funktion programmSchritt:
1 | static unsigned long nextTime = 0; |
... und dann die Funktion delay ersetzten durch:
1 | if ((nextTime = timeDelay (zeit, nextTime)) != 0) {schritt--;} |
Damit (schritt--) wird das Weiterschalten verhindert, wenn das Delay noch nicht verbraucht ist. Laut Doku sollte das 50 Tage so funktionieren.
>Nur halte ich Zustandsautomaten didaktisch für wichtiger. Da stimme ich dir voll und ganz zu. Das erste Beispiel eines Arduino Tutorials, LED blinken, sollte aus millis() und einen trivialen Zustandsautomaten bestehen. Das zweite Beispiel ersetzt die boolean durch einen echten Zustandsautomaten. Das dritte Beispiel hat dann einen Zustandsautomaten, der Timer und Taster koordiniert. Ganz andere Geschichte - Die Arduino Library 1:1 auf 32bit MCs übertragen? Besser erst mal überlegen, ob man den Low-Level loop() durch irgend etwas ersetzen kann, bei dem man nicht über die Low-Level Probleme der Nebenläufigkeit nachdenken muss.
Noch einer schrieb: >>Nur halte ich Zustandsautomaten didaktisch für wichtiger. > > Da stimme ich dir voll und ganz zu. Das würde ich nicht unterschreiben. Ich habe schon Professoren erlebt, die bei einer Problembeschreibung durch Zustandsautomaten schier verzweifelt sind. Zustandsautomaten sind ein schönes mathematisches Konzept, aber nicht zum Programmieren geeignet. Besser ist es, erst mal die Bedingungen aufzuschreiben und dann Schritt für Schritt die Lösung in einen Zustandsautomaten zu überführen. Möglichst mit Unterstützung von Verifikations-Werkzeugen. Meine 2 cent.
@Stefan Us (stefanus) >Ich will Qt nicht schlecht reden. Nur halte ich Zustandsautomaten >didaktisch für wichtiger. Die sollte man zuerst lernen, danach kommt man >mit dem Signal/Slot Modell von Qt auch gut klar. Stimmt! Denn Grundlagen sind durch NICHTS zu ersetzen! >Aber dann eher auf 'nem >PC, statt auf µC. Naja, die Grenzen sind heute fließend. Was ist ein Raspberry Pi? PC oder noch uC? Embedded-PC?
@Rolf Hänisch (b0d0) >Das würde ich nicht unterschreiben. Ich habe schon Professoren erlebt, >die bei einer Problembeschreibung durch Zustandsautomaten schier >verzweifelt sind. Dann sind sie inkompetent. > Zustandsautomaten sind ein schönes mathematisches >Konzept, aber nicht zum Programmieren geeignet. Unsinn. Wenn man sie praxisgerecht anwendet, sind die eher einfach und sehr pragmatisch. >Besser ist es, erst mal die Bedingungen aufzuschreiben und dann Schritt >für Schritt die Lösung in einen Zustandsautomaten zu überführen. >Möglichst mit Unterstützung von Verifikations-Werkzeugen. Jaja, und immer schön blinken wenn man auf Klo geht.
Hi Vom delay() auf inkompetente Professoren zu kommen, schafft man auch nicht in jedem Forum :) MfG
> Besser ist es, erst mal die Bedingungen aufzuschreiben und dann Schritt > für Schritt die Lösung in einen Zustandsautomaten zu überführen. Ja sicher, das gehört selbstverständlich dazu, einen Zustandsautomaten zu implementieren. Es geht ja darum, für jede Aktion die zugehörige Bedingung zu definieren. Der Rest ist dann nur noch stumpf, die Worte in C zu übersetzen.
Rolf H. schrieb: > Laut Doku sollte das 50 Tage so funktionieren. Fast 50 Tage... Und dann versagt es. In der PC Welt mag es unüblich sein, dass Programme 50 Tage durchlaufen. In der µC Welt laufen Programme teilweise viel länger. Der Knackpunkt liegt hier: > now+delay; Das produziert, zum Ende hin, einen weiteren Überlauf und damit schlägt die nächste Abfrage dann fehl. Du hast also hier einen Code publiziert, in welchem das Versagen eingebaut ist. Vielleicht solltest du diesen nochmal lesen.... https://playground.arduino.cc/Learning/BlinkWithoutDelayDe -------------------- Falk B. schrieb: > Naja, die Grenzen sind heute fließend. Was ist ein Raspberry Pi? PC oder > noch uC? Embedded-PC? Da es ein Betriebssystem hat und eine grafische Oberfläche (zumindest meistens) kommt es einem PC näher als einem µC. Auch die Anschlüsse ... Nunja, auch hat ein RPI ein mehrfaches an RechenPower, Speicher usw als mein erster PC. Aus meiner Sicht ist die Sache recht klar: Der RPI ist ein mini PC. Zumindest, als ein solcher nutzbar. Ein paar Dinge, wie zugänglicher SPI, I2C, GPIOs machen es zum Zwitter. Ja, die Grenze ist fließend. Endlos viele Systeme haben ein Linux onBoard, z.B. nahezu alle DSL Router. Auf Grund der Spezialisierung, würde ich solche Systeme nicht als mini PC bezeichnen. Es ist also eher der Einsatzzweck, anhand dessen die Frage beantwortet werden muss.
Arduino F. schrieb: > Rolf H. schrieb: >> Laut Doku sollte das 50 Tage so funktionieren. > Fast 50 Tage... > Und dann versagt es. Ich nehme mal zur Kenntnis, dass in diesem Forum manchmal ein etwas rauher Ton herrscht. Allerdings gebe ich zu bedenken, dass der Hinweis, "das Programm läuft nur endliche Zeit" genau vor dem Versagen im Dauerbetrieb warnt. Jeder mag daraus die Schlüsse ziehen, die im am Herzen liegen.
Dabei ist es so einfach, es richtig zu machen. So misst man die Ausführungszeit von einer Aktion:
1 | start=millis(); |
2 | doSomething(); |
3 | elapsed=millis()-start; |
So verzögert man das Programm um 1000 Millisekunden:
1 | start=millis(); |
2 | while (millis()-start<1000) {}; |
Der Trick besteht in der Subtraktion. Die liefert auch nach einem Timerüberlauf das richtige Ergebnis.
Stefan U. schrieb: > Dabei ist es so einfach, es richtig zu machen. Danke für den Hinweis! Bekanntlich sagt man: "Das Bessere ist des Guten Feind". Anzumerken ist noch, dass meine Variante auch nach kurzer Zeit einen Fehler (beim Überlauf während des Delays) haben kann, wenn die Funktion sieben Wochen nach dem Systemstart aufgerufen wird. Der Effekt ist dann, dass das Delay sehr sehr lang werden kann :) Stefan U. schrieb: > > Der Trick besteht in der Subtraktion. Die liefert auch nach einem > Timerüberlauf das richtige Ergebnis. Richtig, unsigned Arithmetik. Der Trick Funktioniert aber nur in dieser Form. Denn in meiner Voraussetzung spielt der ausgezeichnete Wert 0L eine wichtige Rolle, die dann bei einem Überlauf vorkommen könnte. Damit würde sich das Delay eventuell auf 0 ms reduzieren. Aber man kann nicht alles haben. Auf jeden Fall nicht gleichzeitig, wie mein Chef immer zu sagen pflegt. Zusammenfassend kann man sagen, etwas einfach richtig zu machen, ist nicht immer leicht ist.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.