Schrittmotor ansteuern

Ich habe mir auch überlegt es mit switch/case zu machen da es für mich logisch aussieht.

Das ist das gleiche habe nur das richtige Wort nicht gefunden.

Sagen wir so. Ich verstehe da vieles noch nicht so ganz weshalb ich es wahrscheinlich als nicht geeignet für mich sehe.
Ich werde mir dein Programm nochmals genau anschauen und probieren. Evtl. verstehe ich es irgend wann und kann damit meine Idee umsetzten.

Aktuell habe ich keinen R4 zur Hand daher kann ich es erst morgen anschauen.

PS: Ich arbeite hauptsächlich mit Codes aus dem Forum und Beispiele da ich wirklich sehr wenig Erfahrung habe. Ich suche mir alles zusammen und versuche daraus was zu machen und den Ablauf zu verstehen. Daher die Fehler verzeihen.

Hallo,
Ich denke das ist wesentlich komplizierter als über eine Webseite. Alleine schon die Darstellung von numerischen Tasten um etwas einzugeben. Ich hab sowas einmal gemacht , das reicht.

Mit einem Handy als Display hast du doch alles schon fertig.

Mach doch mal eine Handskizze wie du dir die Bedienoberfläche so vorstellst. Welche Eingabefelder , Anzeigen , Buttons.

Das geht jetzt sogar über "mit Kanonen auf Spatzen schießen" hinaus Arduino Giga das ist schon Atombombe auf Spatzen werfen.

Wenn du mal eine Skizze machst auf der du alle zukünftigen Eventualitäten die auf dem Display angezeigt werden sollen schon mit eingezeichnet sind, dann kann man eine Empfehlung machen was für einen Microcontroller und was für ein Display.

Das sind Konstanten und Du hilfst dem Compiler, wenn Du sie entsprechend markierst. Außerdem können Pinnummern nicht HIGH sein, sondern haben einen Zahlenwert:

const int driverENA = 10;    // Motortreiber ENA

In Beispielen findet man häufig #define für die Festlegung von Konstanten. Den Compiler stört das nicht, aber für Dich kann es hilfreich sein, einheitlich vorzugehen, beispielsweise so:

// Eingänge
constexpr int driverZero {3};     // Sensor Motor Nullposition
constexpr int scaleZero {4};      // Messskala Nullposition
constexpr int scaleMax {5};       // Sensor Messskala Maximalposition
constexpr int potiSpeed {A0};     // Potentiometer Drehzahl
// Später über Touch Display
constexpr int start {6};          // Taster Start
constexpr int stopp {7};          // Taster Stop
constexpr int rotation {8};       // Taster Drehrichtung
constexpr int transfer {9};       // Taster Werte / Varablen Übertragen

// Ausgänge
constexpr int driverENA {10};     // Motortreiber ENA
constexpr int driverDIR {11};     //  Motortreiber DIR
constexpr int driverPUL {12};     //  Motortreiber PUL
constexpr int LEDscaleZero {A3};  //  LED Messskala Nullposition

Die Pinnummern sind gewürfelt :slightly_smiling_face:

Ich habe deine Beschreibungen analysiert die 4 Modi haben etliche Gemeinsamkeiten

Allen Vier Modi ist in jedem Teilbereich gemeinsam

Wenn sich der Motor dreht und man die Taste "rotation" drückt soll sich der Motor so lange wie gedrückt wird in die andere Richtung drehen

Ich würde das ja "Reverse" nennen. Dann bringt das Wort schon auf den Punkt was passiert.

Das ist also immer aktiv und weil es in jedem Modus genau gleich ist, ist es vom Modus unabhängig

Ausführliche Sätze sind prima um die Details zu verstehen. Es macht aber auch Sinn eine zusamenfassende Überschrift zu haben

Modus 1: 	Rechtslauf + Umkehrtaster

Motor steht auf Nullposition 
A-rechts 			Poti für Geschindigkeit drehen - Motor dreht sich mit Rechtslauf bis Poti auf 0 gestellt wird oder auf Touch Display Stopp gedrückt wird 
B-andere-Richtung 	Wenn sich der Motor dreht und man die Taste "rotation" drückt soll sich der Motor so lange wie gedrpckt wird in die andere Richtung drehen 



Modus 2: Rechtslauf + Umkehrtaster + scaleMax-Sensor aktiv

Motor steht auf Nullposition 
A-rechts 			Poti für Geschindigkeit drehen - Motor dreht sich mit Rechtslauf bis Poti auf 0 gestellt wird oder auf Touch Display Stopp gedrückt wird
B-andere-Richtung 	Wen sich der Motor dreht und man die Taste "rotation" drückt soll sich der Motor so lange wie gedrpckt wird in die andere Richtung drehen 
C-scaleMax-aktiv
 = Richtungsumkehr 	Wird der Sensor "scaleMax" erreicht dreht sich der Motor mit Linkslauf bis Poti auf 0 gestellt wird oder auf Touch Display Stopp gedrückt wird
B-andere-Richtung 	Wenn sich der Motor dreht und man die Taste "rotation" drückt soll sich der Motor so lange wie gedrpckt wird in die andere Richtung drehen 



Modus 3: Linkslauf + Umkehrtaster

Motor steht auf Nullposition 
A-links 			Poti für Geschindigkeit drehen - Motor dreht sich mit Linkslauf bis Poti auf 0 gestellt wird oder auf Touch Display Stopp gedrückt wird 
B-andere-Richtung 	Wenn sich der Motor dreht und man die Taste "rotation" drückt soll sich der Motor so lange wie gedrpckt wird in die andere Richtung drehen 



Modus 4: Linkslauf + Umkehrtaster + scaleMax-Sensor aktiv

Motor steht auf Nullposition 
A-Links 			Poti für Geschindigkeit drehen - Motor dreht sich mit Linkslauf bis Poti auf 0 gestellt wird oder auf Touch Display Stopp gedrückt wird
B-andere-Richtung 	Wen sich der Motor dreht und man die Taste "rotation" drückt soll sich der Motor so lange wie gedrpckt wird in die andere Richtung drehen 
C-scaleMax-aktiv 	
 = Richtungsumkehr 	Wird der Sensor "scaleMax" erreicht dreht sich der Motor mit Rechtslauf bis Poti auf 0 gestellt wird oder auf Touch Display Stopp gedrückt wird
B-andere-Richtung 	Wenn sich der Motor dreht und man die Taste "rotation" drückt soll sich der Motor so lange wie gedrpckt wird in die andere Richtung drehen

Man kann das schon als 4 unterschiedliche Modi programmieren.
Mann könnte auch 40 unterschiedliche Modi programmieren. Geht alles.

Aber die 4 Modi unterscheiden sich nur in Details

rechts/links-Lauf
scaleMax-Sensor aktiv/inaktiv

Das spricht mehr dafür das als unterschiedliche Einstellungen zu sehen.

Wie groß soll die Schrift auf dem Touch-Display sein?
Was wird da im Maximalfall angezeigt?
Ich vermute auf dieser Display-Darstellung steht am meisten

  1. über Touch Display eingeben "Länge", "Gewicht", "S oder Z Drehung" (Touchdisplay zeigt an welcher Modus ausgewählt und Eingabefelder für ... und Start Taste)

Davonhängt ab welche Bildschirmgröße und wie viele Pixel.

Was ist da das "..." ???

Wenn du ein sogenannt "dummes" Display verwenden willst, das sind Displays denen man jedes Detail von jedem Pixel explizit übertragen muss, dann braucht der Microcontroller entsprechend viel RAM-Speicher.
Es gibt vorgefertigte Programmteile sogenannte Libraries die das stark vereinfachen.

Bei der Touchabfrage muss man die jeweiligen Koordinaten selbst bestimmen.

Nextion-Display
Wenn du ein intelligentes Display verwendest dann reicht deutlich weniger Speicher im Microcontroller aber man muss die Darstellung auf dem Display mit einem Editor designen

Beim Nextion-Display programmiert man lieber zu Fuß.
Die Nextion-library ist sehr lernaufwendig.

Wenn du mit WiFi und webbrowser-Steuerung arbeitest ist die Programmierung von
Zahlen und Texte anzeigen lassen bzw. die Auswertung von Touch-Befehlen etwas einfacher.

Ich kenne aber zum Beispiel die Display-Ansteuerung eines Arduino Giga mit aufgesteckten Display überhaupt nicht. Je nachdem wie komfortabel die dazugehörige Library ist geht das u.U. auch einfach. Weiß ich aber nicht.

Ich hatte das Wochenende leider gar keine Zeit. Daher werde ich heute wieder weiter machen.
Ich werde mir beide Möglichkeiten Display und Web nochmals anschauen mit Beispiele und Videos.

Das mit Giga habe ich nur in den Raum geworfen weil es halt ein Display gibt wo extra dafür gemacht wurde.
Daher es ist nichts gekauft oder endgültig beschlossen.

Die #define habe ich ersetzt durch die constexpr int
Das mit den Pinnummer und HIGH / LOW habe ich auch gesehen. Wäre mir irgend wann auch noch aufgefallen.

Die Zusammenfassung unten habe ich nochmals geändert so wie du es im Kommentar geschrieben hast.

Ich werde heute im Laufe des Tages noch eine Skizze machen von den Display Darstellungen und Posten.

Ich bin jetzt aber auch am überlegen was ist sinnvoller. Erst mal das Programm / den Ablauf machen und mit Taster simulieren oder erst eine Visualisierung machen und dann das Programm / den Ablauf?

Programmieren ist eine kreative Tätigkeit und da muß jeder seinen eigenen Weg finden. Ohne Erfahrung macht man nicht realisierbare Pläne, aber ohne Plan verheddert man sich. Daher kann es helfen, ein Projekt in kleinere Teile zu zerlegen und zunächst diese zu lösen.

Beispielsweise ist die Schrittkette noch nicht Dein Freund, sollte es aber meines Erachtens sein. Daher habe ich Dir einen Ansatz dazu vorgeschlagen. Das kannst Du mit Tasten und dem seriellen Monitor angehen. Auch einen Browser haben viele, weshalb ich das Beispiel aus der Bibliothek sympatisch finde. So kannst Du auch Hilfe aus dem Forum erhalten, denn dazu benötigt man keine spezielle Hardware. Sobald Du ein Display verwendest, das ich vermutlich nicht habe, bin ich vermutlich raus.


ausbaufähiges Programm mit "start" und "stop"
/*
  WiFi Web Server to control a stepper ( for UNO R4 WiFi )

  A simple web server that lets control a stepper via the web.
  This sketch will print the IP address of your WiFi module (once connected)
  to the Serial Monitor. From there, you can open that address in a web browser
  to control a stepper.

  An extension of the AP_SimpleWebServer example for UNO R4 WIFI
*/

// One of the following 2 defines must be active:
#define DEBUG_P( x, ... ) {char dbgBuf[80]; snprintf_P( dbgBuf, 80, PSTR( x ), ##__VA_ARGS__ ) ; Serial.println( dbgBuf ); }
//#define DEBUG_P(...)  // no debug printing

#if defined ARDUINO_ARCH_ESP32
#include "WiFi.h"
#else
#include "WiFiS3.h"
#endif
#include <MobaTools.h>  // min version 2.6.1: https://github.com/MicroBahner/MobaTools

#include "zugangsdaten.h"  // "arduino_secrets.h"
/*/////please enter your sensitive data in the newly created tab 'arduino_secrets.h'
  e.g.:
  #define SECRET_SSID "your-ssid"
  #define SECRET_PASS "your-passwd"
*/
const char * ssid = STA_SSID;              // your network SSID (name)
const char * pass = STA_PASSWORD;          // your network WPA  password

// change pin numers to your needs
#if defined ARDUINO_ARCH_ESP32
const int dirPin    = 25;
const int stepPin   = 26;
const int enaPin    = 27;
const int tasterPin = 12;
const int refPin    = 32;
#else
const int dirPin    =  5;
const int stepPin   =  6;
const int enaPin    =  7;
const int tasterPin =  2;
const int refPin    =  3;
#endif

const int STEPS_REVOLUTION = 800;                         // 1/4 Microstep -> 800 steps/rev
MoToStepper myStepper( STEPS_REVOLUTION, STEPDIR );       // create stepper instance

uint32_t htSpeed = 8000;    // steps/10 sec
uint32_t htRamp = 100;      // ramp length in steps

int status = WL_IDLE_STATUS;
WiFiServer server(80);
#include "website.h"

void setup() {
  Serial.begin(115200);                             // initialize serial communication
  // initialize stepper
  myStepper.attach( stepPin, dirPin );              // assign step/dir pins
  myStepper.attachEnable( enaPin, 10, LOW );        // attach enable in ( LOW=active )
  myStepper.setSpeedSteps( htSpeed );               // initial value of speed
  myStepper.setRampLen( htRamp );                   // initial ramp length


#if defined ARDUINO_ARCH_ESP32
  // nicht relevant
#else
  // check for the WiFi module:
  if (WiFi.status() == WL_NO_MODULE) {
    DEBUG_P("Communication with WiFi module failed!");
    // don't continue
    while (true);
  }
#endif

  // attempt to connect to WiFi network:
  DEBUG_P("Attempting to connect to Network named: %s", ssid);                   // print the network name (SSID);
  WiFi.begin(ssid, pass);
  while (WiFi.status() != WL_CONNECTED) {
    delay(200);
  }
  DEBUG_P("connected");
  server.begin();                           // start the web server on port 80
  printWifiStatus();                        // you're connected now, so print out the status

  setupManuell();
}

void loop() {
  handleWiFi();
  loopManuell();
}

void handleWiFi() {
  // text buffer receiving from connected browser
  constexpr uint8_t lineBufLen = 80;
  char lineBuf[lineBufLen];
  uint8_t bufIx = 0;

  WiFiClient client = server.available();   // listen for incoming clients
  if (client) {                             // if you get a client,
    DEBUG_P("new client");                  // print a message out the serial port
    while (client.connected()) {            // loop while the client's connected
      if (client.available()) {             // if there's bytes to read from the client,
        char c = client.read();             // read a byte, then
        if (c == '\n') {                    // if the byte is a newline character
          lineBuf[bufIx] = '\0';          // terminate string

          // if the current line is blank, you got two newline characters in a row.
          // that's the end of the client HTTP request, so send a response:
          if (bufIx == 0) {
            char htmlTemp[sizeof(HTMLTEXT) + 15]; // Size of website+some extra bytes for 2 variable fields
            DEBUG_P("Send website, speed=%d, ramp=%d", htSpeed, htRamp)
            snprintf( htmlTemp, sizeof(htmlTemp), HTMLTEXT, htRamp, htSpeed / 10 );
            client.print( htmlTemp);
            DEBUG_P("---------------Send HTTP-Page --------------------");
            break;
          } else {
            // We got a complete line. Test if we got a GET line and process it if so
            handleStepper(  lineBuf );
            bufIx = 0;
          }

        } else if (c != '\r') {
          // If you got anything else but a carriage return character,
          // write it into the buffer, but pay attention to the buffer length!
          if ( bufIx < (lineBufLen - 1) ) {      // leave space for a terminating \0
            lineBuf[bufIx++] = c;
          }
        }

      }
    } // End 'while connected'
    // close the connection:
    client.stop();
    DEBUG_P("client disconnected");
  }
}

void handleStepper( char * GETcom ) {
  // Field commands from the browser
  enum : uint8_t {SPEED, RAMP, SETSPEED_RAMP, SETSPEED, SETRAMP, LINKS, RECHTS, CONTL, CONTR, STOP}; // actions
  const char * keyWords[] = { "speed=", "ramp=", "setSpeedRamp=", "setSpeed=", "setRamp=", "links=", "rechts=", "contl=", "contr=", "stop=" };
  constexpr uint8_t keyIxMax = sizeof(keyWords) / sizeof(keyWords[0]);
  uint8_t keyIx;
  char *keyP, *valP;
  //check for GET command from client
  char* strGET = strstr( GETcom, "GET" );
  if ( strGET != NULL ) {
    // It's a GET line - process it
    uint32_t tmpSpeed = 8000, tmpRamp = 100;    // Default values for ramp and speed field - will usually been overwritten.
    DEBUG_P(GETcom);
    strGET = strstr( strGET, "stepper?" );
    if ( strGET != NULL ) {
      strGET += strlen("stepper?");
      strGET = strtok( strGET, " &" );
      DEBUG_P("vvvvvvvvvvvvvvvvvvvvvvv");
      while ( strGET != NULL ) {
        // DEBUG_P( strGET );
        // check for keywords - separate keyword from value
        valP = strchr(strGET, (int)'=');
        if ( valP ) valP++;
        for ( keyIx = 0; keyIx < keyIxMax; keyIx++ ) {
          keyP = strstr( strGET, keyWords[keyIx] );
          if ( keyP != NULL ) {
            DEBUG_P("Keyword: % s, Ix: % d", keyP, keyIx);
            // found keyword
            switch (keyIx) {
              case SPEED:
                tmpSpeed = 10 * atoi(valP);
                DEBUG_P("Speedval = %d", tmpSpeed);
                break;
              case RAMP:
                tmpRamp = atoi(valP);
                DEBUG_P("Rampval = % d", tmpRamp);
                break;
              case SETSPEED:
                htSpeed = tmpSpeed;
                htRamp = myStepper.setSpeedSteps(htSpeed, htRamp);
                DEBUG_P("set Speed = % d, actRamp = % d", htSpeed, htRamp);
                break;
              case SETSPEED_RAMP:
                htSpeed = tmpSpeed;
                htRamp = myStepper.setSpeedSteps(htSpeed);
                DEBUG_P("setSpeed + ramp = % d, actRamp = % d", htSpeed, htRamp);
                break;
              case SETRAMP:
                htRamp = tmpRamp;
                htRamp = myStepper.setRampLen(htRamp);
                break;
              case LINKS:
                myStepper.doSteps(-STEPS_REVOLUTION);
                DEBUG_P("One rev. CCW");
                break;
              case RECHTS:
                myStepper.doSteps(STEPS_REVOLUTION);
                DEBUG_P("one rev. CW");
                break;
              case CONTL:
                myStepper.rotate( -1 );
                DEBUG_P("rotate CCW");
                break;
              case CONTR:
                myStepper.rotate( 1 );
                DEBUG_P("rotate CW");
                break;
              case STOP:
                myStepper.rotate( 0 );
                DEBUG_P("Stop the stepper");
                break;
            }
            break; // Exit for loop, we found the keyword.
          }
        }
        strGET = strtok( NULL, " &" );
      }
      DEBUG_P("^^^^^^^^^^^^^^^^^^^^^^^^^");
    }
  }

}


void printWifiStatus() {
  // print the SSID of the network you're attached to:
  Serial.print("SSID: ");
  Serial.println(WiFi.SSID());

  // print your board's IP address:
  IPAddress ip = WiFi.localIP();
  Serial.print("IP Address: ");
  Serial.println(ip);

  // print the received signal strength:
  long rssi = WiFi.RSSI();
  Serial.print("signal strength (RSSI): ");
  Serial.print(rssi);
  Serial.println(" dBm");
  // print where to go in a browser:
  Serial.print("To see this page in action, open a browser to http://");
  Serial.println(ip);
}

void setupManuell()
{
  pinMode(tasterPin, INPUT_PULLUP);
  pinMode(refPin, INPUT_PULLUP);
}

int leseSeriell()
{
  static String serielleEingabe;
  int rueckgabe = -1;
  while (Serial.available())
  {
    char c = Serial.read();
    if (c == '\n')
    {
      DEBUG_P("serielleEingabe: %s", serielleEingabe);
      if (serielleEingabe.equals("stop"))  rueckgabe = 0;
      if (serielleEingabe.equals("start")) rueckgabe = 1;
      serielleEingabe = "";
    }
    else if (c != '\r')
    {
      serielleEingabe += c;
    }
  }
  return rueckgabe;
}

void loopManuell()
{
  char * strPos;
  enum struct Schritt : byte {WARTEN, REFERENZ, WEITER};
  static Schritt schritt = Schritt::WARTEN;

  switch (schritt)
  {
    case Schritt::WARTEN:
      if (!digitalRead(tasterPin))
      {
        DEBUG_P("Start Referenzsuche");
        myStepper.setZero( );
        myStepper.write( 360 );
        schritt = Schritt::REFERENZ;
      }
      break;
    case Schritt::REFERENZ:
      if (!digitalRead(refPin))
      {
        myStepper.setZero( );
        myStepper.stop( );
        DEBUG_P("Referenz gefunden");
        schritt = Schritt::WEITER;
      }
      if (!myStepper.moving())
      {
        DEBUG_P("Referenz nicht gefunden");
        schritt = Schritt::WEITER;
      }
      break;
    case Schritt::WEITER:
      switch (leseSeriell())
      {
        case 0:
          myStepper.rotate( 0 );
          DEBUG_P("Stop");
          break;
        case 1:
          myStepper.rotate( 1 );
          DEBUG_P("Start");
          break;
      }
      break;
    default:
      DEBUG_P("Fehler: In der Schrittkette falsch abgebogen!");
      break;
  }
}

website.h bleibt unverändert.

Es gibt viele Displays, die mit vielen Arduinomodellen zusammenarbeiten.

Grüße Uwe

schon mal vielen Dank für die ganzen hilfreichen Tipps.
Aktuell komme ich mit dem ganzen Code für die Webseite gar nicht klar.
Ich versuche es zu kapieren, das kann allerdings noch eine weile dauern. Bis ich wieder was neues habe zum posten

Du weißt ja, wo Du Fragen stellen kannst :wink:

Ich empfehle dir dazu folgende Vorgehensweise

Den kompletten Sketch den du zu verstehen versuchst als Code-Section posten.
In dem Sketch in genau der Zeile die du nicht verstehst einen Kommentar hinzufügen

Wichtig ! den kompletten sketch posten. Wenn du nur einen Teil postest dann nervt GENAU das, dass nur ein Teil des Codes da ist. Du wirst dann prompt aufgefordert den kompletten Sketch zu posten. Also poste gleich den kompletten Sketch.

Code-Sections haben eine begrenzte Höhe man kann schnell drüberscrollen wenn man das möchte. Der komplette Sketch stellt gleich alle Informationen zur Verfügung man muss nicht nachfragen.

Dann stelle eine vermutende Frage. Zu der Zeile die du noch nicht verstehst.
Je konkreter die Fragen desto schneller gibt es antworten. Selbst wenn du zu jeder zweiten Zeile eine Frage hast einfach posten. Konkrete Fragen beantworten geht meistens ganz fix.

Beispiel:

if (Serial.available() > 0) {

wie funktioniert diese if-bedingung?
vermutende Frage:
"Könnte es sein, dass immer dann wenn ich ein positive Zahl sende, das dann die Bedingung erfüllt ist?"

Antwort: "Nein. Serial.available() ist eine function eine Zahl zurück gibt.
Diese Zahl gibt an wie viele Zeichen sich im Empfangspuffer der seriellen Schnittstelle befinden. Diese Zahl ist 0 wenn keine Zeichen im Empfangspuffer sind.

Wenn 2 Zeichen im Empfangspuffer sind gibt die function Serial.available() die Zahl 2 zurück

Wenn 3 Zeichen im Empfangspuffer sind gibt die function Serial.available() die Zahl 3 zurück

usw.

Die Bedingung > 0 dient dazu zu prüfen befindet sich ein Zeichen im Empfangspuffer.