sketch_67_nanoslave_I2C_servos_ansteuern (Arduino Nano)

sketch_67_nanoslave_I2C_servos_ansteuern
  /*Ueber die I2C serielle Schnittstelle ist ein ESP8266 NodeMCU (Master) mit mehreren Arduino Nano (Slaves) verbunden. 
  SDA (Serial Data):  ESP Pin D2 - Nano Pin A4
  SCL (Serial Clock): ESP Pin D1 - Nano Pin A5
  
  Auf die Nanos wird dieser sketch geladen, auf den ESP sketch_66_espmaster_I2C_servos_ansteuern.
  Jeder Nano steuert einen Roboter.
  Der Bewegungsablauf (Aktion) muss auf jedem Nano im Unterprogramm "Aktion.h" einprogrammiert werden.
  Die Busadresse des jeweiligen Nano wird in die Variable "robot" gespeichert.
  
  Ueber den seriellen Monitor wird im Sketch des Masters (ESP) eingegeben, welcher Nano (d.h. welcher Roboter) jeweils 
  ueber den I2C Bus angesprochen werden soll: a1 ... a5 (a steht fuer "Aktion").
  
  Im seriellen Monitor der Nanos als auch des ESP erfolgen Anzeigen zum Ablauf.
  Die Ausgabe im seriellen Monitor fuer den Slave ist nur moeglich, wenn er an einem anderen Computer angeschlossen ist
  (Neu-Aufruf des Monitors loest bei Nano immer einen Reset aus (nicht bei ESP).
    
  Die Spannungsversorgung vom ESP als auch der Nanos erfolgt ueber die USB-Kabel. 
  Beachte, fuer diesen Sketch muss bei "Werkzeugen" eingetragen sein:
  Board "Arduino Nano" / Prozessor:"ATmega 328 Old Bootloader" und das richtige COM-Port.
  */
  byte robot = 1;                       // In die Variable muss die Nr.des Roboters = Busadresse des Slave eingetragen werden
                                        // siehe unten: Wire.begin(robot) 
  #include "Aktion.h"
  #include <Wire.h>                     
  volatile byte flag = 0;               // Hilfsvariable, zur Steuerung des Programms (volatile, da auch Verwendung in der Interruptroutine)
                                        // siehe https://www.arduino.cc/reference/de/language/variables/variable-scope-qualifiers/volatile/
  void setup()
  {
   pinMode(2, OUTPUT);                  // Nano digital Pin D2 (Ausgang zu Servo Drehen)    
   pinMode(4, OUTPUT);                  // Nano digital Pin D4 (Ausgang zu Servo Greifer)
   pinMode(6, OUTPUT);                  // Nano digital Pin D6 (Ausgang zu Servo Heben)                
   pinMode(8, OUTPUT);                  // Nano digital Pin D8 (Ausgang zu Servo VorZurueck)
   
   Wire.begin(robot);                   // Anschluss an den I2C-Bus unter der Adresse, die in der Variablen robot gespeichert ist
   Wire.onReceive(receiveEvent);        // Interrupt: Byte wurde empfangen und ist abholbereit aus dem Empfangspuffer mit Wire.read
                                        // Es wird void receiveEvent aufgerufen (siehe unten)
   Wire.onRequest(requestEvent);        // Wenn der Master Daten vom Slave anfordert, wird void requestEvent aufgerufen (siehe unten)
   Serial.begin(9600);                  // Starten serieller Monitor
   Serial.print("Nano Slave Bereit");
  }
  
  void loop()
  {
   delay (200);
   if (flag > 0)                        // Wenn Daten vom Master empfangen wurden - Aktion wird gestartet
   { 
    Aktion();                           // Aufruf des gesamten Bewegungsablaufs im Unterprogramm Aktion.h
    flag = 0;                           // Flag wird wieder =0 gesetzt, damit sich die Aktion nicht wiederholt 
    Serial.println ("Aktion abgeschlossen");
   }
  }
  
  /*Diese Funktion wird immer dann ausgefuehrt, wenn Daten vom Master empfangen wurden (siehe oben Wire.onReceive)*/
  void receiveEvent(int howMany) 
  {
   while (1 < Wire.available())         // wiederhole solange bis alle ausser das letzte Byte ankamen                                                                
   { 
    char c = Wire.read();               // Alle 18 Bytes des String "Aktion Roboter Nr." werden aus dem Empfangspuffer geholt
    Serial.print(c);                    // jeweils Anzeige des Zeichens (character)
   }
    robot = Wire.read();                // jetzt wird das letzte Byte geholt, es enthaelt die Nr. des Roboters 
    Serial.println(robot);              // Anzeige der Nr. des Roboters
    flag = 1;                           // Setzen des Flags - damit kann im loop die Aktion gestartet werden
  }
  
  /*Diese Funktion wird immer dann ausgefuehrt, wenn der Master Daten vom Slave angefragt hat (siehe oben Wire.onRequest)*/
  void requestEvent()
  {
   if (flag > 0)
   {
    Wire.write("Aktion aktiv--");        // Senden dieser 14 Zeichen (Anzahl muss mit Sketch im Master korrespondieren)
   }
   else
   {
    Wire.write("--keine Aktion");        // Senden dieser 14 Zeichen
   }
  }
Aktion.h
  /*Hier wird der Bewegungsablauf (Aktion)programmiert.
    Nacheinander werden die Servos aufgerufen.*/
  
  #include "Drehung.h"
  #include "Greifer.h"
  #include "Heben.h"
  #include "VorZurueck.h"
  
  void Aktion()
  {
   int PWM_Dr = 1500;
   Drehung(PWM_Dr);
   delay(1000);
   
   int PWM_Gr= 1500;
   Greifer(PWM_Gr);
   delay(1000);
   
   int PWM_He = 1500;
   Heben(PWM_He);
   delay(1000);
   
   int PWM_Vo= 1500;
   VorZurueck(PWM_Vo);
  }
Drehung.h
  void Drehung(int PWM_Dr)             //vor "PWM_Dr" muss nochmal "int" (aber nicht im Hauptprogramm)
  {
   for(byte i=0; i<=60 ; i++)          //Wird i-mal wiederholt, der Servo hat i x 20ms Zeit seine Position zu erreichen
   {
    digitalWrite(2,HIGH);
    delayMicroseconds(PWM_Dr);         //Zeitvorgabe High-Impuls
    digitalWrite(2,LOW);
    delay(19);                         //Ergaenzung auf Zykluszeit etwa 20ms (delayMicroseconds funktioniert nur bis 16383 "integer") 
   }
  }
Greifer.h
  void Greifer(int PWM_Gr)             //vor "PWM_Gr" muss nochmal "int" (aber nicht im Hauptprogramm)
  {
   for(byte i=0; i<=60 ; i++)          //Wird i-mal wiederholt, der Servo hat i x 20ms Zeit seine Position zu erreichen
   {
    digitalWrite(4,HIGH);
    delayMicroseconds(PWM_Gr);         //Zeitvorgabe High-Impuls
    digitalWrite(4,LOW);
    delay(19);                         //Ergaenzung auf Zykluszeit etwa 20ms (delayMicroseconds funktioniert nur bis 16383 "integer") 
   }
  }
Heben.h
  void Heben(int PWM_He)               //vor "PWM_He" muss nochmal "int" (aber nicht im Hauptprogramm)
  {
   for(byte i=0; i<=60 ; i++)          //Wird i-mal wiederholt, der Servo hat i x 20ms Zeit seine Position zu erreichen
   {
    digitalWrite(6,HIGH);
    delayMicroseconds(PWM_He);         //Zeitvorgabe High-Impuls
    digitalWrite(6,LOW);
    delay(19);                         //Ergaenzung auf Zykluszeit etwa 20ms (delayMicroseconds funktioniert nur bis 16383 "integer") 
   }
  }
VorZurueck.h
  void VorZurueck(int PWM_Vo)          //vor "PWM_Vo" muss nochmal "int" (aber nicht im Hauptprogramm)
  {
   for(byte i=0; i<=60 ; i++)          //Wird i-mal wiederholt, der Servo hat i x 20ms Zeit seine Position zu erreichen
   {
    digitalWrite(8,HIGH);
    delayMicroseconds(PWM_Vo);         //Zeitvorgabe High-Impuls
    digitalWrite(8,LOW);
    delay(19);                         //Ergaenzung auf Zykluszeit etwa 20ms (delayMicroseconds funktioniert nur bis 16383 "integer") 
   }
  }