Arduino zu Arduino kommunikation (char senden und Befehl ausführen)

Wertes Schwarmbewusstsein, ich brauche deine Hilfe :slight_smile:
Ich habe jetzt einige Zeit das Web durchforstet aber komme auf keinen grünen Zweig.

Mein Vorhaben:
Der Master soll via i2c Kommunikation Befehle Befehl an zwei Slave´s senden welche dann dass dazugehörige Programm abfahren.

Master schickt "H" an Slave1 = Slave1 schaltet LED ein
Master schickt "L" an Slave1 = Slave1 schaltet LED aus
(das klappt soweit, gibt es ja zu genüge Tutorials für) :smiley:

Master schickt "H" an Slave2 = Slave2 lässt LED X mal blinken und hört von alleine wieder auf.
(Tja und da wird es haarig)

Ich habe mittlwerweile einige Ideen durch aber finde nicht den richtigen Weg.
Meine erste Idee war eine Variable zu beschreiben. Heißt, sobald das "H" ankommt wird "int CommandState = 0" auf "1" geschrieben und im weiteren Sketch wird das gelesen um zu wissen dass ein blinken abgespielt werden soll. um Anschluss hätte Slave2 "CommandState" wieder auf "0" gesetzt. Leider war ich damit auch nicht erfolgeich.

Langsam gehen mit die Ideen aus und Fragen kostet bekanntlich nichts. Vielleicht lerne ich ja noch einen kniff.

Hier mal die Codes.

Sender

#include <Wire.h>

const int buttonPin = 2;
const int ledPin =  13;

int buttonState = 0;

void setup()
{
  Wire.begin();
  pinMode(ledPin, OUTPUT);
  pinMode(buttonPin, INPUT);
}

void loop()
{
  buttonState = digitalRead(buttonPin);


  if (buttonState == HIGH) {
    digitalWrite(ledPin, HIGH);

    Wire.beginTransmission(1);
    Wire.write('H');
    Wire.endTransmission();

    delay(500);

    Wire.beginTransmission(1);
    Wire.write('L');
    Wire.endTransmission();

    delay(500);

    Wire.beginTransmission(1);
    Wire.write('H');
    Wire.endTransmission();

    delay(500);

    Wire.beginTransmission(1);
    Wire.write('L');
    Wire.endTransmission();

    delay(500);

    Wire.beginTransmission(2);
    Wire.write('H');
    Wire.endTransmission();

    delay(1000);

    Wire.beginTransmission(2);
    Wire.write('L');
    Wire.endTransmission();

  } else {

    Wire.beginTransmission(1);
    Wire.write('L');
    Wire.endTransmission();

    Wire.beginTransmission(2);
    Wire.write('L');
    Wire.endTransmission();
  }
}

Empfänger (Slave2):

#include <Wire.h>

const byte slaveId = 2;

void setup()
{
  Wire.begin(slaveId);
  Wire.onReceive(receiveEvent);
  pinMode(13, OUTPUT);

}

void loop()
{
}

void receiveEvent(int howMany)
{
  char inChar;

  while (Wire.available() > 0)
  {
    inChar = Wire.read();

    if (inChar == 'H')
    {
      digitalWrite(13, HIGH);
      delay (100);
      digitalWrite(13, LOW);
      delay (100);
      digitalWrite(13, HIGH);
      delay (100);
      digitalWrite(13, LOW);
      delay (100);
      digitalWrite(13, HIGH);
      delay (100);
      digitalWrite(13, LOW);
      delay (100);
    }
    if (inChar == 'L')
    {
      digitalWrite(13, LOW);
    }
  }
}

void receiveEvent(int howMany) läuft im ISR Kontext.
Darum sind delay() an der Stelle tödlich.

Klingt sehr plausibel, was combie schreibt.

Deshalb solltest Du Dein "Blinken" (wenn Du es so programmieren willst) innerhalb der loop ausführen.

In der receiveEvent Methode setzt Du einfach eine Variable z.b. doBlink = true
In der loop überprüfst Du ob doBlink true ist, und blinkst wenn ja.

Da ja viele Wege nach Rom führen habe ich einen gänzlich anderen Lösungsweg beschritten.

Mit dem Sender erzeuge ich verschiedene PWM Signale die von den Empfängern gelesen werden.
Je nach dem welchen wert das Signal besitzt wird eine diesem zugewiesene Aktion ausgeführt.

Wie genau ich das ganze via i2c machen könnte habe ich selbst nicht herausgefunden, da muss ich mich wohl noch ein wenig schlau machen. Ich würde mich allerdings sehr freuen wenn mir das hier jemand näher bringen könnte. :slight_smile:

Mir wäre ein einziger Uno oder Mega eigentlich lieber aber ich brauche einige Abläufe die simultan und nicht der reihe nach ablaufen.
Da wären Servos die ein paar Bewegungen ausführen, WS2812 LED´s welche die farben wechseln, ein Soundmodul das abgespielt werden will und die nächste Hürde wird wohl noch eine Funkverbindung zu einem weiteren Mini.

Die Abstände der einzelnen Module zueinander ist nicht ser groß, tatsächlich sollen später alle auf einer Platine Platz finden.

Im Moment nutze ich einen Micro als Master und 3 Minis als Slave (Ton, Licht, Servos und Motoren).
Die PWM Methode funktionert ganz gut, hat aber einen Nachteil dass es immer mal wieder spitzen gibt und man mit einem gewissen Spielraum arbeiten muss.

Hier Mal die Skechtes damit man sieht wie ich es gelöst habe.
Für Anregungen und Verbesserungvorschläge bin ich immer offen.

Sender:

/*Analogwrite values from 0 to 255
 look serieal monitor on reciver to figure out
*/


int compin = 5;      // comunicationpin to other arduino connected to digital pin 5

const int buttonPin = 1;     
const int buttonPin2 = 2;   
const int buttonPin3 = 3;  

const int ledPin =  13; 

int buttonState = 0;
int buttonState2 = 0;
int buttonState3 = 0;

void setup()
{
  pinMode(compin, OUTPUT);  
  pinMode(buttonPin, INPUT);
  pinMode(buttonPin2, INPUT);
  pinMode(buttonPin3, INPUT);
  pinMode(ledPin, OUTPUT);
}

void loop() {
  buttonState = digitalRead(buttonPin);
  buttonState2 = digitalRead(buttonPin2);
  buttonState3 = digitalRead(buttonPin3);

  if (buttonState == HIGH) {
    digitalWrite(ledPin, HIGH);
    analogWrite(compin, 50);
    delay (50);
  }
  if (buttonState2 == HIGH) {
    digitalWrite(ledPin, HIGH);
    analogWrite(compin, 100);
    delay (50);
  }
  if (buttonState3 == HIGH) {
    digitalWrite(ledPin, HIGH);
    analogWrite(compin, 150);
    delay (50);
  }
  else {
    digitalWrite(ledPin, LOW);
    analogWrite(compin, 0);
  }
}

und die Codes der Empfänger

[/code]

Empfänger Ton

// Eingebundene Bebliotheken

#include <Wire.h> // Wire Bibbliothek für mp3 player
#include "SoftwareSerial.h"
#include "DFRobotDFPlayerMini.h" //Bibbliothek für mp3 player

// Festgelegte Belegung
/*MP3 PLayer*/
SoftwareSerial mySoftwareSerial(0, 1); // RX, TX
DFRobotDFPlayerMini myDFPlayer;
void printDetail(uint8_t type, int value);

// Variablen
volatile int pwm_value = 0; //written by transmitter
volatile int prev_time = 0;

/*delay platzhalter*/
int delay_blink = 50;
int delay_blink2 = 250;
int delay_blink3 = 500;

void setup() {
  /*PWM lesen*/
  attachInterrupt(0, rising, RISING);    // when pin D2 goes high, call the rising function

  /*mp3 player setup*/
  mySoftwareSerial.begin(9600);
  (!myDFPlayer.begin(mySoftwareSerial));
  myDFPlayer.volume(20);                    //lautstärke von 0 = 30

  pinMode(LED_BUILTIN, OUTPUT); //kontroll led
}

void loop()
{
  if (pwm_value > 200 && pwm_value < 210) {
    digitalWrite(LED_BUILTIN, HIGH);
    myDFPlayer.playMp3Folder(0000); // start first mp3 file
    myDFPlayer.playMp3Folder(0001); 
    delay (5500);
    myDFPlayer.playMp3Folder(0002);
    delay (2000);
    digitalWrite(LED_BUILTIN, LOW);
    pwm_value = 0;                        //pwm_value to 0 to stop working
  }
  if (pwm_value > 400 && pwm_value < 410) {
    digitalWrite(LED_BUILTIN, HIGH);
    delay(delay_blink);
    digitalWrite(LED_BUILTIN, LOW);
    delay(delay_blink);
    pwm_value = 0;
  }
  if (pwm_value > 600 && pwm_value < 610) {
    digitalWrite(LED_BUILTIN, HIGH);
    delay(delay_blink);
    digitalWrite(LED_BUILTIN, LOW);
    delay(delay_blink);
    pwm_value = 0;
  }
  else {
    digitalWrite(LED_BUILTIN, LOW);
  }
}

void rising()
{
  attachInterrupt(0, falling, FALLING);
  prev_time = micros();
}

void falling()
{
  attachInterrupt(0, rising, RISING);
  pwm_value = micros() - prev_time;
  Serial.println(pwm_value);
}

Empfänger Licht

// Eingebundene Bebliotheken
#include <Adafruit_NeoPixel.h>

// Festgelegte Belegung
/*Neopixel*/
#define PIN            5   //angeschlossen an Pin X
#define NUMPIXELS      8   // X Pixel werden verwendet
Adafruit_NeoPixel strip = Adafruit_NeoPixel(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);

// Variablen
volatile int pwm_value = 0;
volatile int prev_time = 0;

int delay_blink = 50;
int delay_blink2 = 250;
int delay_blink3 = 500;

void setup() {
  /*Neopixel initialisieren*/
  strip.begin();
  strip.show();

  /*PWM lesen initialisieren*/
  Serial.begin(115200);
  attachInterrupt(0, rising, RISING);   // when pin D2 goes high, call the rising function

  pinMode(LED_BUILTIN, OUTPUT); //Kontroll LED
}

void loop()
{
  if (pwm_value > 200 && pwm_value < 210)
  {
    digitalWrite(LED_BUILTIN, HIGH);
    strip.setPixelColor(0, 0, 0, 0);
    strip.setPixelColor(1, 0, 0, 0);
    strip.setPixelColor(2, 0, 0, 0);
    strip.setPixelColor(3, 0, 0, 0);
    strip.setPixelColor(4, 0, 0, 0);
    strip.setPixelColor(5, 0, 0, 0);
    strip.setPixelColor(6, 0, 0, 0);
    strip.setPixelColor(7, 0, 0, 0);
    strip.show();
    delay (14500);
    strip.setPixelColor(0, 50, 50, 0);
    strip.setPixelColor(7, 50, 50, 0);
    strip.show();
    delay(200);
    strip.setPixelColor(0, 100, 100, 0);
    strip.setPixelColor(1, 50, 50, 0);
    strip.setPixelColor(6, 50, 50, 0);
    strip.setPixelColor(7, 100, 100, 0);
    strip.show();
    delay(200);
    strip.setPixelColor(0, 200, 200, 0);
    strip.setPixelColor(1, 100, 100, 0);
    strip.setPixelColor(2, 50, 50, 0);
    strip.setPixelColor(5, 50, 50, 0);
    strip.setPixelColor(6, 100, 100, 0);
    strip.setPixelColor(7, 200, 200, 0);
    strip.show();
    delay(200);
    strip.setPixelColor(1, 200, 200, 0);
    strip.setPixelColor(2, 100, 100, 0);
    strip.setPixelColor(3, 50, 50, 0);
    strip.setPixelColor(4, 50, 50, 0);
    strip.setPixelColor(5, 100, 100, 0);
    strip.setPixelColor(6, 200, 200, 0);
    strip.show();
    delay(200);
    strip.setPixelColor(2, 200, 200, 0);
    strip.setPixelColor(3, 100, 100, 0);
    strip.setPixelColor(4, 100, 100, 0);
    strip.setPixelColor(5, 200, 200, 0);
    strip.show();
    delay(200);
    strip.setPixelColor(3, 200, 200, 0);
    strip.setPixelColor(4, 200, 200, 0);
    strip.show();
    digitalWrite(LED_BUILTIN, LOW);
    pwm_value = 0;
  }
  if (pwm_value > 400 && pwm_value < 410)
  {
    digitalWrite(LED_BUILTIN, HIGH);
    delay(delay_blink);
    digitalWrite(LED_BUILTIN, LOW);
    delay(delay_blink);
    pwm_value = 0;
  }
  if (pwm_value > 600 && pwm_value < 610)
  {
    digitalWrite(LED_BUILTIN, HIGH);
    delay(delay_blink);
    digitalWrite(LED_BUILTIN, LOW);
    delay(delay_blink);
    pwm_value = 0;
  }
  else if (pwm_value > -10 && pwm_value < 10) {
    digitalWrite(LED_BUILTIN, LOW);
  }
}

void rising()
{
  attachInterrupt(0, falling, FALLING);
  prev_time = micros();
}

void falling()
{
  attachInterrupt(0, rising, RISING);
  pwm_value = micros() - prev_time;
  Serial.println(pwm_value);
}

Empfänger Servos und Motoren

#include <Servo.h>

Servo servo1;
Servo servo2;

const int servopower =  4;
const int servo1Pin =  5;
const int servo2Pin =  6;

const int steptime = 350;

volatile int pwm_value = 0;
volatile int prev_time = 0;

int delay_blink = 50;
int delay_blink2 = 250;
int delay_blink3 = 500;

void setup() {
  servo1.attach(5); // Servo an Pin 10
  servo2.attach(6); // Servo an Pin 11

  pinMode(servopower, OUTPUT);
  pinMode(servo1Pin, OUTPUT);
  pinMode(servo2Pin, OUTPUT);

  Serial.begin(115200);
  // when pin D2 goes high, call the rising function
  attachInterrupt(0, rising, RISING);

  pinMode(LED_BUILTIN, OUTPUT);
}

void loop()
{
  if (pwm_value > 200 && pwm_value < 221)
  {
    digitalWrite(servopower, HIGH);
    digitalWrite(LED_BUILTIN, HIGH);
    servo1.write(0);    // max down position / startposition
    servo2.write(150);
    delay(steptime);
    servo1.write(160);    //max up position / pos1
    servo2.write(0);
    delay(steptime);
    servo1.write(40);   //mid position / pos2
    servo2.write(75);
    delay(steptime);
    servo1.write(112);   //pos3
    servo2.write(150);
    delay(steptime);
    servo1.write(40);   //pos4
    servo2.write(37);
    delay(steptime);
    servo1.write(120);    //pos5
    servo2.write(112);
    delay(steptime);
    servo1.write(0);    //pos6
    servo2.write(0);
    delay(steptime);
    servo1.write(80);   //pos7
    servo2.write(75);
    delay(steptime);
    servo1.write(40);    //pos8
    servo2.write(37);
    delay(steptime);
    servo1.write(120);
    servo2.write(112);
    delay(steptime);
    servo1.write(80);
    servo2.write(75);
    delay(steptime);
    servo1.write(40);
    servo2.write(112);
    delay(steptime);
    servo1.write(80);
    servo2.write(75);
    delay(steptime);
    servo1.write(160);
    servo2.write(0);
    delay(steptime);
    servo1.write(120);
    servo2.write(37);
    delay(steptime);
    servo1.write(40);
    servo2.write(112);
    delay(steptime);
    servo1.write(120);
    servo2.write(37);
    delay(steptime);
    servo1.write(0);
    servo2.write(150);
    delay (steptime);
     digitalWrite(LED_BUILTIN, LOW);
     digitalWrite(servopower, LOW);
    pwm_value = 0;
  }
  if (pwm_value > 400 && pwm_value < 410)
  {
    digitalWrite(LED_BUILTIN, HIGH);
    delay(delay_blink);
    digitalWrite(LED_BUILTIN, LOW);
    delay(delay_blink);
    pwm_value = 0;
  }
  if (pwm_value > 600 && pwm_value < 610)
  {
    digitalWrite(LED_BUILTIN, HIGH);
    delay(delay_blink);
    digitalWrite(LED_BUILTIN, LOW);
    delay(delay_blink);
    pwm_value = 0;
  }
  else if (pwm_value > -10 && pwm_value < 10) {
    digitalWrite(LED_BUILTIN, LOW);
  }
}

void rising()
{
  attachInterrupt(0, falling, FALLING);
  prev_time = micros();
}

void falling()
{
  attachInterrupt(0, rising, RISING);
  pwm_value = micros() - prev_time;
  Serial.println(pwm_value);
}

Mir wäre ein einziger Uno oder Mega eigentlich lieber aber ich brauche einige Abläufe die simultan und nicht der reihe nach ablaufen.

Deine Nebenläufigkeit machst du dir mit dem delay() kaputt
Ansonsten sehe ich nicht wirklich, warum das nicht alles in einen Pro Mini, oder anderen (fast) beliebigen Arduino passen sollte.

Ablaufsteuerung
Meine Standardantwort zu Ablaufsteuerungen:

Eine Stichworte Sammlung für Google Suchen:
Endlicher Automat,
State Machine,
Multitasking,
Coroutinen,
Ablaufsteuerung,
Schrittkette,
BlinkWithoutDelay,

Blink Without Delay
Der Wachmann

Multitasking Macros
Intervall Macro

Für Anregungen und Verbesserungvorschläge bin ich immer offen.

ok...
Mit dem PWM, hast du dir eine seltsame Kommunikations Art ausgesucht.
Üblich bei Funkfernsteuerungen, aber das wars auch schon...

Ich verwende I2C, wenn alles dicht zusammen steht.

Und wenn die Entfernungen größer werden UART, und da meist den CmdMessenger.
Wenn mehrere Arduinos verbunden werden sollen, dann wird das wie ein Token-Passing (Token Ring™) System aufgebaut.

Aber, mir scheint, dein Hauptproblem sind erstmal die Nebenläufigkeiten.
Dein per delay() geregeltes "Nacheinander" scheint mir ein Irrweg zu sein.

Ein typischer Arduino schafft fast 16 Millionen Befehle pro Sekunde.
Da fällt das zwangsläufige nacheinander eher nicht so auf.
Es sei denn, man schiebt sich selber mit dem delay() einen Stock in die Speichen.

Übrigens:

void falling()

{
 attachInterrupt(0, rising, RISING);
 pwm_value = micros() - prev_time;
 Serial.println(pwm_value);
}

Die Verwendung von Serial.println() in einer ISR kann/wird zu Deadlocks führen.

const int servo1Pin =  5;

const int servo2Pin =  6;

  servo1.attach(5); // Servo an Pin 10
  servo2.attach(6); // Servo an Pin 11

Solche Kommentare tragen eher zur Verwirrrung bei, als dass sie helfen.
Schreibe im Kommentar, welchen Zweck der Servo erfüllt.

z.B.

  servo1.attach(servo1Pin); // Spiegel horizontal
  servo2.attach(servo2Pin); // Spiegel vertikal

Und es geht noch viel schöner......

Ich finde noch nicht die richtigen Wege um ohne Delays zu arbeiten. Werde mich mal in der nächsten Zeit mit der funktion von Millis beschäftigen, davon habe ih bisher öfter gelesen dass das sehr helfen soll.

Das wird alles nochmal schön geschrieben keine Sorge, sonst blicke ich ja selbst nicht mehr durch sollte ich mal etwas suchen. ;D

Bisher hatte ich immer das Problem dass wenn ich nur mit einem Uno oder Micro arbeiten wollte irgendwo etwas kollidierte und Abläufe nicht so kamen dass sie zum Soundfile passten, der dient mir quasie als Timecode und anhand der Delays schiebe ich meine Funktion, zum beispiel eine LED die die Farbe passend wechselt, an die richtige Stelle.

Werde mich mal in der nächsten Zeit mit der funktion von Millis beschäftigen, davon habe ih bisher öfter gelesen dass das sehr helfen soll.

Ja, das geht in die richtige Richtung!

Denn wenn du einmal gelernt hast, in Nebenläufigkeiten zu denken, lösen sich viele dieser Problem in Luft auf.

noiasca:
Abhängig vom verwendeten Soundmodul (welches?) kann man dir sicher auch helfen.

Ich benutze einen DF Player Mini, der läuft ganz gut.

noiasca:
ich kann dir nur raten HEUTE mit dem Entwirren der delays anzufangen. Ansonsten investierst du jetzt Zeit in eine Konstruktion die Fehleranfällig ist und kaum wartbar ist.

Aye Aye Captain :smiling_face:

Ja dann werde ich mich heute Abend mal an die Millis setzen. Dazu gibt es hier ja schon 999k Tutorials

Ich habe ein "Progrämmchen" in der Wühlkiste, welches auf Wunsch mit der LED an Pin 13 blinkt.
Vom PC aus, kann man die Puls und Pausenzeit einstellen.
Auch kann man das Blinken ein und aus schalten.

:o Aber ich traue mich das gar nicht zu posten/zeigen ..... :o

Aber ich traue mich das gar nicht zu posten/zeigen

Ja, das würde ich auch -ungefragt- für mich behalten. :slight_smile:

Das gibt es erstens schon im Internet tausendfach (zwar bestimmt nicht so gut wie deins :slight_smile: )
Zweitens sollte jeder, den es interessiert, sowas mal selber "erfunden" haben.
Ausserdem ist deins vermutlich "nur" Werbung für deine INTERVAL Bibliothek oder den INTERVAL Ersatzstoff

Vielleicht kriegst du ja eine PM von jemandem.

:wink:

Ausserdem ist deins vermutlich "nur" Werbung für deine INTERVAL Bibliothek oder den INTERVAL Ersatzstoff

Nöö...
Ähnliches Verfahren, aber vor der Zeit.
Ok, der SimpleTimer ist schon drin.

Also:
Ja, es ist Werbung, für eine andere Betrachtungsweise.

Vielleicht kriegst du ja eine PM von jemandem.

Keine Hilfe per PM.
Nie und nimmer.