Brauche Hilfe bei meinem Programm zur Vorschubsteuerung

Hallo zusammen,

ich schreibe gerade ein Programm, mit dem ich die Vorschubgeschwindigkeit in mm/min für die Achsen XYZ und in rpm für die A-Achse steuern kann. Die Geschwindigkeit für die Schrittmotoren wird über die Frequenz der Rechteckimpulse gesteuert. Zur Erzeugung der Rechtecksignale verwende ich die Bibliothek Tone.h. Jeder Motor hat einen Plus- und Minus-Taster und zusätzlich einen Taster für den Eilgangmodus.
Wird der Eilgangmodus aktiviert, soll die bisherige Geschwindigkeit (currentSpeed) in der Variable oldSpeed gespeichert werden und in currentSpeed wird der Wert von maxSpeed geschrieben. Wenn der Eilgangmodus verlassen wird, soll der Wert von oldSpeed zurück in currentSpeed geschrieben werden, damit nach dem Eilgang wieder die zuvor eingestellte Geschwindigkeit vorliegt.
Leider funktioniert das nicht, denn auch nach dem verlassen des Eilgangmodus bleibt die Geschwindigkeit auf dem Wert von maxSpeed.

Kann mir bitte jemand helfen und sagen wo mein Fehler liegt?

Vielen Dank und Grüße

Daniel

Code:

/*  Manual Mill Controller v1.0
 *  written by Iron-Dan
 *  Creates stepper pulses to set speeds in mm/min and rpm and included rapid traverse mode.
 *  Implemented with the usage of the libraries which are included below.
 */

/*********************************************************************
  This is an example for our Monochrome OLEDs based on SSD1306 drivers

  Pick one up today in the adafruit shop!
  ------> http://www.adafruit.com/category/63_98

  This example is for a 128x64 size myOLED using I2C to communicate
  3 pins are required to interface (2 I2C and one reset)

  Adafruit invests time and resources providing this open source code,
  please support Adafruit and open-source hardware by purchasing
  products from Adafruit!

  Written by Limor Fried/Ladyada  for Adafruit Industries.
  BSD license, check license.txt for more information
  All text above, and the splash screen must be included in any redistribution
*********************************************************************/

/*********************************************************************
  I change the adafruit SSD1306 to SH1106
  SH1106 driver don't provide several functions such as scroll commands.
*********************************************************************/

#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SH1106.h>

#define OLED_RESET -1
Adafruit_SH1106 myOLED(OLED_RESET);

#include <Tone.h>

// Variables

const byte minusButtonA = 8;                        // Minus Button for speed value on A-Axis at Arduino Pin 10.
const byte plusButtonA = 7;                         // Plus Button for speed value on A-Axis at Arduino Pin 9.
const byte rapidButtonA = 2;                        // Button for rapid traverse mode on A-Axis at Arduino Pin 2.
const byte rapidLEDA = 11;                          // LED for indication of rapid traverse mode on A-Axis at Arduino Pin 11.
volatile byte stateRapidModeA = LOW;                // State of rapid traverse mode on A-Axis.
const float maxSpeedA = 20.0;                       // Max. speed in rpm.
volatile float currentSpeedA = 0.0;                 // Current speed in rpm.
volatile float oldSpeedA = 0.0;                     // Old speed in rpm.

const byte minusButtonXYZ = 10;                     // Minus Button for speed value on XYZ-Axis at Arduino Pin 8.
const byte plusButtonXYZ = 9;                       // Plus Button for speed value on XYZ-Axis at Arduino Pin 7.
const byte rapidButtonXYZ = 3;                      // Button for rapid traverse mode on XYZ-Axis at Arduino Pin 3.
const byte rapidLEDXYZ = 12;                        // LED for indication of rapid traverse mode on XYZ-Axis at Arduino Pin 12.
volatile byte stateRapidModeXYZ = LOW;              // State of rapid traverse mode on XYZ-Axis.
const float maxSpeedXYZ = 2000.0;                   // Max. speed in mm/min.
volatile float currentSpeedXYZ = 0.0;               // Current speed in mm/min.
volatile float oldSpeedXYZ = 0.0;                   // Old speed in mm/min.

// Timer variables

unsigned long lastIntTimeA = 0;                     // Time value in ms when ISR rapidModeA was called last time.
unsigned long newIntTimeA;                          // New time value in ms when ISR rapidModeA is called.
unsigned long previousMillisMinusButtonA = 0;       // Store time in ms as MinusButtonA was clicked first time.
unsigned long currentMillisMinusButtonA = 0;        // Store time value as long as MinusButtonA is held.
unsigned long previousMillisPlusButtonA = 0;        // Store time in ms as PlusButtonA was clicked first time.
unsigned long currentMillisPlusButtonA = 0;         // Store time value as long as PlusButtonA is held.

unsigned long lastIntTimeXYZ = 0;                   // Time value in ms when ISR rapidModeXYZ was called last time.
unsigned long newIntTimeXYZ;                        // New time value in ms when ISR rapidModeXYZ is called.
unsigned long previousMillisMinusButtonXYZ = 0;     // Store time in ms as MinusButtonXYZ was clicked first time.
unsigned long currentMillisMinusButtonXYZ = 0;      // Store time value as long as MinusButtonXYZ is held.
unsigned long previousMillisPlusButtonXYZ = 0;      // Store time in ms as PlusButtonXYZ was clicked first time.
unsigned long currentMillisPlusButtonXYZ = 0;       // Store time value as long as PlusButtonXYZ is held.

// Stepper variables

unsigned int microStepsA = 16;
unsigned int motorStepsA = 200;
unsigned int turnsPerRoundA = 90;
unsigned int microStepsXYZ = 16;
unsigned int motorStepsXYZ = 200;
unsigned int mmPerRoundXYZ = 5;
unsigned int frequencyA = 0;
unsigned int frequencyXYZ = 0;

Tone pulseA;                                        // Create Tone object pulseA.
Tone pulseXYZ;                                      // Create Tone object pulseXYZ.

// Interrupt Service Routines (ISR)

void rapidModeA()
{
  newIntTimeA = millis();
  if (newIntTimeA - lastIntTimeA > 200)             // Push button debouncing.
  {
    stateRapidModeA = !stateRapidModeA;             // Toggle stateRapidModeA when rapidButtonA was pressed.
  }
  lastIntTimeA = newIntTimeA;
  
  if (stateRapidModeA == HIGH)
  {
    digitalWrite(rapidLEDA, HIGH);
    oldSpeedA = currentSpeedA;                      // Store previous speed for A-Axis.
    currentSpeedA = maxSpeedA;                      // Set max speed for A-Axis.
  }
  else if (stateRapidModeA == LOW)
  {
    digitalWrite(rapidLEDA, LOW);
    currentSpeedA = oldSpeedA;                      // Restore speed value before rapid traverse mode was entered.
  }
}

void rapidModeXYZ()
{
  newIntTimeXYZ = millis();
  if (newIntTimeXYZ - lastIntTimeXYZ > 200)         // Push button debouncing.
  {
    stateRapidModeXYZ = !stateRapidModeXYZ;         // Toggle stateRapidModeXYZ when rapidButtonXYZ was pressed.
  }
  lastIntTimeXYZ = newIntTimeXYZ;

  if (stateRapidModeXYZ == HIGH)
  {
    digitalWrite(rapidLEDXYZ, HIGH);
    oldSpeedXYZ = currentSpeedXYZ;                  // Store previous speed for XYZ-Axis.
    currentSpeedXYZ = maxSpeedXYZ;                  // Set max speed for XYZ-Axis.
  }
  else if (stateRapidModeXYZ == LOW)
  {
    digitalWrite(rapidLEDXYZ, LOW);
    currentSpeedXYZ = oldSpeedXYZ;                  // Restore speed value before rapid traverse mode was entered.
  }
}


void setup() {
  pinMode(minusButtonA, INPUT_PULLUP);
  pinMode(plusButtonA, INPUT_PULLUP);
  pinMode(rapidButtonA, INPUT_PULLUP);
  pinMode(minusButtonXYZ, INPUT_PULLUP);
  pinMode(plusButtonXYZ, INPUT_PULLUP);
  pinMode(rapidButtonXYZ, INPUT_PULLUP);
  pinMode(rapidLEDA, OUTPUT);
  pinMode(rapidLEDXYZ, OUTPUT);
  attachInterrupt(digitalPinToInterrupt(rapidButtonA), rapidModeA, FALLING);
  attachInterrupt(digitalPinToInterrupt(rapidButtonXYZ), rapidModeXYZ, FALLING);

  pulseA.begin(5);                                  // Init stepper pulses for A-Axis at Arduino Pin 5.
  pulseXYZ.begin(6);                                // Init stepper pulses for XYZ-Axis at Arduino Pin 6.

  bootScreen();                                     // Show Boot Screen

}

void loop() {

  readMinusButtonA();
  readPlusButtonA();
  readMinusButtonXYZ();
  readPlusButtonXYZ();

  updateDisplay();

  if (currentSpeedA > 0)
  {
    frequencyA = (round(currentSpeedA) * microStepsA * motorStepsA * turnsPerRoundA) / 60;
    pulseA.play(frequencyA);
  }
  else
  {
    pulseA.stop();
  }
  
  if (currentSpeedXYZ > 0)
  {
    frequencyXYZ = (round(currentSpeedXYZ) * microStepsXYZ * motorStepsXYZ) / (60 * mmPerRoundXYZ);
    pulseXYZ.play(frequencyXYZ);
  }
  else
  {
    pulseXYZ.stop();
  }

}

void bootScreen()
{
  myOLED.begin();                                   // Init the OLED.
  myOLED.clearDisplay();                            // Clear display buffer.
  myOLED.setTextSize(1);
  myOLED.setTextColor(WHITE);
  myOLED.setCursor(0, 0);
  myOLED.print("MANUAL");
  myOLED.setCursor(0, 10);
  myOLED.print("MILL");
  myOLED.setCursor(0, 20);
  myOLED.print("CONTROLLER");
  myOLED.setCursor(0, 30);
  myOLED.print("v1.0");
  myOLED.setCursor(0, 40);
  myOLED.print("BY IRON-DAN");
  myOLED.display();
  delay(3000);
  myOLED.clearDisplay();                            // Clear display buffer.
  myOLED.setTextSize(2);
}

void updateDisplay()
{
  myOLED.setCursor(0, 0);
  myOLED.print("XYZ");
  myOLED.setCursor(40, 0);
  myOLED.print(currentSpeedXYZ);
  myOLED.setCursor(0, 30);
  myOLED.print("A");
  myOLED.setCursor(40, 30);
  myOLED.print(currentSpeedA);
  myOLED.display();
  delay(100);
  myOLED.clearDisplay();                            // Clear display buffer.
}

void readMinusButtonA()
{
  if (!digitalRead(minusButtonA))
  {
    previousMillisMinusButtonA = millis();          // Store first time value when MinusButtonA was clicked.

    while (!digitalRead(minusButtonA))
    {
      currentMillisMinusButtonA = millis();         // Update time value as long as MinusButtonA is held.
      if (currentMillisMinusButtonA - previousMillisMinusButtonA > 50 && currentMillisMinusButtonA - previousMillisMinusButtonA <= 1000)
      {
        currentSpeedA -= 0.01;
        if (currentSpeedA < 0)
        {
          currentSpeedA = 0;
        }
        updateDisplay();
      }
      else if (currentMillisMinusButtonA - previousMillisMinusButtonA > 1000 && currentMillisMinusButtonA - previousMillisMinusButtonA <= 5000)
      {
        currentSpeedA -= 0.10;
        if (currentSpeedA < 0)
        {
          currentSpeedA = 0;
        }
        updateDisplay();
      }
      else if (currentMillisMinusButtonA - previousMillisMinusButtonA > 5000)
      {
        currentSpeedA -= 1.00;
        if (currentSpeedA < 0)
        {
          currentSpeedA = 0;
        }
        updateDisplay();
      }
    }
  }
}

void readPlusButtonA()
{
  if (!digitalRead(plusButtonA))
  {
    previousMillisPlusButtonA = millis();           // Store first time value when PlusButtonA was clicked.

    while (!digitalRead(plusButtonA))
    {
      currentMillisPlusButtonA = millis();          // Update time value as long as PlusButtonA is held.
      if (currentMillisPlusButtonA - previousMillisPlusButtonA > 50 && currentMillisPlusButtonA - previousMillisPlusButtonA <= 1000)
      {
        currentSpeedA += 0.01;
        if (currentSpeedA > maxSpeedA)
        {
          currentSpeedA = maxSpeedA;
        }
        updateDisplay();
      }
      else if (currentMillisPlusButtonA - previousMillisPlusButtonA > 1000 && currentMillisPlusButtonA - previousMillisPlusButtonA <= 5000)
      {
        currentSpeedA += 0.10;
        if (currentSpeedA > maxSpeedA)
        {
          currentSpeedA = maxSpeedA;
        }
        updateDisplay();
      }
      else if (currentMillisPlusButtonA - previousMillisPlusButtonA > 5000)
      {
        currentSpeedA += 1.00;
        if (currentSpeedA > maxSpeedA)
        {
          currentSpeedA = maxSpeedA;
        }
        updateDisplay();
      }
    }
  }
}
void readMinusButtonXYZ()
{
  if (!digitalRead(minusButtonXYZ))
  {
    previousMillisMinusButtonXYZ = millis();        // Store first time value when MinusButtonXYZ was clicked.

    while (!digitalRead(minusButtonXYZ))
    {
      currentMillisMinusButtonXYZ = millis();       // Update time value as long as MinusButtonXYZ is held.
      if (currentMillisMinusButtonXYZ - previousMillisMinusButtonXYZ > 50 && currentMillisMinusButtonXYZ - previousMillisMinusButtonXYZ <= 1000)
      {
        currentSpeedXYZ -= 0.01;
        if (currentSpeedXYZ < 0)
        {
          currentSpeedXYZ = 0;
        }
        updateDisplay();
      }
      else if (currentMillisMinusButtonXYZ - previousMillisMinusButtonXYZ > 1000 && currentMillisMinusButtonXYZ - previousMillisMinusButtonXYZ <= 5000)
      {
        currentSpeedXYZ -= 0.10;
        if (currentSpeedXYZ < 0)
        {
          currentSpeedXYZ = 0;
        }
        updateDisplay();
      }
      else if (currentMillisMinusButtonXYZ - previousMillisMinusButtonXYZ > 5000 && currentMillisMinusButtonXYZ - previousMillisMinusButtonXYZ <= 10000)
      {
        currentSpeedXYZ -= 1.00;
        if (currentSpeedXYZ < 0)
        {
          currentSpeedXYZ = 0;
        }
        updateDisplay();
      }
      else if (currentMillisMinusButtonXYZ - previousMillisMinusButtonXYZ > 10000)
      {
        currentSpeedXYZ -= 10.00;
        if (currentSpeedXYZ < 0)
        {
          currentSpeedXYZ = 0;
        }
        updateDisplay();
      }
    }
  }
}

void readPlusButtonXYZ()
{
  if (!digitalRead(plusButtonXYZ))
  {
    previousMillisPlusButtonXYZ = millis();         // Store first time value when PlusButtonXYZ was clicked.

    while (!digitalRead(plusButtonXYZ))
    {
      currentMillisPlusButtonXYZ = millis();        // Update time value as long as PlusButtonXYZ is held.
      if (currentMillisPlusButtonXYZ - previousMillisPlusButtonXYZ > 50 && currentMillisPlusButtonXYZ - previousMillisPlusButtonXYZ <= 1000)
      {
        currentSpeedXYZ += 0.01;
        if (currentSpeedXYZ > maxSpeedXYZ)
        {
          currentSpeedXYZ = maxSpeedXYZ;
        }
        updateDisplay();
      }
      else if (currentMillisPlusButtonXYZ - previousMillisPlusButtonXYZ > 1000 && currentMillisPlusButtonXYZ - previousMillisPlusButtonXYZ <= 5000)
      {
        currentSpeedXYZ += 0.10;
        if (currentSpeedXYZ > maxSpeedXYZ)
        {
          currentSpeedXYZ = maxSpeedXYZ;
        }
        updateDisplay();
      }
      else if (currentMillisPlusButtonXYZ - previousMillisPlusButtonXYZ > 5000 && currentMillisPlusButtonXYZ - previousMillisPlusButtonXYZ <= 10000)
      {
        currentSpeedXYZ += 1.00;
        if (currentSpeedXYZ > maxSpeedXYZ)
        {
          currentSpeedXYZ = maxSpeedXYZ;
        }
        updateDisplay();
      }
      else if (currentMillisPlusButtonXYZ - previousMillisPlusButtonXYZ > 10000)
      {
        currentSpeedXYZ += 10.00;
        if (currentSpeedXYZ > maxSpeedXYZ)
        {
          currentSpeedXYZ = maxSpeedXYZ;
        }
        updateDisplay();
      }
    }
  }
}

Zum Einen: Warum verwendest Du für die Eilgangtaster Interrupts? Du baust Dir da nur gefährliche Fehlerquellen ein, weil Du multi-Byte Variablen im Interrupt änderst, die Du auch im loop abfragst. Da können beliebige Fehlereffekte auftreten, wenn der Interrupt mitten in einer Variablenabfrage im loop auftritt. Du weist ja nie, wo sich dein Programm gerade befindet, wenn Du den Taster drückst.
Also bearbeite deine Eilgangtaster genauso im loop wie die Plus- und Minus Taster. Damit hast Du schonmal eine Fehlerquelle weniger.

Des weitern hast Du ( außer dem updateDisplay() ) eigentlich keine 'Bremse' in deinem Loop. Es macht aber keinen Sinn, die Pulsfrequenz häufiger zu ändern, als es der Entprellzeit der Taster entspricht. Eigentlich macht es nur Sinn, wenn sich durch die Taster die Geschwindigkeit tatsächlich verändert hat. Ich weis auch nicht, ob es Probleme bei der tone-Lib gibt, wenn man das 'play' u.U. häufigeraufruft, als es der ausgegebenen Frequenz entspricht. Das macht ja ebenfalls keinen Sinn.

Du kannst all diese Fliegen mit einer Klappe erschlagen, wenn Du das Lesen der Taster und Ändern der Frequenz einfach über millis gesteuert nur alle 20..50ms machst. Da entprellst Du mit einer millis-Abfrage alle Taster, und die play() Methode wird auch nicht zu oft aufgerufen.

Edit: Ich sehe gerade, dass Du in deinem 'updateDisplay()' ein delay(100) drin hast. Dann kannst Du dir das Entprellem der Taster eigentlich ganz sparen, da sie eh nur >alle 100ms abgefragt werden. Das Problem mit dem Interrupt bleibt aber.

Wenn diese Fehlerquellen alle beseitigt sind hat sich vielleicht auch dein Problem mit dem Eilgang erledigt.

P.S. Wozu benutzt Du SPI, wenn das OLED über I2C angeseteuert wird?

Nochmal Edit:
Das hier macht so auch keinen Sinn und ist eher eine Fehlerquelle:

  if (stateRapidModeA == HIGH)
  {
    digitalWrite(rapidLEDA, HIGH);
    oldSpeedA = currentSpeedA;                      // Store previous speed for A-Axis.
    currentSpeedA = maxSpeedA;                      // Set max speed for A-Axis.
  }
  else if (stateRapidModeA == LOW) // <===== das if hier ist sinnlos
  {
    digitalWrite(rapidLEDA, LOW);
    currentSpeedA = oldSpeedA;                      // Restore speed value before rapid traverse mode was entered.
  }
}

Besser ist:

  if (stateRapidModeA)
  {
    digitalWrite(rapidLEDA, HIGH);
    oldSpeedA = currentSpeedA;                      // Store previous speed for A-Axis.
    currentSpeedA = maxSpeedA;                      // Set max speed for A-Axis.
  }
  else
  {
    digitalWrite(rapidLEDA, LOW);
    currentSpeedA = oldSpeedA;                      // Restore speed value before rapid traverse mode was entered.
  }
}

( Dasselbe bei XYZ)

Hallo,
mir stellt sich die Frage warum Du keine gängige Lib zur Ansteuerung der Schrittmotoren verwendest.
MobaTools , AccelStepper

wären da geeignete Kandidaten
Heinz

Eine erste Überschlagsrechnung ergab, dass er Schrittfrequenzen erzeugt, die weit über dem liegen, was beide Libs erzeugen können - zumindest auf einem AVR Prozessor. Selbst für die tone-lib liegt er da teilweise schon an oder über den Grenzen - zumindest laut dem, was auf GitHub für die tone-Lib steht.

    frequencyA = (round(currentSpeedA) * microStepsA * motorStepsA * turnsPerRoundA) / 60;
    pulseA.play(frequencyA);

mit

maxSpeedA = 20;
microStepsA = 16;
motorStepsA = 200;
turnsPerRoundA = 90;

ergeben sich da 96kHz!
Lt GitHub Beschreibung ist bei der tone-Lib bereits bei ca 80kHz Schluß.

Hallo,
na so tief bin ich nicht eingestiegen, dann ist er aber total auf dem Holzweg und sollte sich einen andere Lösung suchen.
Heinz

Hallo MicroBahner,

danke für deine Rückmeldung und die Verbesserungsvorschläge.

Weil ich das im Internet gelesen hatte, dass man das mit Interrupts machen soll, wenn man sichergehen will, dass die Taster sicher erkannt werden. Und ich dachte das Umschalten vom Eilgang in den normalen Betrieb sollte sicher erkannt werden. Aber wenn ich jetzt so darüber nachdenke ist meine Reaktionszeit sowieso viel länge als die Zykluszeit, da kann ich auch im Loop abfragen :slight_smile: Sorry, bin noch nicht so erfahren mit dem Programmieren des Arduino.

Weil das so im Beispiel für die Bibliothek Adafruit_SH1106.h OLED vorhanden war, ich habe das einfach übernommen.

Danke für den Hinweis, das werde ich abändern.

Vielen Dank und Grüße
Dan

Hallo Heinz,

danke für deinen Beitrag.

Vorrangig, weil ich dachte, dass ich bei den Libs nur Distanzen mit einer gewünschten Geschwindigkeit anfahren kann und danach kommen keine Pulse mehr. Ich will einfach nur kontinuierlich Pulse mit veränderbarer Frequenz erzeugen, ein Richtungs- oder Enablesignal benötige ich nicht, das wollte ich direkt am Schrittmotortreiber über Hardwaretaster lösen.
Das erschien mir praktikabler. :slight_smile:

Viele Grüße
Dan

Hallo zusammen,

ich habe das Programme umgeschrieben und jetzt soweit zum Laufen gebracht.
Es gibt nur noch ein Problem, wenn ich beide Taster für den Eilgang betätige, dann hängt sich das Programm auf.

Weiß jemand eine Lösung hierzu?

Außerdem ist nun ein Problem mit der Anzeige auf dem OLED aufgetreten, denn es zeigt plötzlich Pixelfehler.

Am Display liegt es nicht, ein anderes Display mit SH1106-Treiber zeigt eine völlig identische Darstellung, es muss also am Code liegen.

Ich werde dazu ein neues Thema eröffnen.

Vielen Dank und Grüße
Dan

/*  Manual Mill Controller v1.0
    written by Iron-Dan
    Creates stepper pulses to set speeds in mm/min and rpm and included rapid traverse mode.
    Implemented with the usage of the libraries which are included below.
*/

/*********************************************************************
  This is an example for our Monochrome OLEDs based on SSD1306 drivers

  Pick one up today in the adafruit shop!
  ------> http://www.adafruit.com/category/63_98

  This example is for a 128x64 size myOLED using I2C to communicate
  3 pins are required to interface (2 I2C and one reset)

  Adafruit invests time and resources providing this open source code,
  please support Adafruit and open-source hardware by purchasing
  products from Adafruit!

  Written by Limor Fried/Ladyada  for Adafruit Industries.
  BSD license, check license.txt for more information
  All text above, and the splash screen must be included in any redistribution
*********************************************************************/

/*********************************************************************
  I change the adafruit SSD1306 to SH1106
  SH1106 driver don't provide several functions such as scroll commands.
*********************************************************************/

#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SH1106.h>

#define OLED_RESET -1
Adafruit_SH1106 myOLED(OLED_RESET);

#include <Tone.h>

// Variables

const byte minusButtonA = 8;                        // Minus Button for speed value on A-Axis at Arduino Pin 10.
const byte plusButtonA = 7;                         // Plus Button for speed value on A-Axis at Arduino Pin 9.
const byte rapidButtonA = 2;                        // Button for rapid traverse mode on A-Axis at Arduino Pin 2.
const byte rapidLEDA = 11;                          // LED for indication of rapid traverse mode on A-Axis at Arduino Pin 11.
byte stateRapidModeA = LOW;                         // State of rapid traverse mode on A-Axis.
const unsigned long maxSpeedA = 136;                // Max. speed / 10 = speed in rpm. 136 = 65280Hz -> max. 65535Hz!
unsigned long currentSpeedA = 0;                    // Current speed in rpm.
unsigned long oldSpeedA = 0;                        // Old speed in rpm.

const byte minusButtonXYZ = 10;                     // Minus Button for speed value on XYZ-Axis at Arduino Pin 8.
const byte plusButtonXYZ = 9;                       // Plus Button for speed value on XYZ-Axis at Arduino Pin 7.
const byte rapidButtonXYZ = 3;                      // Button for rapid traverse mode on XYZ-Axis at Arduino Pin 3.
const byte rapidLEDXYZ = 12;                        // LED for indication of rapid traverse mode on XYZ-Axis at Arduino Pin 12.
byte stateRapidModeXYZ = LOW;                       // State of rapid traverse mode on XYZ-Axis.
const unsigned long maxSpeedXYZ = 20000;            // Max. speed / 10 = speed in mm/min.
unsigned long currentSpeedXYZ = 0;                  // Current speed in mm/min.
unsigned long oldSpeedXYZ = 0;                      // Old speed in mm/min.

// Timer variables

unsigned long previousMillisRapidButtonA = 0;       // Time value in ms when rapidButtonA was pressed last time.
unsigned long currentMillisRapidButtonA;            // New time value in ms when rapidButtonA was pressed.
unsigned long previousMillisMinusButtonA = 0;       // Store time in ms as MinusButtonA was clicked first time.
unsigned long currentMillisMinusButtonA = 0;        // Store time value as long as MinusButtonA is held.
unsigned long previousMillisPlusButtonA = 0;        // Store time in ms as PlusButtonA was clicked first time.
unsigned long currentMillisPlusButtonA = 0;         // Store time value as long as PlusButtonA is held.

unsigned long previousMillisRapidButtonXYZ = 0;     // Time value in ms when rapidButtonXYZ was pressed last time.
unsigned long currentMillisRapidButtonXYZ;          // New time value in ms when rapidButtonXYZ was pressed.
unsigned long previousMillisMinusButtonXYZ = 0;     // Store time in ms as MinusButtonXYZ was clicked first time.
unsigned long currentMillisMinusButtonXYZ = 0;      // Store time value as long as MinusButtonXYZ is held.
unsigned long previousMillisPlusButtonXYZ = 0;      // Store time in ms as PlusButtonXYZ was clicked first time.
unsigned long currentMillisPlusButtonXYZ = 0;       // Store time value as long as PlusButtonXYZ is held.

// Stepper variables

unsigned int microStepsA = 16;
unsigned int motorStepsA = 200;
unsigned int turnsPerRoundA = 90;
unsigned int microStepsXYZ = 16;
unsigned int motorStepsXYZ = 200;
unsigned int mmPerRoundXYZ = 5;
unsigned int frequencyA = 0;
unsigned int frequencyXYZ = 0;

Tone pulseA;                                        // Create Tone object pulseA.
Tone pulseXYZ;                                      // Create Tone object pulseXYZ.

// Setup

void setup() {
  pinMode(minusButtonA, INPUT_PULLUP);
  pinMode(plusButtonA, INPUT_PULLUP);
  pinMode(rapidButtonA, INPUT_PULLUP);
  pinMode(minusButtonXYZ, INPUT_PULLUP);
  pinMode(plusButtonXYZ, INPUT_PULLUP);
  pinMode(rapidButtonXYZ, INPUT_PULLUP);
  pinMode(rapidLEDA, OUTPUT);
  pinMode(rapidLEDXYZ, OUTPUT);

  pulseA.begin(5);                                  // Init stepper pulses for A-Axis at Arduino Pin 5.
  pulseXYZ.begin(6);                                // Init stepper pulses for XYZ-Axis at Arduino Pin 6.

  bootScreen();                                     // Show Boot Screen


}

void loop() {

  readRapidButtonA();
  readRapidButtonXYZ();
  readMinusButtonA();
  readPlusButtonA();
  readMinusButtonXYZ();
  readPlusButtonXYZ();

  updateDisplay();

}

void bootScreen()
{
  myOLED.begin();                                   // Init the OLED.
  myOLED.clearDisplay();                            // Clear display buffer.
  myOLED.setTextSize(1);
  myOLED.setTextColor(WHITE);
  myOLED.setCursor(0, 0);
  myOLED.print("MANUAL");
  myOLED.setCursor(0, 10);
  myOLED.print("MILL");
  myOLED.setCursor(0, 20);
  myOLED.print("CONTROLLER");
  myOLED.setCursor(0, 30);
  myOLED.print("v1.0");
  myOLED.setCursor(0, 40);
  myOLED.print("BY IRON-DAN");
  myOLED.display();
  delay(3000);
  myOLED.clearDisplay();                            // Clear display buffer.
  myOLED.setTextSize(2);
}

void updateDisplay()
{
  int xPosSpeedA;
  int xPosSpeedXYZ;

  if ((currentSpeedA / 10) >= 0 && (currentSpeedA / 10) <= 9)
  {
    xPosSpeedA = 46 + 36;
  }
  else if ((currentSpeedA / 10) >= 10 && (currentSpeedA / 10) <= 99)
  {
    xPosSpeedA = 46 + 24;
  }
  else if ((currentSpeedA / 10) >= 100 && (currentSpeedA / 10) <= 999)
  {
    xPosSpeedA = 46 + 12;
  }
  else if ((currentSpeedA / 10) >= 1000)
  {
    xPosSpeedA = 46;
  }

  if ((currentSpeedXYZ / 10) >= 0 && (currentSpeedXYZ / 10) <= 9)
  {
    xPosSpeedXYZ = 46 + 36;
  }
  else if ((currentSpeedXYZ / 10) >= 10 && (currentSpeedXYZ / 10) <= 99)
  {
    xPosSpeedXYZ = 46 + 24;
  }
  else if ((currentSpeedXYZ / 10) >= 100 && (currentSpeedXYZ / 10) <= 999)
  {
    xPosSpeedXYZ = 46 + 12;
  }
  else if ((currentSpeedXYZ / 10) >= 1000)
  {
    xPosSpeedXYZ = 46;
  }

  myOLED.clearDisplay();                            // Clear display buffer.
  myOLED.drawRect(0, 0, 128, 20, WHITE);
  myOLED.drawLine(39, 0, 39, 19, WHITE);
  myOLED.fillRect(96, 15, 2, 2, WHITE);
  myOLED.drawRect(0, 30, 128, 20, WHITE);
  myOLED.drawLine(39, 30, 39, 49, WHITE);
  myOLED.fillRect(96, 45, 2, 2, WHITE);
  myOLED.setCursor(3, 3);
  myOLED.print("XYZ");
  myOLED.setCursor(xPosSpeedXYZ, 3);
  myOLED.print(currentSpeedXYZ / 10);
  myOLED.setCursor(103, 3);
  myOLED.print(currentSpeedXYZ % 10);
  myOLED.setCursor(3, 33);
  myOLED.print("A");
  myOLED.setCursor(xPosSpeedA, 33);
  myOLED.print(currentSpeedA / 10);
  myOLED.setCursor(103, 33);
  myOLED.print(currentSpeedA % 10);
  myOLED.display();
  delay(100);

}

void readRapidButtonA()
{
  if (!digitalRead(rapidButtonA))
  {
    currentMillisRapidButtonA = millis();
    if (currentMillisRapidButtonA - previousMillisRapidButtonA > 200)             // Push button debouncing.
    {
      stateRapidModeA = !stateRapidModeA;           // Toggle stateRapidModeA when rapidButtonA was pressed.
      if (stateRapidModeA)
      {
        digitalWrite(rapidLEDA, HIGH);
        oldSpeedA = currentSpeedA;                  // Store previous speed for A-Axis.
        currentSpeedA = maxSpeedA;                  // Set max speed for A-Axis.
        setSpeedA();
      }
      else
      {
        digitalWrite(rapidLEDA, LOW);
        currentSpeedA = oldSpeedA;                  // Restore speed value before rapid traverse mode was entered.
        setSpeedA();
      }
    }
    previousMillisRapidButtonA = currentMillisRapidButtonA;
  }
}

void readRapidButtonXYZ()
{
  if (!digitalRead(rapidButtonXYZ))
  {
    currentMillisRapidButtonXYZ = millis();
    if (currentMillisRapidButtonXYZ - previousMillisRapidButtonXYZ > 200)         // Push button debouncing.
    {
      stateRapidModeXYZ = !stateRapidModeXYZ;       // Toggle stateRapidModeXYZ when rapidButtonXYZ was pressed.
      if (stateRapidModeXYZ)
      {
        digitalWrite(rapidLEDXYZ, HIGH);
        oldSpeedXYZ = currentSpeedXYZ;              // Store previous speed for XYZ-Axis.
        currentSpeedXYZ = maxSpeedXYZ;              // Set max speed for XYZ-Axis.
        setSpeedXYZ();
      }
      else
      {
        digitalWrite(rapidLEDXYZ, LOW);
        currentSpeedXYZ = oldSpeedXYZ;              // Restore speed value before rapid traverse mode was entered.
        setSpeedXYZ();
      }
    }
    previousMillisRapidButtonXYZ = currentMillisRapidButtonXYZ;
  }
}

void readMinusButtonA()
{
  if (!digitalRead(minusButtonA))
  {
    previousMillisMinusButtonA = millis();          // Store first time value when MinusButtonA was clicked.

    while (!digitalRead(minusButtonA))
    {
      currentMillisMinusButtonA = millis();         // Update time value as long as MinusButtonA is held.
      if (currentMillisMinusButtonA - previousMillisMinusButtonA > 50 && currentMillisMinusButtonA - previousMillisMinusButtonA <= 1000)
      {
        if (currentSpeedA >= 1)
        {
          currentSpeedA -= 1;
        }
        updateDisplay();
        setSpeedA();
      }
      else if (currentMillisMinusButtonA - previousMillisMinusButtonA > 1000 && currentMillisMinusButtonA - previousMillisMinusButtonA <= 5000)
      {
        if (currentSpeedA >= 5)
        {
          currentSpeedA -= 5;
        }
        updateDisplay();
        setSpeedA();
      }
      else if (currentMillisMinusButtonA - previousMillisMinusButtonA > 5000)
      {
        if (currentSpeedA >= 10)
        {
          currentSpeedA -= 10;
        }
        updateDisplay();
        setSpeedA();
      }
    }
  }
}

void readPlusButtonA()
{
  if (!digitalRead(plusButtonA))
  {
    previousMillisPlusButtonA = millis();           // Store first time value when PlusButtonA was clicked.

    while (!digitalRead(plusButtonA))
    {
      currentMillisPlusButtonA = millis();          // Update time value as long as PlusButtonA is held.
      if (currentMillisPlusButtonA - previousMillisPlusButtonA > 50 && currentMillisPlusButtonA - previousMillisPlusButtonA <= 1000)
      {
        if (currentSpeedA <= (maxSpeedA - 1))
        {
          currentSpeedA += 1;
        }
        updateDisplay();
        setSpeedA();
      }
      else if (currentMillisPlusButtonA - previousMillisPlusButtonA > 1000 && currentMillisPlusButtonA - previousMillisPlusButtonA <= 5000)
      {
        if (currentSpeedA <= (maxSpeedA - 5))
        {
          currentSpeedA += 5;
        }
        updateDisplay();
        setSpeedA();
      }
      else if (currentMillisPlusButtonA - previousMillisPlusButtonA > 5000)
      {
        if (currentSpeedA <= (maxSpeedA - 10))
        {
          currentSpeedA += 10;
        }
        updateDisplay();
        setSpeedA();
      }
    }
  }
}
void readMinusButtonXYZ()
{
  if (!digitalRead(minusButtonXYZ))
  {
    previousMillisMinusButtonXYZ = millis();        // Store first time value when MinusButtonXYZ was clicked.

    while (!digitalRead(minusButtonXYZ))
    {
      currentMillisMinusButtonXYZ = millis();       // Update time value as long as MinusButtonXYZ is held.
      if (currentMillisMinusButtonXYZ - previousMillisMinusButtonXYZ > 50 && currentMillisMinusButtonXYZ - previousMillisMinusButtonXYZ <= 1000)
      {
        if (currentSpeedXYZ >= 1)
        {
          currentSpeedXYZ -= 1;
        }
        updateDisplay();
        setSpeedXYZ();
      }
      else if (currentMillisMinusButtonXYZ - previousMillisMinusButtonXYZ > 1000 && currentMillisMinusButtonXYZ - previousMillisMinusButtonXYZ <= 5000)
      {
        if (currentSpeedXYZ >= 5)
        {
          currentSpeedXYZ -= 5;
        }
        updateDisplay();
        setSpeedXYZ();
      }
      else if (currentMillisMinusButtonXYZ - previousMillisMinusButtonXYZ > 5000 && currentMillisMinusButtonXYZ - previousMillisMinusButtonXYZ <= 10000)
      {
        if (currentSpeedXYZ >= 10)
        {
          currentSpeedXYZ -= 10;
        }
        updateDisplay();
        setSpeedXYZ();
      }
      else if (currentMillisMinusButtonXYZ - previousMillisMinusButtonXYZ > 10000)
      {
        if (currentSpeedXYZ >= 100)
        {
          currentSpeedXYZ -= 100;
        }
        updateDisplay();
        setSpeedXYZ();
      }
    }
  }
}

void readPlusButtonXYZ()
{
  if (!digitalRead(plusButtonXYZ))
  {
    previousMillisPlusButtonXYZ = millis();         // Store first time value when PlusButtonXYZ was clicked.

    while (!digitalRead(plusButtonXYZ))
    {
      currentMillisPlusButtonXYZ = millis();        // Update time value as long as PlusButtonXYZ is held.
      if (currentMillisPlusButtonXYZ - previousMillisPlusButtonXYZ > 50 && currentMillisPlusButtonXYZ - previousMillisPlusButtonXYZ <= 1000)
      {
        if (currentSpeedXYZ <= (maxSpeedXYZ - 1))
        {
          currentSpeedXYZ += 1;
        }
        updateDisplay();
        setSpeedXYZ();
      }
      else if (currentMillisPlusButtonXYZ - previousMillisPlusButtonXYZ > 1000 && currentMillisPlusButtonXYZ - previousMillisPlusButtonXYZ <= 5000)
      {
        if (currentSpeedXYZ <= (maxSpeedXYZ - 5))
        {
          currentSpeedXYZ += 5;
        }
        updateDisplay();
        setSpeedXYZ();
      }
      else if (currentMillisPlusButtonXYZ - previousMillisPlusButtonXYZ > 5000 && currentMillisPlusButtonXYZ - previousMillisPlusButtonXYZ <= 10000)
      {
        if (currentSpeedXYZ <= (maxSpeedXYZ - 10))
        {
          currentSpeedXYZ += 10;
        }
        updateDisplay();
        setSpeedXYZ();
      }
      else if (currentMillisPlusButtonXYZ - previousMillisPlusButtonXYZ > 10000)
      {
        if (currentSpeedXYZ <= (maxSpeedXYZ - 100))
        {
          currentSpeedXYZ += 100;
        }
        updateDisplay();
        setSpeedXYZ();
      }
    }
  }
}

void setSpeedA()
{
  if (currentSpeedA >= 1)
  {
    frequencyA = (currentSpeedA * microStepsA * motorStepsA * turnsPerRoundA) / (60 * 10);
    pulseA.play(frequencyA);
  }
  else
  {
    pulseA.stop();
  }
}

void setSpeedXYZ()
{
  if (currentSpeedXYZ >= 10)
  {
    frequencyXYZ = (currentSpeedXYZ * microStepsXYZ * motorStepsXYZ) / (60 * mmPerRoundXYZ * 10);
    pulseXYZ.play(frequencyXYZ);
  }
  else
  {
    pulseXYZ.stop();
  }
}

MobaTools:

  • void myStepper.rotate( int direction );
    Der Motor dreht bis zum nächsten Stop-Befehl.( 1= forwarts, -1 = rückwarts )

Zur Anzeige schau Dir mal U8g2 von OliKraus an, dann flackert auch die Anzeige nicht (Dein nächstes Problem :slightly_smiling_face: ).

Hallo agmue,

danke für deinen Beitrag.

Die Lib schaue ich gerne mal an.

Sie flackert ja nicht, sie zeigt nur Pixel an wo keine hingehören. :slight_smile:
Ich habe mir die U8g2 schon angeschaut, die benötigt aber sehr viel Speicher, schon beim Hello World-Beispiel hat der Compiler gemeldet, dass mein Speicher voll ist. :frowning:

Viele Grüße
Dan

Wird kommen, wenn Du die Anzeige änderst.

Es gibt Möglichkeiten zum Sparen:

/*
  HelloWorld.ino

  Universal 8bit Graphics Library (https://github.com/olikraus/u8g2/)

  Copyright (c) 2016, olikraus@gmail.com
  All rights reserved.

  U8g2lib Example Overview:
    Frame Buffer Examples: clearBuffer/sendBuffer. Fast, but may not work with all Arduino boards because of RAM consumption
    Page Buffer Examples: firstPage/nextPage. Less RAM usage, should work with all Arduino boards.
    U8x8 Text Only Example: No RAM usage, direct communication with display controller. No graphics, 8x8 Text only.
    
  This is a page buffer example.    
*/

#include <Arduino.h>
#include <U8g2lib.h>
#include <Wire.h>
// Please UNCOMMENT one of the contructor lines below
// U8g2 Contructor List (Picture Loop Page Buffer)
// The complete list is available here: https://github.com/olikraus/u8g2/wiki/u8g2setupcpp
// Please update the pin numbers according to your setup. Use U8X8_PIN_NONE if the reset pin is not connected
U8G2_SH1106_128X64_NONAME_1_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);
//U8G2_SH1106_128X64_VCOMH0_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);    // same as the NONAME variant, but maximizes setContrast() range
//U8G2_SH1106_128X64_WINSTAR_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);   // same as the NONAME variant, but uses updated SH1106 init sequence
//U8G2_SH1106_128X32_VISIONOX_1_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE); 
//U8G2_SH1106_128X32_VISIONOX_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
//U8G2_SH1106_72X40_WISE_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);

void setup(void) {
  u8g2.begin();  
}

void loop(void) {
  u8g2.firstPage();
  do {
    u8g2.setFont(u8g2_font_VCR_OSD_mu);
    u8g2.drawStr(0,24,"XYZ  00:00");
  } while ( u8g2.nextPage() );
  delay(1000);
}
Der Sketch verwendet 9466 Bytes (29%) des Programmspeicherplatzes. Das Maximum sind 32256 Bytes.
Globale Variablen verwenden 650 Bytes (31%) des dynamischen Speichers, 1398 Bytes für lokale Variablen verbleiben. Das Maximum sind 2048 Bytes.

Oli hat viele praxisnahe Möglichkeiten eingebaut.

Hallo agmue,

ich habe die u8g2-Lib jetzt ertsmal im Full Buffer- Modus ausprobiert und sie scheint da gar nicht so viel Speicher zu benötigen.

Der Sketch verwendet 18134 Bytes (59%) des Programmspeicherplatzes. Das Maximum sind 30720 Bytes.
Globale Variablen verwenden 762 Bytes (37%) des dynamischen Speichers, 1286 Bytes für lokale Variablen verbleiben. Das Maximum sind 2048 Bytes.

Aber irgendetwas mache ich noch falsch, denn mir wird nur der obere Teil des Displays angezeigt.
Weißt du woran das liegen könnte?

Die Beispiele im Full Buffer-Modus benötigen zwar viel Speicher, werden aber korrekt angezeigt.

Danke und Grüße
Dan

/*  
  Manual Mill Controller v1.0
  written by Iron-Dan
  Creates stepper pulses to set speeds in mm/min and rpm and included rapid traverse mode.
  Implemented with the usage of the libraries which are included below.
*/

/*
  Universal 8bit Graphics Library (https://github.com/olikraus/OLED/)

  Copyright (c) 2016, olikraus@gmail.com
  All rights reserved.

  Redistribution and use in source and binary forms, with or without modification, 
  are permitted provided that the following conditions are met:

  * Redistributions of source code must retain the above copyright notice, this list 
    of conditions and the following disclaimer.
    
  * Redistributions in binary form must reproduce the above copyright notice, this 
    list of conditions and the following disclaimer in the documentation and/or other 
    materials provided with the distribution.
*/

#include <Arduino.h>
#include <U8g2lib.h>

#ifdef U8X8_HAVE_HW_SPI
#include <SPI.h>
#endif
#ifdef U8X8_HAVE_HW_I2C
#include <Wire.h>
#endif

// Please UNCOMMENT one of the contructor lines below
// OLED Contructor List (Picture Loop Page Buffer)
// The complete list is available here: https://github.com/olikraus/OLED/wiki/OLEDsetupcpp
// Please update the pin numbers according to your setup. Use U8X8_PIN_NONE if the reset pin is not connected

U8G2_SH1106_128X64_NONAME_1_HW_I2C OLED(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);

#include <Tone.h>

// Variables

const byte minusButtonA = 8;                        // Minus Button for speed value on A-Axis at Arduino Pin 10.
const byte plusButtonA = 7;                         // Plus Button for speed value on A-Axis at Arduino Pin 9.
const byte rapidButtonA = 2;                        // Button for rapid traverse mode on A-Axis at Arduino Pin 2.
const byte rapidLEDA = 11;                          // LED for indication of rapid traverse mode on A-Axis at Arduino Pin 11.
byte stateRapidModeA = LOW;                         // State of rapid traverse mode on A-Axis.
const unsigned long maxSpeedA = 136;                // Max. speed / 10 = speed in rpm. 136 = 65280Hz -> max. 65535Hz!
unsigned long currentSpeedA = 0;                    // Current speed in rpm.
unsigned long oldSpeedA = 0;                        // Old speed in rpm.

const byte minusButtonXYZ = 10;                     // Minus Button for speed value on XYZ-Axis at Arduino Pin 8.
const byte plusButtonXYZ = 9;                       // Plus Button for speed value on XYZ-Axis at Arduino Pin 7.
const byte rapidButtonXYZ = 3;                      // Button for rapid traverse mode on XYZ-Axis at Arduino Pin 3.
const byte rapidLEDXYZ = 12;                        // LED for indication of rapid traverse mode on XYZ-Axis at Arduino Pin 12.
byte stateRapidModeXYZ = LOW;                       // State of rapid traverse mode on XYZ-Axis.
const unsigned long maxSpeedXYZ = 20000;            // Max. speed / 10 = speed in mm/min.
unsigned long currentSpeedXYZ = 0;                  // Current speed in mm/min.
unsigned long oldSpeedXYZ = 0;                      // Old speed in mm/min.

// Timer variables

unsigned long previousMillisRapidButtonA = 0;       // Time value in ms when rapidButtonA was pressed last time.
unsigned long currentMillisRapidButtonA;            // New time value in ms when rapidButtonA was pressed.
unsigned long previousMillisMinusButtonA = 0;       // Store time in ms as MinusButtonA was clicked first time.
unsigned long currentMillisMinusButtonA = 0;        // Store time value as long as MinusButtonA is held.
unsigned long previousMillisPlusButtonA = 0;        // Store time in ms as PlusButtonA was clicked first time.
unsigned long currentMillisPlusButtonA = 0;         // Store time value as long as PlusButtonA is held.

unsigned long previousMillisRapidButtonXYZ = 0;     // Time value in ms when rapidButtonXYZ was pressed last time.
unsigned long currentMillisRapidButtonXYZ;          // New time value in ms when rapidButtonXYZ was pressed.
unsigned long previousMillisMinusButtonXYZ = 0;     // Store time in ms as MinusButtonXYZ was clicked first time.
unsigned long currentMillisMinusButtonXYZ = 0;      // Store time value as long as MinusButtonXYZ is held.
unsigned long previousMillisPlusButtonXYZ = 0;      // Store time in ms as PlusButtonXYZ was clicked first time.
unsigned long currentMillisPlusButtonXYZ = 0;       // Store time value as long as PlusButtonXYZ is held.

// Stepper variables

unsigned int microStepsA = 16;
unsigned int motorStepsA = 200;
unsigned int turnsPerRoundA = 90;
unsigned int microStepsXYZ = 16;
unsigned int motorStepsXYZ = 200;
unsigned int mmPerRoundXYZ = 5;
unsigned int frequencyA = 0;
unsigned int frequencyXYZ = 0;

Tone pulseA;                                        // Create Tone object pulseA.
Tone pulseXYZ;                                      // Create Tone object pulseXYZ.

// Setup

void setup() {
  pinMode(minusButtonA, INPUT_PULLUP);
  pinMode(plusButtonA, INPUT_PULLUP);
  pinMode(rapidButtonA, INPUT_PULLUP);
  pinMode(minusButtonXYZ, INPUT_PULLUP);
  pinMode(plusButtonXYZ, INPUT_PULLUP);
  pinMode(rapidButtonXYZ, INPUT_PULLUP);
  pinMode(rapidLEDA, OUTPUT);
  pinMode(rapidLEDXYZ, OUTPUT);

  pulseA.begin(5);                                  // Init stepper pulses for A-Axis at Arduino Pin 5.
  pulseXYZ.begin(6);                                // Init stepper pulses for XYZ-Axis at Arduino Pin 6.

  OLED.begin();                                     // Init the OLED.  
  bootScreen();                                     // Show Boot Screen

}

void loop() {

  readRapidButtonA();
  readRapidButtonXYZ();
  readMinusButtonA();
  readPlusButtonA();
  readMinusButtonXYZ();
  readPlusButtonXYZ();

  printDisplay();

}

void bootScreen()
{ 
  OLED.clearBuffer();
  OLED.setFont(u8g2_font_profont22_mf);
  OLED.drawStr(0, 15, "MANUAL");
  OLED.drawStr(0, 25, "MILL");
  OLED.drawStr(0, 35, "CONTROLLER");
  OLED.drawStr(0, 45, "v1.0");
  OLED.drawStr(0, 55, "BY IRON-DAN");
  OLED.sendBuffer();
  delay(3000);  
}

void printDisplay()
{
  int xPosSpeedA;
  int xPosSpeedXYZ;

  if ((currentSpeedA / 10) >= 0 && (currentSpeedA / 10) <= 9)
  {
    xPosSpeedA = 46 + 36;
  }
  else if ((currentSpeedA / 10) >= 10 && (currentSpeedA / 10) <= 99)
  {
    xPosSpeedA = 46 + 24;
  }
  else if ((currentSpeedA / 10) >= 100 && (currentSpeedA / 10) <= 999)
  {
    xPosSpeedA = 46 + 12;
  }
  else if ((currentSpeedA / 10) >= 1000)
  {
    xPosSpeedA = 46;
  }

  if ((currentSpeedXYZ / 10) >= 0 && (currentSpeedXYZ / 10) <= 9)
  {
    xPosSpeedXYZ = 46 + 36;
  }
  else if ((currentSpeedXYZ / 10) >= 10 && (currentSpeedXYZ / 10) <= 99)
  {
    xPosSpeedXYZ = 46 + 24;
  }
  else if ((currentSpeedXYZ / 10) >= 100 && (currentSpeedXYZ / 10) <= 999)
  {
    xPosSpeedXYZ = 46 + 12;
  }
  else if ((currentSpeedXYZ / 10) >= 1000)
  {
    xPosSpeedXYZ = 46;
  }

  OLED.clearBuffer();                            // Clear display buffer.
  OLED.drawFrame(0, 0, 128, 20);
  OLED.drawLine(39, 0, 39, 19);
  OLED.drawBox(96, 15, 2, 2);
  OLED.drawFrame(0, 30, 128, 20);
  OLED.drawLine(39, 30, 39, 49);
  OLED.drawBox(96, 45, 2, 2);
  OLED.setCursor(3, 18);
  OLED.print("XYZ");
  OLED.setCursor(xPosSpeedXYZ, 18);
  OLED.print(currentSpeedXYZ / 10);
  OLED.setCursor(103, 18);
  OLED.print(currentSpeedXYZ % 10);
  OLED.setCursor(3, 48);
  OLED.print("A");
  OLED.setCursor(xPosSpeedA, 48);
  OLED.print(currentSpeedA / 10);
  OLED.setCursor(103, 48);
  OLED.print(currentSpeedA % 10);
  OLED.sendBuffer();
  delay(100);

}

void readRapidButtonA()
{
  if (!digitalRead(rapidButtonA))
  {
    currentMillisRapidButtonA = millis();
    if (currentMillisRapidButtonA - previousMillisRapidButtonA > 200)             // Push button debouncing.
    {
      stateRapidModeA = !stateRapidModeA;           // Toggle stateRapidModeA when rapidButtonA was pressed.
      if (stateRapidModeA)
      {
        digitalWrite(rapidLEDA, HIGH);
        oldSpeedA = currentSpeedA;                  // Store previous speed for A-Axis.
        currentSpeedA = maxSpeedA;                  // Set max speed for A-Axis.
        setSpeedA();
      }
      else
      {
        digitalWrite(rapidLEDA, LOW);
        currentSpeedA = oldSpeedA;                  // Restore speed value before rapid traverse mode was entered.
        setSpeedA();
      }
    }
    previousMillisRapidButtonA = currentMillisRapidButtonA;
  }
}

void readRapidButtonXYZ()
{
  if (!digitalRead(rapidButtonXYZ))
  {
    currentMillisRapidButtonXYZ = millis();
    if (currentMillisRapidButtonXYZ - previousMillisRapidButtonXYZ > 200)         // Push button debouncing.
    {
      stateRapidModeXYZ = !stateRapidModeXYZ;       // Toggle stateRapidModeXYZ when rapidButtonXYZ was pressed.
      if (stateRapidModeXYZ)
      {
        digitalWrite(rapidLEDXYZ, HIGH);
        oldSpeedXYZ = currentSpeedXYZ;              // Store previous speed for XYZ-Axis.
        currentSpeedXYZ = maxSpeedXYZ;              // Set max speed for XYZ-Axis.
        setSpeedXYZ();
      }
      else
      {
        digitalWrite(rapidLEDXYZ, LOW);
        currentSpeedXYZ = oldSpeedXYZ;              // Restore speed value before rapid traverse mode was entered.
        setSpeedXYZ();
      }
    }
    previousMillisRapidButtonXYZ = currentMillisRapidButtonXYZ;
  }
}

void readMinusButtonA()
{
  if (!digitalRead(minusButtonA))
  {
    previousMillisMinusButtonA = millis();          // Store first time value when MinusButtonA was clicked.

    while (!digitalRead(minusButtonA))
    {
      currentMillisMinusButtonA = millis();         // Update time value as long as MinusButtonA is held.
      if (currentMillisMinusButtonA - previousMillisMinusButtonA > 50 && currentMillisMinusButtonA - previousMillisMinusButtonA <= 1000)
      {
        if (currentSpeedA >= 1)
        {
          currentSpeedA -= 1;
        }
        printDisplay();
        setSpeedA();
      }
      else if (currentMillisMinusButtonA - previousMillisMinusButtonA > 1000 && currentMillisMinusButtonA - previousMillisMinusButtonA <= 5000)
      {
        if (currentSpeedA >= 5)
        {
          currentSpeedA -= 5;
        }
        printDisplay();
        setSpeedA();
      }
      else if (currentMillisMinusButtonA - previousMillisMinusButtonA > 5000)
      {
        if (currentSpeedA >= 10)
        {
          currentSpeedA -= 10;
        }
        printDisplay();
        setSpeedA();
      }
    }
  }
}

void readPlusButtonA()
{
  if (!digitalRead(plusButtonA))
  {
    previousMillisPlusButtonA = millis();           // Store first time value when PlusButtonA was clicked.

    while (!digitalRead(plusButtonA))
    {
      currentMillisPlusButtonA = millis();          // Update time value as long as PlusButtonA is held.
      if (currentMillisPlusButtonA - previousMillisPlusButtonA > 50 && currentMillisPlusButtonA - previousMillisPlusButtonA <= 1000)
      {
        if (currentSpeedA <= (maxSpeedA - 1))
        {
          currentSpeedA += 1;
        }
        printDisplay();
        setSpeedA();
      }
      else if (currentMillisPlusButtonA - previousMillisPlusButtonA > 1000 && currentMillisPlusButtonA - previousMillisPlusButtonA <= 5000)
      {
        if (currentSpeedA <= (maxSpeedA - 5))
        {
          currentSpeedA += 5;
        }
        printDisplay();
        setSpeedA();
      }
      else if (currentMillisPlusButtonA - previousMillisPlusButtonA > 5000)
      {
        if (currentSpeedA <= (maxSpeedA - 10))
        {
          currentSpeedA += 10;
        }
        printDisplay();
        setSpeedA();
      }
    }
  }
}
void readMinusButtonXYZ()
{
  if (!digitalRead(minusButtonXYZ))
  {
    previousMillisMinusButtonXYZ = millis();        // Store first time value when MinusButtonXYZ was clicked.

    while (!digitalRead(minusButtonXYZ))
    {
      currentMillisMinusButtonXYZ = millis();       // Update time value as long as MinusButtonXYZ is held.
      if (currentMillisMinusButtonXYZ - previousMillisMinusButtonXYZ > 50 && currentMillisMinusButtonXYZ - previousMillisMinusButtonXYZ <= 1000)
      {
        if (currentSpeedXYZ >= 1)
        {
          currentSpeedXYZ -= 1;
        }
        printDisplay();
        setSpeedXYZ();
      }
      else if (currentMillisMinusButtonXYZ - previousMillisMinusButtonXYZ > 1000 && currentMillisMinusButtonXYZ - previousMillisMinusButtonXYZ <= 5000)
      {
        if (currentSpeedXYZ >= 5)
        {
          currentSpeedXYZ -= 5;
        }
        printDisplay();
        setSpeedXYZ();
      }
      else if (currentMillisMinusButtonXYZ - previousMillisMinusButtonXYZ > 5000 && currentMillisMinusButtonXYZ - previousMillisMinusButtonXYZ <= 10000)
      {
        if (currentSpeedXYZ >= 10)
        {
          currentSpeedXYZ -= 10;
        }
        printDisplay();
        setSpeedXYZ();
      }
      else if (currentMillisMinusButtonXYZ - previousMillisMinusButtonXYZ > 10000)
      {
        if (currentSpeedXYZ >= 100)
        {
          currentSpeedXYZ -= 100;
        }
        printDisplay();
        setSpeedXYZ();
      }
    }
  }
}

void readPlusButtonXYZ()
{
  if (!digitalRead(plusButtonXYZ))
  {
    previousMillisPlusButtonXYZ = millis();         // Store first time value when PlusButtonXYZ was clicked.

    while (!digitalRead(plusButtonXYZ))
    {
      currentMillisPlusButtonXYZ = millis();        // Update time value as long as PlusButtonXYZ is held.
      if (currentMillisPlusButtonXYZ - previousMillisPlusButtonXYZ > 50 && currentMillisPlusButtonXYZ - previousMillisPlusButtonXYZ <= 1000)
      {
        if (currentSpeedXYZ <= (maxSpeedXYZ - 1))
        {
          currentSpeedXYZ += 1;
        }
        printDisplay();
        setSpeedXYZ();
      }
      else if (currentMillisPlusButtonXYZ - previousMillisPlusButtonXYZ > 1000 && currentMillisPlusButtonXYZ - previousMillisPlusButtonXYZ <= 5000)
      {
        if (currentSpeedXYZ <= (maxSpeedXYZ - 5))
        {
          currentSpeedXYZ += 5;
        }
        printDisplay();
        setSpeedXYZ();
      }
      else if (currentMillisPlusButtonXYZ - previousMillisPlusButtonXYZ > 5000 && currentMillisPlusButtonXYZ - previousMillisPlusButtonXYZ <= 10000)
      {
        if (currentSpeedXYZ <= (maxSpeedXYZ - 10))
        {
          currentSpeedXYZ += 10;
        }
        printDisplay();
        setSpeedXYZ();
      }
      else if (currentMillisPlusButtonXYZ - previousMillisPlusButtonXYZ > 10000)
      {
        if (currentSpeedXYZ <= (maxSpeedXYZ - 100))
        {
          currentSpeedXYZ += 100;
        }
        printDisplay();
        setSpeedXYZ();
      }
    }
  }
}

void setSpeedA()
{
  if (currentSpeedA >= 1)
  {
    frequencyA = (currentSpeedA * microStepsA * motorStepsA * turnsPerRoundA) / (60 * 10);
    pulseA.play(frequencyA);
  }
  else
  {
    pulseA.stop();
  }
}

void setSpeedXYZ()
{
  if (currentSpeedXYZ >= 10)
  {
    frequencyXYZ = (currentSpeedXYZ * microStepsXYZ * motorStepsXYZ) / (60 * mmPerRoundXYZ * 10);
    pulseXYZ.play(frequencyXYZ);
  }
  else
  {
    pulseXYZ.stop();
  }
}

Versuch es mal so:

void bootScreen()
{ 
  OLED.setFont(u8g2_font_profont15_tr);
  
  OLED.firstPage();
  do {
  OLED.drawStr(0, 10, "MANUAL");
  OLED.drawStr(0, 23, "MILL");
  OLED.drawStr(0, 36, "CONTROLLER");
  OLED.drawStr(0, 49, "v1.0");
  OLED.drawStr(0, 62, "BY IRON-DAN");
  } while ( OLED.nextPage() );
  delay(3000);  
}

void printDisplay()
{
  int xPosSpeedA;
  int xPosSpeedXYZ;

  if ((currentSpeedA / 10) >= 0 && (currentSpeedA / 10) <= 9)
  {
    xPosSpeedA = 46 + 36;
  }
  else if ((currentSpeedA / 10) >= 10 && (currentSpeedA / 10) <= 99)
  {
    xPosSpeedA = 46 + 24;
  }
  else if ((currentSpeedA / 10) >= 100 && (currentSpeedA / 10) <= 999)
  {
    xPosSpeedA = 46 + 12;
  }
  else if ((currentSpeedA / 10) >= 1000)
  {
    xPosSpeedA = 46;
  }

  if ((currentSpeedXYZ / 10) >= 0 && (currentSpeedXYZ / 10) <= 9)
  {
    xPosSpeedXYZ = 46 + 36;
  }
  else if ((currentSpeedXYZ / 10) >= 10 && (currentSpeedXYZ / 10) <= 99)
  {
    xPosSpeedXYZ = 46 + 24;
  }
  else if ((currentSpeedXYZ / 10) >= 100 && (currentSpeedXYZ / 10) <= 999)
  {
    xPosSpeedXYZ = 46 + 12;
  }
  else if ((currentSpeedXYZ / 10) >= 1000)
  {
    xPosSpeedXYZ = 46;
  }

  OLED.setFont(u8g2_font_profont22_mr);
  OLED.firstPage();
  do {
  OLED.setCursor(3, 18);
  OLED.print("XYZ");
  OLED.setCursor(xPosSpeedXYZ, 18);
  OLED.print(currentSpeedXYZ / 10);
  OLED.setCursor(103, 18);
  OLED.print(currentSpeedXYZ % 10);
  OLED.setCursor(3, 48);
  OLED.print("A");
  OLED.setCursor(xPosSpeedA, 48);
  OLED.print(currentSpeedA / 10);
  OLED.setCursor(103, 48);
  OLED.print(currentSpeedA % 10);
  OLED.drawFrame(0, 0, 128, 20);
  OLED.drawLine(39, 0, 39, 19);
  OLED.drawBox(96, 15, 2, 2);
  OLED.drawFrame(0, 30, 128, 20);
  OLED.drawLine(39, 30, 39, 49);
  OLED.drawBox(96, 45, 2, 2);
  } while ( OLED.nextPage() );
  delay(100);
}

Ich bekomme Warnungen:

In function 'void printDisplay()':
143:28: warning: comparison of unsigned expression >= 0 is always true [-Wtype-limits]
   if ((currentSpeedA / 10) >= 0 && (currentSpeedA / 10) <= 9)
       ~~~~~~~~~~~~~~~~~~~~~^~~~
160:30: warning: comparison of unsigned expression >= 0 is always true [-Wtype-limits]
   if ((currentSpeedXYZ / 10) >= 0 && (currentSpeedXYZ / 10) <= 9)
       ~~~~~~~~~~~~~~~~~~~~~~~^~~~

Jetzt noch tone raus und MobaTools rein :slightly_smiling_face:

Du prüfst etwas, was immer wahr ist. Daher ist die Prüfung nicht notwendig.

‚currentSpeedXYZ‘ bzw. ‚currentSpeedA‘ sind bei dir als Variable ohne Vorzeichen deklariert (unsigned). Ohne Vorzeichen hat eine Variable immer den Wert >= 0. Und somit immer Wahr. Also ist der Vergleich

(currentSpeedA / 10) >= 0 

bzw.


(currentSpeedXYZ / 10) >= 0 

immer wahr und somit unnötig.

Das wird bei den von ihm angestrebten Stepraten ( >80kHz! ) nicht funktionieren.

Danke für den Hinweis, daran habe ich gar nicht gedacht!

Danke, so zeigt das Display die Informationen zumindest mal korrekt an.
Aber mir ist aufgefallen, dass wenn ich die Taster zum Einstellen der Geschwindigkeit lange gedrückt halte um einen hohen Wert einzustellen, dass das Display dann etwas hinterherhinkt.
Also wenn ich den Taster loslasse dauert es noch ca. 1 Sekunde bis der endgültige Wert angezeigt wird. Oder wenn ich zwischendrin den Eilgangtaster betätige wird der Wert auch erst 1 Sekunde später angezeigt.
Kann das am Displaytreiber liegen? :thinking:

Ich werde wahrscheinlich mit den Microsteps auf 8 runtergehen, das ist aber immernoch zu schnell für MobaTools.
Außerdem würde ich das Programm gerne mit Tone.h zum Laufen bekommen und verstehen warum es nicht funktioniert.

Woran könnte es liegen, dass sich der Arduino aufhängt, wenn ich beide Eilgangtaster betätige? :thinking:

Danke schonmal für eure Unterstützung!

Grüße
Dan

Ein Fortschritt :slightly_smiling_face:

Spekulativ eher nicht, da fallen mir eher delay und while negativ auf. Beides ist in Programmen für Bewegungen "verboten". Irritierend finde ich auch den Aufruf von printDisplay(); sowohl in den Funktionen, wie auch in loop(). Das deutet für mich auf ein unglückliches Konzept hin. Bei genauerer Betrachtung gilt dies auch für setSpeedA() und setSpeedXYZ().

Aber ein aktuelles Programm könnte hilfreich sein.

Gibt es eine bessere Möglichkeit abzufragen ob der Taster gedrückt wurde und immer noch gedrückt ist? Bzw. wie kann man die Erhöhung der Zählschritte bei längerer Betätigung des Tasters eleganter lösen?

Wenn ich printDisplay(); nur im Loop aufrufe, wird der aktuell eingestellte Wert erst nach dem Loslassen der Taster sichtbar.
Das gleiche gilt für die Frequenz, also setSpeedA() und setSpeedXYZ();.
Viele Grüße
Dan

Du kannst es selbst programmieren oder bei MobaTools\examples_Buttons\ nachsehen, denn da wird zwischen verschiedenen Zuständen unterschieden.

Das ist eben das unglückliche Konzept mit while.

Du könntest einen Merker setzen zur Auffrischung der Anzeige, worauf die Anzeige aber nur alle 200 ms oder so reagiert. Schneller kannst Du nicht schauen.