Gedankenfehler? TasterStatus in variable schreiben

Hallo zusammen,

ich stecke, als ziemlich blutiger Anfänger, schon am Anfang meines Projektes an einem scheinbar sehr einfachen Problem fest.

Ich habe das vor:

Ein Motor wird über 3 Taster gesteuert.

Taster 1 - vorwärts Taster 2 - rückwärts Taster 3 - Stopp

Taster 1 und Taster 2 funktionieren auch, aber nur, wenn man den Taster gedrückt hält. (Also ist Taster 3 bisher ohne Funktion)

Jetzt habe ich überlegt, wie ich den Taster "gedrückt" halten kann.

Meine Idee: Sobald Taster1 oder 2 gedrückt werden, wird in einer variablen ihr Status als "1" gespeichert, woraufhin der Motor läuft. Taster3 (Stopp) setzt den Status wieder auf 0 und beendet den Motorlauf.

Jetzt habe ich mal mit einem einfachen Grundgerüst das Prinzip getestet, aber ich bekomme es einfach nicht zum laufen.

Hier der Code:

(Ist nachempfunden, da ich gerade weder Arduino, noch meinen eigentlichen Code gerade zur Hand habe. Da es aber wirklich nicht viel Code ist, dürfte der zu 99% mit meinem Testcode übereinstimmen)

#define led1 13
#define taster1 11
#define taster2 12

int tasterStatus = 0;


void setup() {

  pinMode(led1, OUTPUT);
  pinMode(taster1, INPUT);
  pinMode(taster2, INPUT);

}

void loop() {

  if (digitalRead(taster1) == HIGH) {
    int tasterStatus = 1;
  }

  if (tasterStatus = 1) {
    digitalWrite(led1, HIGH);

    if (digitalRead(taster2) == HIGH) {
      digitalWrite(led1, LOW);
      int tasterStatus = 0;
    }
  }


}

Da ich schon hier Probleme habe, werde ich euch wohl die nächste Zeit noch mit weiteren "Problemchen" auf die Nerven gehen :D

Habe den Sketch kurz überflogen.

int tasterStatus = 1;

darfst du nur einmal zu Anfang machen, danach nur

tasterStatus = 1;

Hier

 if (tasterStatus = 1) {

muss es heißen

 if (tasterStatus == 1) {

Dann brauchst du Pullup oder Pulldown-Widerstände.

Pullup erreichst du so und sparst dadurch externe Widerstände:

pinMode(taster1, INPUT_PULLUP);

Danach musst du aber in der if-Anweisung auf LOW abfragen:

if (digitalRead(taster1) == LOW)

Das ist mir bisher aufgefallen, soweit könnte es funktionieren, was ich aber nicht getestet habe.

Ah cool, das man im Loop das "int" weglassen muss wusste ich nicht, könnte ja vielleicht sogar schon daran liegen.

Werde damit morgen nochmal testen.

Auch vielen Dank für den Hinweis mit den Pullup-Widerständen! Hatte ich bisher auch nicht auf dem Schirm :)

Aber angenommen ich verzichte auf den physischen Widerstand und vergesse in den pinMode den Pullup zu definieren. Könnte ich da was kaputt machen?

Aber mit meiner grundsätzlichen Idee einen Status zu speichern liege ich nicht falsch, richtig?

Hatte schon die Befürchtung das ich mit der Idee meilenweit von einer praktikablen Lösung entfernt bin :D

Aber angenommen ich verzichte auf den physischen Widerstand und vergesse in den pinMode den Pullup zu definieren. Könnte ich da was kaputt machen?

KA, welche Aktionen deine Motoren so alle überstehen können...

Hatte schon die Befürchtung das ich mit der Idee meilenweit von einer praktikablen Lösung entfernt bin

Ein Stückchen, bist du noch weg. (sorry)

Aber mit meiner grundsätzlichen Idee einen Status zu speichern liege ich nicht falsch, richtig?

Das nennt sich StateMachine, oder auf neudeutsch "Endlicher Automat" oder Zustandsmaschine. Ja, damit liegst du richtig.

Hatte ähnliche Probleme am Anfang auch. Was mir grade bei Tastern sehr geholfen hat ist bounce2.h https://github.com/thomasfredericks/Bounce2/wiki

Ansonsten zeig doch mal was für Motoren du hast. Für die Taster brauchst du keine "physischen Widerstände". Da würde ich den Arduino nutzen, da sollte eig. nichts passieren :)

doozstream: Aber angenommen ich verzichte auf den physischen Widerstand und vergesse in den pinMode den Pullup zu definieren. Könnte ich da was kaputt machen?

combie hat das meiste ja schon beantwortet.

Ohne die Widerstände können die Eingänge einen undefinierten Zustand erhalten und damit natürlich auch Schaltvorgänge verursachen, die nicht gewollt sind, bzw. nicht sein dürfen. Und es können merkwürdige Zustände vorkommen, die man nicht sofort erklären kann. Speziell bei langen Kabeln am Eingang. Also Widerstand muss sein.

Aber am Arduino geht erst mal nichts kaputt.

combie: Ein Stückchen, bist du noch weg. (sorry)

Wäre ja auch zu langweilig direkt ne perfekte Idee zu haben ;)

Ne, das ist mir bewusst dass es noch weitaus eleganter geht. Aber gestern war ich schon froh ne LED zum leuchten zu bringen, heute dreht sich schon ein Motor. Die wirklich guten Wegen kommen dann sicherlich auch irgendwann :D

@Heimdall

Danke! Werde ich mich mal einlesen.

Aktuell zum testen den hier:

https://www.amazon.de/28BYJ-48-28BYJ48-4-Phase-Arduino-Stepper/dp/B00ATA5MFE/ref=sr_1_2?ie=UTF8&qid=1471293620&sr=8-2&keywords=arduino+stepper

(Auch mit dem Treiber)

Aber morgen dann diesen Motor:

https://www.amazon.de/gp/product/B015ST2U5A/ref=oh_aui_detailpage_o00_s01?ie=UTF8&psc=1

mit diesem Treiber:

https://www.amazon.de/gp/product/B00GASG7TO/ref=oh_aui_detailpage_o00_s00?ie=UTF8&psc=1

@HotSystems

Super! Dann werde ich das morgen auch direkt mal ausprobieren! :)

Gut zu wissen dass da erstmal nicht kaputt gehen kann ;)

doozstream: Ah cool, das man im Loop das "int" weglassen muss wusste ich nicht, könnte ja vielleicht sogar schon daran liegen.

Wenn du das innerhalb einer Funktion oder eines Code Blocks nochmal machst erstellst du eine lokale Variable die die globale Variable gleichen Namens überdeckt. Jeder Zugriff innerhalb des Blocks geschieht dann mit der lokalen Version. Und diese hört am Ende der Funktion oder des Blocks auf zu existieren. Die globale Version wurde also nie verändert.

Sorgt u.a. für den netten Effekt, dass man sich wundert wieso Daten z.B. aus Funktionen nicht mehr für den ganzen Sketch zu verfügung stehen, weil sie quasi “immer wieder gelöscht werden” :smiley:

So, ich habe gerade eure Tipps ausprobiert und siehe da, es klappt :smiley:
Scheint wirklich ausschlaggebend an der nicht geänderten variablen gelegen zu haben.

Hier mal der Code, bei dem ihr vermutlich rasendes Kopfschütteln bekommen werdet :wink:

#include <Stepper.h>

const int stepsPerRevolution = 2048;
Stepper stepper(stepsPerRevolution, 2, 3, 4, 5);

const int LED1 = 7;     // LED für Forwärts - Taster 1
const int LED2 = 8;     // LED für Rückwärts - Taster 2
const int LED3 = 9;     // LED für STOPP - Taster 3
const int T1 = 13;      // Taster Forwärts
const int T2 = 12;      // Taster Rückwärts
const int T3 = 11;      // Taster STOPP

int stepCount = 0;      // Anzahl der gemachten Steps

int T1S = 0;
int T2S = 0;


void setup() {
  pinMode(LED1, OUTPUT);
  pinMode(LED2, OUTPUT);
  pinMode(LED3, OUTPUT);
  pinMode(T1, INPUT);
  pinMode(T2, INPUT);
  pinMode(T3, INPUT);
  
  //StartUp Sequenz - LED Lauflicht:
  digitalWrite(LED1, HIGH);
  delay (200);
  digitalWrite(LED1, LOW);
  digitalWrite(LED2, HIGH);
  delay (200);
  digitalWrite(LED2, LOW);
  digitalWrite(LED3, HIGH);
  delay (200);
  digitalWrite(LED3, LOW);
}

void backward() {
  while (T2S == HIGH ){
    digitalWrite (LED2, HIGH);

    int potiRead = analogRead(A0);
    int motorSpeed = map(potiRead, 0, 1023, 0, 14);

    Serial.println(motorSpeed);

    if (motorSpeed > 0) {
      stepper.setSpeed(motorSpeed);
      stepper.step(-stepsPerRevolution / 100);
      Serial.println(motorSpeed);

      if (digitalRead(T3) == HIGH) {
        T2S = 0;
        digitalWrite(LED2, LOW);
      }
    }
  }
}

void forward() {
  while (T1S == 1) {
    digitalWrite (LED1, HIGH);
    
    int potiRead = analogRead(A0);                  
    int motorSpeed = map(potiRead, 0, 1023, 0, 14); 

    Serial.println(motorSpeed);

    if (motorSpeed > 0) {
      stepper.setSpeed(motorSpeed);
      stepper.step(stepsPerRevolution / 100);
      Serial.println(motorSpeed);

      if (digitalRead(T3) == HIGH) {
        T1S = 0;
        digitalWrite(LED1, LOW);
      }
    }
  }
}

void loop() {

  if (digitalRead(T1) == HIGH) {
    T1S = 1;                              
    if (T1S == 1) {
      forward();
    }
  }

  if (digitalRead(T2) == HIGH) {
    T2S = 1;
    if (T2S == 1) {
      backward();
    }
  }
}

Da gibt es natürlich noch einiges an Optimierungspotential, aber es funktioniert erstmal :wink:

Das einzige was ich mich aktuell Frage:

Die void forward und backward musste ich jetzt vor dem void loop setzen, damit es keine Fehlermeldung gibt.
In einem anderen Sketch konnte ich zusätzliche voids aber auch nach den Loop setzen ohne irgendwelche Probleme.

Gibt es da auch eine einfache Erklärung für?

doozstream: So, ich habe gerade eure Tipps ausprobiert und siehe da, es klappt :D Scheint wirklich ausschlaggebend an der nicht geänderten variablen gelegen zu haben.

Hier mal der Code, bei dem ihr vermutlich rasendes Kopfschütteln bekommen werdet ;)

Da gibt es natürlich noch einiges an Optimierungspotential, aber es funktioniert erstmal ;)

Das sieht doch zum Anfang sehr gut aus. Ich kann nicht dran aussetzen.

Das einzige was ich mich aktuell Frage:

Die void forward und backward musste ich jetzt vor dem void loop setzen, damit es keine Fehlermeldung gibt. In einem anderen Sketch konnte ich zusätzliche voids aber auch nach den Loop setzen ohne irgendwelche Probleme.

Gibt es da auch eine einfache Erklärung für?

Ja, die gibt es. Hängt mit der Deklaration der Funktionen zusammen.

Aber bevor ich hier rumstochere und Blödsinn erzähle, sollen es die Fachleute erklären, die können es def. besser.

Es gibt keine voids! Die Dinger heißen Funktionen. void ist ein Datentyp. Hier gibt das an dass die Funktion nichts zurück gibt. Man kann auch Funktionen schreiben die Werte an die aufrufende Funktion zurückgeben. z.B:

int summe(int a, int b)
{
   return a + b;
}

Normalerweise müssen Funktionen bekannt sein bevor sie verwendet werden. Deshalb gibt es Funktionsprototypen bei denen man schon mal die Signatur der Funktion oben hinschreibt. Die Implementierung kann dann woanders erfolgen (C/C++ unterscheidet zwischen Deklaration und Definition). Die Arduino IDE übernimmt das für dich i.d.R und macht es versteckt im Hintergrund. Man kann also Funktionen normalerweise verwenden bevor sie implementiert werden. Es gibt ein paar Dinge wo das nicht richtig geht, aber void func() gehört sicherlich nicht dazu.

Du kannst mal das probieren:

void forward();

...

void forward()
{
}

Die erste Zeile ist dabei der Prototyp. Normal schreibt man die oben hin, aber es geht glaube auch einfach bei der Funktion. Jedenfalls in der Arduino IDE.

Der Prototyp kommt oben hin bevor die Funktion verwendest!

Aber wie gesagt sollte das hier eigentlich nicht nötig sein. Keine Ahnung wieso es hier mal nicht klappt.

Funktions-Prototypen setzt man an den Anfang einer Quelldatei, oder in eine Header-Datei. Dann weiß der Compiler, wie diese Funktionen aufzurufen sind, und muß nicht meckern wenn sie im Code irgendwo verwendet werden. Es schadet auch nicht, wenn ein Prototyp öfters angegeben wird, solange es jedesmal der gleiche ist (Ergebnistyp und Parameterliste müssen gleich sein). Aus unterschiedlichen Prototypen macht der Compiler unterschiedliche Funktionen, und meckert dann, wenn nur eine davon implementiert ist.

Den Unterschied zwischen Prototyp (Deklaration) und Implementierung (Definitition) hat Serenifly schon aufgezeigt: Beim Prototyp steht dort nur ein Strichpunkt, wo in der Implementierung der Codeblock {...} steht.

Ok, ich muss mich korrigieren :(

Für diesen Zweck muss der Prototyp wie ganz normal oben stehen. Sonst geht es nicht. Ich dachte da hätte die IDE auch etwas Magie. Das sieht man wenn man mal was verwendet was die IDE nicht selbst kann, wie ein enum als Parameter (da die IDE die Prototypen über die enum Definition schreibt). Dann verhält es sich wie man von C/C++ gewöhnt ist.

Was mich verwirrt hat ist dass es bei der Verwendung von Funktions-Attributen (naked, always_inline, weak, etc.) auch unten geht (jedenfalls kompiliert es dann). Ich dachte irgendwie das wäre das gleiche