Start auf Knopfdruck

Hallo zusammen,

ich habe ein Programm geschrieben, das für eine Linearachse mit Schrittmotor gedacht ist. Der Schlitten soll mit der vorgegebenen Geschwindigkeit von links nach rechts bzw rechts nach links fahren und jeweils am Endschalter stoppen. Nun möchte ich, das die Bewegung von Endschalter zu Endschalter nur dann startet, wenn ich deinen Start-Knopf betätige (Einmaliges drücken, kein dauerhaftes drücken).

Nun bin ich mir jedoch nicht sicher, ob mein Programm das auch so abruft. Ich habe das Programm zusammen mit meinem Vater geschrieben und habe leider selber kaum Programmierkenntnise.

// Einlesen der Accelstepper Library
// Wird benötigt, da spezielle Commands hinterlegt sind
#include <AccelStepper.h>
#include <MultiStepper.h>

//Festlegung der Geschwindigkeiten
const int Speed1 = 50.51; //  Entspricht 1m/min
const int Speed2 = 37.88; //  Entspricht 0,75m/min
const int Speed3 = 25.25; //  Entspricht 0,5m/min
//    Berechnet sich aus:
//    n_Umdrehungen=v_Schlitten/U_Achse       n_Achse=Drehzahl der Achse [1/sec]; U_Achse=66mm; v_Schlitten= Vorschubgeschwindigkeit Schlitten [m/min]
//    st_Achse=n_Umdrehung*st_Umdrehung       st_Achse= Steps pro Sekunde die benötigt wird für die gewünschte Geschwindigkeit; st_Umdrehung= Steps pro Umdrehung (Motor)

//Hier werden die Pins des Arduino zugeordnet
// Eingaenge:
const int Speed1Pin = 2;            // Pin2 wird der Position 1 des Schiebeschalters zugeordnet
const int Speed2Pin = 3;            // Pin3 wird der Position 2 des Schiebeschalters zugeordnet
const int Speed3Pin = 4;            // Pin5 wird der Position 3 des Schiebeschalters zugeordnet
const int StartSwitchPin = 5;       // Pin6 wird dem Startschalter zugeordnet
const int eslPin = 6;               // Pin6 wird dem linken Endlageschalter zugeordnet
const int esrPin = 7;               // Pin7 wird der rechten Endlageschalter zugeordnet

// Ausgaenge:
const int dirPin = 8;               // Pin8 wird dem 'Richtungs-Pin' zugeordnet
const int pulPin = 9;               // Pin9 wird dem 'Schritte-Pin' zugeordnet
const int enblPin = 12;             // Pin12 wird dem Enable zugeordnet


//Aufrufen der AccelStepper Library für die Verwendung eines Schrittmotor
AccelStepper Schrittmotor(1,9,8);   //1 steht für Anbindung an einen Treiber, Schritte-Pin, Richtungs-Pin

//Festlegen des Setups
// EIngänge und Ausgänge festlegen
void setup(){
 //Eingänge:
  pinMode( Speed1Pin, INPUT );
  pinMode( Speed2Pin, INPUT );
  pinMode( Speed3Pin, INPUT );
  pinMode( StartSwitchPin, INPUT );
  pinMode( esrPin, INPUT );
  pinMode( eslPin, INPUT );
  
  Schrittmotor.setEnablePin(enblPin);       // AccelStepper Command zum festlegen des Enable Pin
  
  Schrittmotor.setMaxSpeed(70);             // Maximale Geschwindigkeit in steps pro Sekunde
  Schrittmotor.setSpeed(GetSpeed());        // Festlegen der Geschwindigkeit in Steps pro Sekunde

//Startposition einnehmen  
  Move( 'L' );
}


// Starten des Eigentlichen Hauptprogrammes
void loop() {
	
	char direction = 'R'; // aktuelle Laufrichtung, MUSS nach dem Einehmen der Startpositions 'R' sein
	while( 1 ){
	  Schrittmotor.setSpeed(GetSpeed());       // Möglichkeit zum einstellen der Geschwindigkeit
   	    while( digitalRead(StartSwitchPin) == HIGH ){  delay(50);/* warte auf Start */ }
		Move( direction );                      // Durchfühen der Motorbewerung
		// Am Ende der Bewegung die Richtung wieder umschalten
		if( direction == 'L' ) {
			direction = 'R';
		} else if( direction == 'R' ) {
			direction = 'L';
		}
	}
}

// Motorbewegung
// Ausgehend von der aktuellen Stellung in die angegebene Richtung mit der angegebenen Geschwindigkeit
// Eingänge:
//  char direction: 'L' für links, 'R' für rechts

void Move( char direction )
{
	// Endposition schon erreicht?
	if( GetEndSwitch() == direction ) return;

    Schrittmotor.enableOutputs(enblPin);  // Motor kann laufen

    int speed = GetSpeed();
	
	while( GetEndSwitch() == 'N' ) {
       if( direction == 'L' ) {Schrittmotor.setSpeed(GetSpeed()); Schrittmotor.runSpeed();}       // Wenn sich der Schlittem vom linken Enschalter aus bewegt, laufe nacch rechts
       if( direction == 'R' ) {Schrittmotor.setSpeed(-GetSpeed()); Schrittmotor.runSpeed();}      // Wenn sich der Schlitten vom rechten Endschalter aus bewegt, laufe nach links
	}
	   
	Schrittmotor.disableOutputs(enblPin);  // Motor bleibt stehen
}


// Funktion zum Einlesen der Geschwindigkeit
// Liefert 1, 2, oder 3 für die selektierte Geschwindigkeit
int GetSpeed()
{
  // Es ist immer nur einer der Pins auf LOW (Drehschalter/Schiebeschalter)
  if( digitalRead( Speed1Pin ) == LOW ) return Speed1;  
  if( digitalRead( Speed2Pin ) == LOW ) return Speed2;
  if( digitalRead( Speed3Pin ) == LOW ) return Speed3;
}

// Auslesen der Endschalter
// 'L' wenn linker Endschalter aktiv ist
// 'R' wenn rechter Endschalter aktiv ist
// 'N' wenn kein Endschalter aktiv ist
char GetEndSwitch()
{
	if( digitalRead( eslPin ) == LOW ) return 'L';
    if( digitalRead( esrPin ) == LOW ) return 'R';
	return 'N';
}

Hallo,

das ist nicht euer Hauptproblem. Ihr habt Endlosschleifen "ohne Ende".

loop ist eine und while(1) ebenso. Entscheidet euch lieber für loop.
Wenn irgendwann move (...) aufgerufen wird, ist das fast eine Endlosschleife.
Während das Programm darin verweilt kann es auf nichts anderes reagieren.
Wie wäre es mit einer Reaktion jederzeit auf Not-Aus?

Zur Eingangsfrage. Entprellt einen Taster und toggelt dabei den Zustand einer Bool Variablen. Dann ergibt das eine Schalterfunktion.

Im Grunde wird das auch ein Zustandsautomat. Zustände STOP, START, LINKS, RECHTS
Je nachdem welcher Zustand aktuell ist verzweigt das Programm lässt den Motor laufen oder auch nicht.

Vielen Dank für den Hinweiß.

Wir haben das Programm abgeändert und das mit dem Schalter habe ich glaube ich nun auch verstanden.

Ist das Problem so besser behoben?

// Einlesen der Accelstepper Library
// Wird benötigt, da spezielle Commands hinterlegt sind
#include <AccelStepper.h>
#include <MultiStepper.h>

//Festlegung der Geschwindigkeiten
const int Speed1 = 50; // 50.51;  Entspricht 1m/min
const int Speed2 = 39; // 37.88;  Entspricht 0,75m/min
const int Speed3 = 25; // 25.25;  Entspricht 0,5m/min
//    Berechnet sich aus:
//    n_Umdrehungen=v_Schlitten/U_Achse       n_Achse=Drehzahl der Achse [1/sec]; U_Achse=66mm; v_Schlitten= Vorschubgeschwindigkeit Schlitten [m/min]
//    st_Achse=n_Umdrehung*st_Umdrehung       st_Achse= Steps pro Sekunde die benötigt wird für die gewünschte Geschwindigkeit; st_Umdrehung= Steps pro Umdrehung (Motor)

//Hier werden die Pins des Arduino zugeordnet
// Eingaenge:
const int Speed1Pin = 2;            // Pin2 wird der Position 1 des Schiebeschalters zugeordnet
const int Speed2Pin = 3;            // Pin3 wird der Position 2 des Schiebeschalters zugeordnet
const int Speed3Pin = 4;            // Pin5 wird der Position 3 des Schiebeschalters zugeordnet
const int StartSwitchPin = 5;       // Pin6 wird dem Startschalter zugeordnet
const int eslPin = 6;               // Pin6 wird dem linken Endlageschalter zugeordnet
const int esrPin = 7;               // Pin7 wird der rechten Endlageschalter zugeordnet

// Ausgaenge:
const int dirPin = 8;               // Pin8 wird dem 'Richtungs-Pin' zugeordnet
const int pulPin = 9;               // Pin9 wird dem 'Schritte-Pin' zugeordnet
const int enblPin = 12;             // Pin12 wird dem Enable zugeordnet

char start_direction = 'L';         // In diese Richtung wird gestartet
char direction = 'R';               // Mit dieser Richtung wird nach Einnehmen der Startposition begonnen

//Aufrufen der AccelStepper Library für die Verwendung eines Schrittmotor
AccelStepper Schrittmotor(1,9,8);   //1 steht für Anbindung an einen Treiber, Schritte-Pin, Richtungs-Pin


void setup(){
 // Eingänge und Ausgänge festlegen
 // Eingänge:
  pinMode( Speed1Pin, INPUT_PULLUP );
  pinMode( Speed2Pin, INPUT_PULLUP );
  pinMode( Speed3Pin, INPUT_PULLUP );
  pinMode( StartSwitchPin, INPUT_PULLUP );
  pinMode( esrPin, INPUT_PULLUP );
  pinMode( eslPin, INPUT_PULLUP );
 
  Schrittmotor.setEnablePin(enblPin);       // AccelStepper Command zum festlegen des Enable Pin
 
  Schrittmotor.setMaxSpeed(70);             // Maximale Geschwindigkeit in steps pro Sekunde
  Schrittmotor.setSpeed(GetSpeed());        // Festlegen der Geschwindigkeit in Steps pro Sekunde

   Move( start_direction ); //Startposition einnehmen
}


// Starten des Eigentlichen Hauptprogrammes
void loop() {
    GetStartSignal(); // Taster muss gedrückt und wieder losgelassen werden
	
	Move( direction );                      // Durchfühen der Motorbewerung
	// Am Ende der Bewegung die Richtung wieder umschalten
	if( direction == 'L' ) { 
		direction = 'R';
	} else if( direction == 'R' ) {
		direction = 'L';
	}
}

// Motorbewegung
// Ausgehend von der aktuellen Stellung in die angegebene Richtung mit der angegebenen Geschwindigkeit
// Sobald der zugehörige Endschalter schließt, wird die Bewegung angehalten
// Eingänge:
//  char direction: 'L' für links, 'R' für rechts

void Move( char direction )
{
	// Endposition schon erreicht?
	if( GetEndSwitch() == direction ) return;

    Schrittmotor.enableOutputs(enblPin);  // Motor kann laufen

	// Hier wird der Motor in die Sollrichtung mit Sollgeschwindigkeit gestartet
	if( direction == 'L' ) {Schrittmotor.setSpeed(GetSpeed()); Schrittmotor.runSpeed();}       // Wenn sich der Schlittem vom linken Enschalter aus bewegt, laufe nacch rechts
    if( direction == 'R' ) {Schrittmotor.setSpeed(-GetSpeed()); Schrittmotor.runSpeed();}      // Wenn sich der Schlitten vom rechten Endschalter aus bewegt, laufe nach links
	
	while( GetEndSwitch() != direction ) { /* do nothing than wait for target position */
		delay( 100 ); // check button every 100ms
 		if (digitalRead(StartSwitchPin) == LOW ){ break; } // interrupt movement 
	}
	   
	Schrittmotor.disableOutputs(enblPin);  // Motor bleibt stehen
}


// Funktion zum Einlesen der Geschwindigkeit
// Liefert 1, 2, oder 3 für die selektierte Geschwindigkeit
int GetSpeed()
{
  // Es ist immer nur einer der Pins auf LOW (Drehschalter/Schiebeschalter)
  if( digitalRead( Speed1Pin ) == LOW ) return Speed1; 
  if( digitalRead( Speed2Pin ) == LOW ) return Speed2;
  if( digitalRead( Speed3Pin ) == LOW ) return Speed3;
}

// Auslesen der Endschalter
// 'L' wenn linker Endschalter aktiv ist
// 'R' wenn rechter Endschalter aktiv ist
// 'N' wenn kein Endschalter aktiv ist
char GetEndSwitch()
{
	if( digitalRead( eslPin ) == LOW ) return 'L';
    if( digitalRead( esrPin ) == LOW ) return 'R';
	return 'N';
}

// Starttaster einlesen. 
// Funktion wirds erst verlassen, wenn der Taster betätigt und wieder losgelassen wird
// => Entprellen des Tasters
void GetStartSignal(){
   	while( digitalRead(StartSwitchPin) == HIGH ){ /* do nothing than wait */}
	while( digitalRead(StartSwitchPin) == LOW ) { /* do nothing than wait */}
}

Hallo,

soll GetStartSignal die Tasterentprellung und Schaltfunktion sein? So einfach ist das nicht, weil der µC sehr schnell ist und das prellen eines Tasters im Vergleich dazu sehr langsam. Die Funktion wäre sofort abgearbeitet. Ein kleines Störsignal würde auch ausreichen. Ihr habt doch sicherlich Ambitionen das selbst zu lösen? Dann sucht mal nach Taster entprellen ... ihr könnt auch die Bsp. der IDE durchgehen.

Ich habe es mal kurz überflogen. Es sollte reichen nach dem Knopfdruck einen Delay von 10mS einzuarbeiten, oder?

Hier ist ja bereits ein Delay eingearbeitet:

...

while( GetEndSwitch() != direction ) { /* do nothing than wait for target position */
		delay( 100 ); // check button every 100ms
 		if (digitalRead(StartSwitchPin) == LOW ){ break; } // interrupt movement 
	}

...

Oder meinst du, das man Delay auch noch in die untenstehende "GetStartSignal" Funktion einarbeiten muss?

// Starttaster einlesen. 
// Funktion wirds erst verlassen, wenn der Taster betätigt und wieder losgelassen wird
// => Entprellen des Tasters
void GetStartSignal(){
   	while( digitalRead(StartSwitchPin) == HIGH ){ /* do nothing than wait */}
	while( digitalRead(StartSwitchPin) == LOW ) { /* do nothing than wait */}
}

Grüße
Lorenz

LorenzSchaefer:
... habe leider selber kaum Programmierkenntnise.

Für das Schreiben eines Programms ist das eine sehr schlechte Ausgangsbasis.

Daher nur zwei ziemlich allgemeine Tipps:

  • Zeichne das, was Du tun möchtest, als Programmablaufplan auf. Im Idealfall kannst Du Dein Programm „trocken“ testen und den/die wesentlichen Algoritmen fast direkt ablesen.

  • Gewöhne Dir an, den Programmcode „schön“ zu gestalten: Einheitliche Einrückungen und Klammersetzung. Wenn Du es richtig anstellst, kann man die Arbeitsweise des Programms oder von Teilen davon erkennen, ohne dass man den Code lesen muss. Erzeuge Einrückungen durch Leerzeichen (ich nehme immer 2 Leerzeichen je „Ebene“). Mit der Tab-Taste erzeugte Einrückungen haben den Nachteil, dass sie je nach Einstellung auf Betrachterseite unterschiedlich groß sind.

Wenn Du so vorgehst, kommst Du relativ schnell zu einem fehlerfreien Ergebnis. Und sollten trotzdem Fehler im Code sein, findest Du sie dank passender Einrückungen ziemlich schnell.

Wenn Du mehrere Dinge quasi gleichzeitig ablaufen lassen möchtest, setzt Du das (oft) am besten als „endlichen Automat“ um. Was mir hierzu eingefallen ist, habe ich hier ins Netz gekippt (beachte ggf. die Folgeseite).

HTH

Gregor

Hallo,

ihr habt euch leider nicht Taster entprellen beschäftigt. Zudem bei einer Maschinensteuerung jederzeit auf irgendwelche Eingänge (Taster) reagiert werden muss. while kann man nehmen wenn man z.Bsp. in einem Kalibriermodus ist und nur von Zustand zu Zustand springt. Im laufenden Betrieb ist das nicht gut. Wie schon gesagt, was ist wenn jemand den STOP Taster drückt? Darauf muss sofort reagiert werden können, egal was das gerade Programm macht.

Ein Bsp. von mir:

/*
  Doc_Arduino - german Arduino Forum
  IDE v1.8.5
  08.12.2017
  kurzen und langen Tastendruck erkennen
*/


const byte _Taster = 2;
const byte _LED1 = 30;
const byte _LED2 = 31;


void setup() {
  
  Serial.begin(500000);
  pinMode(_Taster, INPUT_PULLUP);     // mit INPUT_PULLUP invertierte Logik
  pinMode(_LED1, OUTPUT);               
  pinMode(_LED2, OUTPUT);    
}

void loop() {

  update_Taster();
}


void Taster ()
{
  static bool state_Taster = false;
  static unsigned long last_push = 0;
  
  unsigned long diff = 0;
  static bool toggle_long = false;
  static bool toggle_short = false;  
  unsigned long ms = millis();
  
  bool read_Taster = digitalRead(_Taster);      // Tasterstatus einlesen
  
  if (read_Taster != state_Taster) {            // wenn Tasterstatus verschieden zu vorher
    state_Taster = read_Taster;
    if (read_Taster == LOW) {
      last_push = ms;                           // letztes Kontakt prellen merken
    }
    else {
      diff = ms - last_push;                    // wenn Taster losgelassen Differenz berechnen
    }
  }
  
  if (diff > 450) {
    toggle_long = !toggle_long;
    digitalWrite(_LED1, toggle_long);
    Serial.println(diff);
  }
  
  if (diff > 50 && diff < 250) {
    toggle_short = !toggle_short;
    digitalWrite(_LED2, toggle_short);
    Serial.println(diff);
  }
}


void update_Taster ()
{
  static unsigned long last_millis = 0;
  const byte Entprellzeit = 20;           // Taster Entprellzeit [ms]
  
  if (millis()-last_millis > Entprellzeit) {
    last_millis = millis();
    Taster();
  }
}

Wenn ihr das noch nicht so indus habt, nehmt das Bounce von der IDE oder die Bounce2 Lib. Guckt euch auf jeden Fall die Bsp. an sonst wird das nichts.