Projekt: Schrittmotor

Guten Abend liebe Gemeinde, ich bin kürzlich stolzer Besitzer eines Arduino Mega geworden und wollte hier einen Schrittmotor ansteuern. Genauer genommen einen Schrittmotortreiber, der zwischen Schrittmotor und Arduino hängt. Leider sind meine, 10 Jahre alten, C-Kentnisse stark eingerostet. Das Programm so wie es ist lässt den Schrittmotor laufen. Füge ich die Zeilen mit den Kommentaren ein funktioniert es nicht mehr. Ich möchte dass wenn ich in die Konsole 1 eingebe die CLK generiert wird und wenn ich eine 0 eingebe, dass Programm anhält.

boolean CLK =13; //Schrittgeschwindigkeit
boolean DIR =12; //Drehrichtung
boolean NEN = 9; //NOT ENABLE
boolean HAL = 8; //1/2
boolean QUA = 7; //1/4
boolean x;

void setup()
{
  pinMode(CLK, OUTPUT);
  pinMode(DIR, OUTPUT);
  pinMode(NEN, OUTPUT);
  pinMode(HAL, OUTPUT);
  pinMode(QUA, OUTPUT);
  Serial.begin(9600); 
  Serial.println("Test");
}

void loop()
{
  //x = Serial.read();
  //while(x==1) 
  //{ 
    digitalWrite(CLK, HIGH); // CLK einschalten 
    delay(5); 
    digitalWrite(CLK, LOW); // CLK ausschalten 
    delay(5);  
   // continue; 
  //}
}

Wie setze ich "Serial.read" richtig ein?

So macht das keinen Sinn. Du musst Serial.read() innerhalb der while-Schleife einlesen. Und continue macht hier auch nichts. Damit beendet man die aktuelle Iteration und geht zur nächsten.

boolean CLK =13;

boolean? Was du da willst ist ein int.

So ist es meiner Ansicht nach intuitiver:

volatile bool run = false;

loop()
{
    if(run)
    {
        digitalWrite(CLK, HIGH); // CLK einschalten 
        delay(5); 
       digitalWrite(CLK, LOW); // CLK ausschalten 
       delay(5); 
   } 
}


void serialEvent()
{
      x = Serial.read();
      if(x == '0')
      {
        run = false;
      }
      else(if x == '1')
        run = true;
}

Da bool sollte hier eigentlich auch run = Serial.read() funktionieren, aber mit der if-Abfrage bist du sicherer wenn mal was anderes geschickt wird.

Oder ohne Event-Handler:

loop()
{
     x = Serial.read();
     while(x == '1')
     {
        digitalWrite(CLK, HIGH); // CLK einschalten 
        delay(5); 
        digitalWrite(CLK, LOW); // CLK ausschalten 
        delay(5);  
        
        x = Serial.read();
        if(x == '0')
           break;
     }
}

Der EventHandler ist aber besser, da du damit nicht ständig abfragen musst ob an der Schnittstelle etwas angekommen ist.

sonyfuchs: Ich möchte dass wenn ich in die Konsole 1 eingebe die CLK generiert wird und wenn ich eine 0 eingebe, dass Programm anhält.

Da solltest Dir erstmal klar darüber werden, was eigentlich gesendet wird, wenn Du "1" oder "0" eingibst und sendest.

Der serielle Monitor von Arduino sendet immer Zeilenweise. Jede Zeile wird mit den beiden Steuerzeichen CR (Carriage Return, ASCII-13) und LF (Linefeed, ASCII-10) abgeschlossen.

Das gesendete Zeichen wird in ASCII-Zeichencodierung gesendet, also für "0" eine ASCII-48 und für "1" eine ASCII 49.

D.h. wenn Du "1" sendest, sendest Du tatsächlich: 49 13 10 Und wenn Du "0" sendest, sendest Du tatsächlich: 48 13 10

Du kannst z.B. die Daten laufend auslesen und im Fall, dass 49 und 48 gelesen werden, entsprechend reagieren:

void loop()
{ char x;
  static boolean clkEin=false;
  x = Serial.read();
  if (x==49) clkEin=true;
  else if (x==48) clkEin=false;
  else ; // ist egal
  if (clkEin)
     {
        digitalWrite(CLK, HIGH); // CLK einschalten 
        delay(5); 
        digitalWrite(CLK, LOW); // CLK ausschalten 
        delay(5);  
     }
}

ich musste es leicht abändern weil er n paar sachen nicht kannte, aber läuft trotzdem nicht :(

int CLK =13; //Schrittgeschwindigkeit
int DIR =12; //Drehrichtung
int NEN = 9; //NOT ENABLE
int HAL = 8; //1/2
int QUA = 7; //1/4
boolean x;
boolean run = false;

void setup()
{
  pinMode(CLK, OUTPUT);
  pinMode(DIR, OUTPUT);
  pinMode(NEN, OUTPUT);
  pinMode(HAL, OUTPUT);
  pinMode(QUA, OUTPUT);
  Serial.begin(9600); 
  Serial.println("Test");
}

void loop()
{
  while(run)
  {
    digitalWrite(CLK, HIGH); // CLK einschalten 
    delay(5); 
    digitalWrite(CLK, LOW); // CLK ausschalten 
    delay(5); 
  } 
}


void Serialevent()
{
      x = Serial.read();
      if(x == 0)
      {
        run = false;
      }
      else if (x == 1)
        run = true;
}

ich muss noch anmerken dass "Serialevent" schwarz geschrieben wird, also nicht als besondere eingabe erkannt wird wie "loop" ^_^ ich weiß dass hört sich für die meisten lächerlich an. bitte habt nachsicht

Wie jurs sagte, noch vergessen, dass da Characters geschickt werden. Also entweder auf den ASCII-Wert abfragen, oder '0' und '1' (die Anführungsstriche sagen, dass es chars sind und nicht Zahlen). Und x dann als char und nicht als bool.

Und "run" sicherheitshalber als volatile definieren.

Das kommt auch drauf an was man da sonst noch macht. Wenn da später noch anderes Zeug dazu kommt, das in der loop läuft ist da natürlich "if" sinnvoller als "while", sonst steckt man ständig in der while-Schleife drin.

Und gerade noch gemerkt, dass man bei serialEvent, sowieso "if" braucht, da der eventHandler zwischen den loop-Iterationen ausgeführt wird. Oops. :)

vielen dank jurs, dass hat funktioniert. werd mir dass mal gleich richtig ansehen

sonyfuchs:
vielen dank jurs, dass hat funktioniert. werd mir dass mal gleich richtig ansehen

Nur zu! Und wie erwähnt, kannst Du statt auf die ASCII-Codes der Zeichen auch direkt auf die Zeichen prüfen, d.h.

if (x==49) clkEin=true;
else if (x==48) clkEin=false;
ist völlig gleichbedeutend mit:
if (x==‘1’) clkEin=true;
else if (x==‘0’) clkEin=false;

so, ich hab mal n bischen rumprobiert und hab jetzt n paar fragen, aber erstmal der aktuelle Code:

/*
  Der Motor ist bei 00 ausgeschaltet,
  mit 01 und 10 ändert man die Drehrichtung.
*/

int CLK =13; //Schrittgeschwindigkeit
int DIR =12; //Drehrichtung
int NEN = 9; //NOT ENABLE
int HAL = 8; //1/2
int QUA = 7; //1/4

char x;
//static boolean clkEin;

void setup()
{
  pinMode(CLK, OUTPUT);
  pinMode(DIR, OUTPUT);
  pinMode(NEN, OUTPUT);
  pinMode(HAL, OUTPUT);
  pinMode(QUA, OUTPUT);
  Serial.begin(9600); 
  Serial.println("Test");
}

void loop()
{ 
  static boolean clkEin=false;
  x = Serial.read();
  if (x=='10') 
  {
    digitalWrite(DIR, LOW);
    digitalWrite(NEN, LOW);
    clkEin=true;
  }
  else if (x=='00')
  {
    digitalWrite(NEN, HIGH);
    clkEin=false;
  }
  else if (x=='01')
  {
    digitalWrite(DIR, HIGH);
    digitalWrite(NEN, LOW);
    clkEin=true;
  }
  if (clkEin)
  {
    digitalWrite(CLK, HIGH); // CLK einschalten 
    delay(5); 
    digitalWrite(CLK, LOW); // CLK ausschalten 
    delay(5);  
  }
}

so nun die Fragen: 1. wenn ich die Zeile

static boolean clkEin=false;

aus loop zu den anderen Deklarationen nach oben verschiebe, läuft das Programm nicht mehr. Warum? 2. wo ist der unterschied zwischen static boolean und boolean. bei abänderung von static boolean zu boolean funktioniert das Programm auch nicht. 3. aus 48 und 49, '0' und '1' zu machen hat funktioniert. Jetzt hab ich das Programm um die Drehrichtung erweitert und mit '10' '00' und '01' läuft es nicht mehr, wenn ich aber '0' '1' und '2' mache schon. Woran liegt dass? 4. ich möchte dass NEN grundsätzlich High ist wenn nicht 1 oder 2 eingegeben wurde. schreib ich es aber for die if abfrage startet der Motor nicht mehr. Wie kann ich dass abändern?

wo ist der unterschied zwischen static boolean und boolean.

static hat zwei Funktionen: 1.) In Klassen verwendet, ist die Variable für alle Instanzen gleich und existiert nicht getrennt für jede Instanz 2.) In Methoden behält sie ihren Wert von einem Aufruf zum nächsten und wird nicht jedes mal neu initialisiert. Die Initialisierung geschieht nur beim ersten Aufruf.

Hier geht es um den zweiten Fall

Wenn du innerhalb der loop das static weg lässt wird die Variable bei jedem Durchlauf auf false zurückgesetzt. Daher wird dann der Clock-Impuls für jedes Senden nur einmal gemacht. Das sollte aber auch mit der Deklaration außerhalb ohne static funktionieren.

Globale Variable nimmt man gewöhnlich nur wenn diese wirklich im ganzen Programm gelten müssen, z.B. die Pin-Belegung. Sonst hält man deren Geltungsbereich (Scope) so klein wie möglich. "char x" z.B. muss nicht global sein und wird in jeder loop-Iteration neu eingelesen. "clkEin" muss seinen Wert von einem loop-Aufruf zum nächsten behalten, aber da gibt es eben static als Alternative zur globalen Deklaration. Es ist aber nicht grundlegend falsch das global zu machen, wenn es für dich verständlicher ist.

  1. aus 48 und 49, '0' und '1' zu machen hat funktioniert. Jetzt hab ich das Programm um die Drehrichtung erweitert und es läuft nicht mehr. Woran liegt dass?

char ist ein Zeichen. Du kannst nicht 'xx" in einen char schreiben. Benutze dafür zwei getrennte chars, die du nacheinander einließt.

char x = Serial.read();
char y = Serial.read();

if(x == '1' && y == '0')   //am besten hier mal bessere Variablen-Namen nehmen
{
}

Da ich mich gewundert habe wieso da der Compiler nicht meckert, habe ich das mal in Visual Studio ausprobiert. Wenn man das macht: int character = '00'; schreibt er "0011 0000 0011 0000" rein. Der rechte Character steht dabei im niederwertigem Byte, wobei man das hier nicht sieht, da beide gleich sind.

"0011 0000" ist 48 = '0'. Wenn man das einem char zuweist, kommt eine Warnung "warning C4305: 'initializing' : truncation from 'int' to 'char'", und er weist den rechten Character zu und ignoriert den Rest. Es kompiliert also, aber durch die implizite Konversion gehen Daten verloren.

danke erstmal für die Erklärung des Begriffs "static". leider funktioniert es nicht wenn ich es global versuche. Hab jetzt versucht mit einem zweiten char : y die zweite Zahl einzuladen:

/*
  Der Motor ist bei 00 ausgeschaltet,
  mit 01 und 10 ändert man die Drehrichtung.
*/

int CLK =13; //Schrittgeschwindigkeit
int DIR =12; //Drehrichtung
int NEN = 9; //NOT ENABLE
int HAL = 8; //1/2
int QUA = 7; //1/4

char x;
char y;
//static boolean clkEin;

void setup()
{
  pinMode(CLK, OUTPUT);
  pinMode(DIR, OUTPUT);
  pinMode(NEN, OUTPUT);
  pinMode(HAL, OUTPUT);
  pinMode(QUA, OUTPUT);
  Serial.begin(9600); 
  Serial.println("Test");
}

void loop()
{ 
  static boolean clkEin=false;
  x,y = Serial.read();
  //y = Serial.read();
  if (x == '1' && y == '0') 
  {
    digitalWrite(DIR, LOW);
    digitalWrite(NEN, LOW);
    clkEin=true;
  }
  else if (x == '0' && y == '0')
  {
    digitalWrite(NEN, HIGH);
    clkEin=false;
  }
  else if (x == '1' && y == '1')
  {
    digitalWrite(DIR, HIGH);
    digitalWrite(NEN, LOW);
    clkEin=true;
  }
  if (clkEin)
  {
    digitalWrite(CLK, HIGH); // CLK einschalten 
    delay(5); 
    digitalWrite(CLK, LOW); // CLK ausschalten 
    delay(5);  
  }
}

leider funktioniert dass nicht. der Motor springt weder auf 1 0 00 01 10 an. wie kann ich NEN so festlegen, dass wenn noch keine Angabe gemacht wurde er Grundsätzlich HIGH ist?

x = Serial.read();
y = Serial.read();

"x,y = Serial.read()" geht nicht. Du willst zwei Zeichen einlesen, also musst du auch zweimal read() machen.

Du darfst das nicht mit der Initialisierung von Variablen verwechseln. Und wenn du "int x, y = 3" machst, schreibt er auch nur 3 in y, aber x bleibt 0 (es gibt auch Compiler, die keinen default value setzen was eigentlich Standard in C ist)! Wenn du dir über solche Feinheiten nicht im Klaren bist, gehe lieber auf Nummer sicher und schreibe es gleich ausführlich. Da ist der Code länger, aber er funktioniert auch.

Du musst dann im Serial Monitor zwei Zeichen direkt hintereinander schicken. Also "00" und dann senden.

Weiß nicht wieso das nicht gehen sollte wenn es korrekt programmiert ist.

Du kannst ja mal das nach dem Einlesen machen:

Serial.print("x: ");
Serial.print(x);
Serial.print(" - y: ");
Serial.println(y);

Dann schickt er dir die empfangen Zeichen sofort wieder zurück und du hast eine Kontrolle. Das ist eine Art Primitiv-Debugging. Damit kannst du auch überprüfen wo dein Programm steht, wenn du an bestimmten Stellen Ausgaben hinzufügst.

Wenn es geht musst du das aber wieder entfernen.

wie kann ich NEN so festlegen, dass wenn noch keine Angabe gemacht wurde er Grundsätzlich HIGH ist?

Einfach in Setup den Ausgang auf HIGH setzen.

so, jetzt funktioniert die eingabe von '00' '10' etc.

/*
  Der Motor ist bei 00 ausgeschaltet,
  mit 01 und 10 ändert man die Drehrichtung.
*/

int CLK =13; //Schrittgeschwindigkeit
int DIR =12; //Drehrichtung
int NEN = 9; //NOT ENABLE
int HAL = 8; //1/2
int QUA = 7; //1/4

char x;
char y;

void setup()
{
  pinMode(CLK, OUTPUT);
  pinMode(DIR, OUTPUT);
  pinMode(NEN, OUTPUT);
  pinMode(HAL, OUTPUT);
  pinMode(QUA, OUTPUT);
  Serial.begin(9600); 
  Serial.println("Test");
  digitalWrite(NEN, HIGH);
}

void loop()
{ 
  static boolean clkEin=false;
  x = Serial.read();
  y = Serial.read();
  
  Serial.print("x: ");
  Serial.print(x);
  Serial.print(" - y: ");
  Serial.println(y);
  
  if (x == '1' && y == '0') 
  {
    digitalWrite(DIR, LOW);
    digitalWrite(NEN, LOW);
    clkEin=true;
  }
  else if (x == '0' && y == '0')
  {
    digitalWrite(NEN, HIGH);
    clkEin=false;
  }
  else if (x == '1' && y == '1')
  {
    digitalWrite(DIR, HIGH);
    digitalWrite(NEN, LOW);
    clkEin=true;
  }
  if (clkEin)
  {
    digitalWrite(CLK, HIGH); // CLK einschalten 
    delay(5); 
    digitalWrite(CLK, LOW); // CLK ausschalten 
    delay(5);  
  }
}

als ausgabe gibt er mir nur ein unverständliches: Test x: ÿ - y: ÿ x: ÿ - y: ÿ x: ÿ - y: ÿ x: ÿ - y: ÿ ... usw.

ich glaub NEN ist trotzdem nicht von Anfang an auf High wenn ich Serial.println(NEN); eingebe, gibt er mir 9 also den pin aus. wie frag ich nach low und high ab?

sonyfuchs: als ausgabe gibt er mir nur ein unverständliches: Test x: ÿ - y: ÿ x: ÿ - y: ÿ x: ÿ - y: ÿ x: ÿ - y: ÿ ... usw.

Du hast immer noch nicht die Funktionsweise der seriellen Schnittstelle und der dazugehörenden Library verstanden: Wenn kein Zeichen im Eingangspuffer der Schnittstelle vorhanden ist und Du liest die Serielle Schnittstelle aus mit: x = Serial.read(); y = Serial.read(); dann bekommst Du von der read() Funktion immer einen Error-Code zurück. Den kannst Du printen wie Du lustig bist und es bleibt immer der Error-Code. Wenn Du auslesen möchtest was übertragen wurde, dann mußt Du immer zuerst mit "Serial.available()" prüfen, ob überhaupt ein Zeichen zum Lesen im Eingangspuffer vorhanden ist. Nur wenn ein Zeichen im Eingangspuffer drin ist, kannst Du den Wert dieses Zeichens aus dem Eingangspuffer auslesen. Sonst wird immer nur der Error-Code geliefert, wenn Du aus dem leeren Eingangspuffer liest.

sonyfuchs: ich glaub NEN ist trotzdem nicht von Anfang an auf High wenn ich Serial.println(NEN); eingebe, gibt er mir 9 also den pin aus. wie frag ich nach low und high ab?

Ja, logisch: int NEN = 9; Serial.println(NEN); wird immer "9" ausgeben, solange NEN den wert "9" hat.

Wenn Du den Wert des Pins 9 (NEN) auslesen und ausgeben möchtest, dann brauchst Du digitalRead, und Du gibst den Wert von digitalRead(NEN) aus: Serial.println(digitalRead(NEN));

Das war mein Fehler. Sorry :)

Das 'ÿ' ist laut extended ASCII table 255, bzw. FF. Das ist dann das was in x und y steht wenn nichts eingegeben wurde.

Laut Doku: return: "the first byte of incoming serial data available (or -1 if no data is available)"

Und -1 im Zweier-Komplement ist FF...

So funktioniert es:

if(x != -1 && y != -1)
{
  Serial.print("x: ");
  Serial.print(x);
  Serial.print(" - y: ");
  Serial.println(y);
}

Fragt ab ob wirklich 2 Werte eingelesen wurden und schreibst sie nur dann raus.

Oder besser gleich serial.available() > 0: http://arduino.cc/en/Serial/Available

Das kannst du bei dir auch um das Einlesen UND die if-Abfragen (bis auf die Clock Ausgabe) herumbauen. Dann macht er das nur wenn wirklich was eingelesen wurde:

if(Serial.available() > 1)
{
  x = Serial.read();
  y = Serial.read();
  
  
  if (x == '1' && y == '0') 
  {
    .
    .
    .

}   //end Serial.available

if (clkEin)
{
    digitalWrite(CLK, HIGH); // CLK einschalten 
    delay(5); 
    digitalWrite(CLK, LOW); // CLK ausschalten 
    delay(5);  
}

So wie es jetzt ist macht er den Vergleich auch in jeder Iteration von Loop, und da x und y dann -1 sind, passiert da halt nichts.

/*
  Der Motor ist bei 00 ausgeschaltet,
  mit 01 und 10 ändert man die Drehrichtung.
*/

int CLK =13; //Schrittgeschwindigkeit
int DIR =12; //Drehrichtung
int NEN = 9; //NOT ENABLE
int HAL = 8; //1/2
int QUA = 7; //1/4

char x;
char y;

void setup()
{
  pinMode(CLK, OUTPUT);
  pinMode(DIR, OUTPUT);
  pinMode(NEN, OUTPUT);
  pinMode(HAL, OUTPUT);
  pinMode(QUA, OUTPUT);
  Serial.begin(9600); 
  Serial.println("Test");
  digitalWrite(NEN, HIGH);
}

void loop()
{ 
  static boolean clkEin=false;
  x = Serial.read();
  y = Serial.read();
  
  //if (Serial.available() > 0) 
  //{
    Serial.print("x: ");
    Serial.print(x);
    Serial.print(" - y: ");
    Serial.println(y);
    Serial.println(digitalRead(NEN));
  //}
  
  if (x == '1' && y == '0') 
  {
    digitalWrite(DIR, LOW);
    digitalWrite(NEN, LOW);
    clkEin=true;
  }
  else if (x == '0' && y == '0')
  {
    digitalWrite(NEN, HIGH);
    clkEin=false;
  }
  else if (x == '1' && y == '1')
  {
    digitalWrite(DIR, HIGH);
    digitalWrite(NEN, LOW);
    clkEin=true;
  }
  if (clkEin)
  {
    digitalWrite(CLK, HIGH); // CLK einschalten 
    delay(5); 
    digitalWrite(CLK, LOW); // CLK ausschalten 
    delay(5);  
  }
}

wenn man die rauskomentierten 3 Zeilen wieder reinnimmt, läuft das Programm nicht mehr. Dabei ist das doch nur ne Ausgabe.

Serial.available() muss abgefragt werden bevor man mit read() einließt. Wenn nichts im Puffer ist, brauchst du auch nicht read() zu machen. Und nach read() ist available() in deinem Fall 0, also wird dieser Code nie ausgeführt. Der Rest sollte aber laufen.

Siehe Beispiel-Code hier:
http://arduino.cc/en/Serial/Available

Die ganzen if(x == … && y == …) Abfragen braucht man auch nur zu machen wenn wirklich etwas eingelesen wurde.

Ich habe mein Post oben mal editiert, aber der Code am Ende ist nicht getestet!

also, wenn ich nicht nach serial available abfrage läufts.

wenn doch dann sagt mir der serial monitor zu folgender eingabe 00 Senden 10 Senden 11 Senden das hier: Test x: 0 - y: ÿ 1 x: 0 - y: ÿ 1 x: 1 - y: ÿ 1 x: 0 - y: ÿ 1 x: 1 - y: ÿ 1 x: 1 - y: ÿ 1

anscheinend sieht er die 3 eingaben als 6 an und ändert immer nur x und nie y. und er blockiert den Motor mit NEN immer.

hier noch mal der momentane Code:

/*
  Der Motor ist bei 00 ausgeschaltet,
  mit 01 und 10 ändert man die Drehrichtung.
*/

int CLK =13; //Schrittgeschwindigkeit
int DIR =12; //Drehrichtung
int NEN = 9; //NOT ENABLE
int HAL = 8; //1/2
int QUA = 7; //1/4

char x;
char y;

void setup()
{
  pinMode(CLK, OUTPUT);
  pinMode(DIR, OUTPUT);
  pinMode(NEN, OUTPUT);
  pinMode(HAL, OUTPUT);
  pinMode(QUA, OUTPUT);
  Serial.begin(9600); 
  Serial.println("Test");
  digitalWrite(NEN, HIGH);
}

void loop()
{ 
  static boolean clkEin=false;
  if (Serial.available() > 0) 
  {
    x = Serial.read();
    y = Serial.read();
  
  
    Serial.print("x: ");
    Serial.print(x);
    Serial.print(" - y: ");
    Serial.println(y);
    Serial.println(digitalRead(NEN));
  }
  
  if (x == '1' && y == '0') 
  {
    digitalWrite(DIR, LOW);
    digitalWrite(NEN, LOW);
    clkEin=true;
  }
  else if (x == '0' && y == '0')
  {
    digitalWrite(NEN, HIGH);
    clkEin=false;
  }
  else if (x == '1' && y == '1')
  {
    digitalWrite(DIR, HIGH);
    digitalWrite(NEN, LOW);
    clkEin=true;
  }
  if (clkEin)
  {
    digitalWrite(CLK, HIGH); // CLK einschalten 
    delay(5); 
    digitalWrite(CLK, LOW); // CLK ausschalten 
    delay(5);  
  }
}

Frage auf > 1 ab (oder >=2), statt auf > 0. Dann wartet er bis mindestens 2 Zeichen da sind. So ließt er wahrscheinlich schon nach dem ersten Zeichen und das zweite ist noch nicht da. Das liegt daran, dass der Controller schneller als die serielle Übertragung ist.

Was bei dir jetzt noch ist, ist dass er die Einstellung/Umschaltung der Richtung und Enable immer macht. Auch wenn nichts gesendet wurde. Das funktioniert zwar, da die if-Abfragen dann false zurückgeben, aber du kannst das auch innerhalb von if(Serial.available...) { } packen. So dass wenn available() 0 zurück gibt (oder etwas kleiner als 2), nur der Takt-Impuls am Ende gemacht wird.

Mal als Anhaltspunkt: 9600 Baud sind 9600 Signalwechsel pro Sekunde, d.h. ein einzelnes Bit dauert ca. 100µs ! Bei 8 Datenbits, Start und Stop-Bits, dauert ein Zeichen damit eine ganze Millisekunde und mehr.

Also mit der Abfrage nach >=2 funktioniert es jetzt wunderherrlich.
Dass erscheint mir auch sehr logisch.
Mit dem NEN Problem komm ich aber nicht so ganz mit. Ich hoffe du verzeihst mir meine Begriffsstuzigkeit.
Der wechsel ist zu schnell für den serial monitor, oder wie ist das gemeint?
Ich seh ja auch dass der NEN im monitor nicht mit dem Tatsächlichen übereinstimmt, da er manchmal auf 1 steht und der Motor trotzdem dreht.
Wie änder ich dass nun ab?

Das mit der Zeit war nur für die serielle Übertragung PC -> Arduino gemeint. Es dauert halt ca. 2ms um zwei Zeichen zu schicken. Deshalb kannst du nach dem Empfang des ersten Zeichens nicht gleich das zweite auslesen, sondern musst warten bis beide da sind.

Serial.println(digitalRead(NEN)) gibt den aktuellen Wert des Pins aus. Das ist bevor du umschaltest. Wenn du jetzt sagts "Motor stop", gibt er da den alten Wert aus. Nicht den neuen. Kann sein, dass du damit durcheinander kommst.

Mach das mal so:

void loop()
{ 
  static boolean clkEin=false;

  if (Serial.available() > 0) 
  {
    x = Serial.read();
    y = Serial.read();
  
  
    Serial.print("x: ");
    Serial.print(x);
    Serial.print(" - y: ");
    Serial.println(y);
  
    if (x == '1' && y == '0') 
    {
       digitalWrite(DIR, LOW);
       digitalWrite(NEN, LOW);
       clkEin=true;
    }
    else if (x == '0' && y == '0')
    {
      digitalWrite(NEN, HIGH);
      clkEin=false;
    }
    else if (x == '1' && y == '1')
    {
      digitalWrite(DIR, HIGH);
      digitalWrite(NEN, LOW);
      clkEin=true;
    }

    Serial.println(digitalRead(NEN));
  }
  
  if (clkEin)
  {
    digitalWrite(CLK, HIGH); // CLK einschalten 
    delay(5); 
    digitalWrite(CLK, LOW); // CLK ausschalten 
    delay(5);  
  }
}

Dann führt er 1. Die Änderungen nur aus wenn wirklich was eingelesen wurde und 2. Wird NEN erst nach dem Umschalten ausgelesen. Das ist wahrscheinlich eher was du willst.