Forum: Mikrocontroller und Digitale Elektronik Programm mit einem Taster steuern


von Alter D. (naruto3000)


Lesenswert?

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?

von HildeK (Gast)


Lesenswert?

Da brauchst du nichts programmieren: nimm die Reset-Taste!

von Einer K. (Gast)


Lesenswert?

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.

von Christian S. (roehrenvorheizer)


Lesenswert?


von Thomas E. (thomase)


Angehängte Dateien:

Lesenswert?

...

von Patrick J. (ho-bit-hun-ter)


Lesenswert?


: Bearbeitet durch User
von Thomas E. (thomase)


Lesenswert?

Patrick J. schrieb:
> Scheint sauber zu sein:

Danke!

Natürlich ist das sauber.

von Alter D. (naruto3000)


Lesenswert?

Wenn ich die Reset-taste nutze kann ich nicht mit dem gleichen Taster 
(extern) das programm starten.

von Thomas E. (thomase)


Lesenswert?

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.

von Patrick J. (ho-bit-hun-ter)


Lesenswert?

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

von Noch einer (Gast)


Lesenswert?

>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.

von HildeK (Gast)


Lesenswert?

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.

von Stefan F. (Gast)


Lesenswert?

> 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.
von Peter D. (peda)


Lesenswert?

Alter D. schrieb:
> welches LEDs in einer speziellen Reihenfolge an- und ausschaltet.

Meinst Du sowas:

Beitrag "AVR Sleep Mode / Knight Rider"

von Noch einer (Gast)


Lesenswert?

> 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.

von il Conte (Gast)


Lesenswert?

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 ;-)

von ... (Gast)


Lesenswert?

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...

von Alter D. (naruto3000)


Lesenswert?

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);
    }

    }
  }

von Stefan F. (Gast)


Lesenswert?

Ja, du hast den switch/case Befehl völlig sinnlos verwendet. Schau 
nochmal in ein C Tutorial.

von HildeK (Gast)


Lesenswert?

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.

von Noch einer (Gast)


Lesenswert?

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.)

von Peter D. (peda)


Lesenswert?

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.

von Alter D. (naruto3000)


Lesenswert?

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.)

von Patrick J. (ho-bit-hun-ter)


Lesenswert?

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

von Stefan F. (Gast)


Lesenswert?

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.
von michael_ (Gast)


Lesenswert?

Einen Taster in einem Interrupt, womit man dann an den Programmanfang 
springt, ist kein Hexenwerk.
Den braucht man nicht mal entprellen.

von Stefan F. (Gast)


Lesenswert?

> 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.

von Peter D. (peda)


Lesenswert?

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.

von Einer K. (Gast)


Lesenswert?

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
}

von Noch einer (Gast)


Lesenswert?

> 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.

von michael_ (Gast)


Lesenswert?

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.

von Rolf H. (b0d0)


Lesenswert?

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
von Alexander L. (photoniker)


Lesenswert?

... 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
von Einer K. (Gast)


Lesenswert?

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.

von Rolf H. (b0d0)


Lesenswert?

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.

von Noch einer (Gast)


Lesenswert?

> 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.

von Einer K. (Gast)


Lesenswert?

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.

von Noch einer (Gast)


Lesenswert?

> 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.

von Stefan F. (Gast)


Lesenswert?

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.

von Rolf H. (b0d0)


Lesenswert?

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.

von Noch einer (Gast)


Lesenswert?

>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.

von Rolf H. (b0d0)


Lesenswert?

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.

von Falk B. (falk)


Lesenswert?

@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?

von Falk B. (falk)


Lesenswert?

@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.

von Patrick J. (ho-bit-hun-ter)


Lesenswert?

Hi

Vom delay() auf inkompetente Professoren zu kommen, schafft man auch 
nicht in jedem Forum :)

MfG

von Stefan F. (Gast)


Lesenswert?

> 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.

von Einer K. (Gast)


Lesenswert?

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.

von Rolf H. (b0d0)


Lesenswert?

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.

von Stefan F. (Gast)


Lesenswert?

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.

von Rolf H. (b0d0)


Lesenswert?

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
Noch kein Account? Hier anmelden.