Kommunikation zwischen 2 "Arduinos"

Hallo,
ich habe einen Sainsmart Mega 2560 mit dem 8U… und einen Nachbau des Arduino Mega 2560 R3.
Einer der beiden soll eine 16x16 RGB-LED-Matrix multiplexen, der andere soll ihm die Bilder senden, die er darstellen soll.
Wie stelle ich das am besten an?

Ich habe es bereits mit SoftSerial versucht, vergebens.
Dabei habe ich Pin 7 mit Pin 6 und Pin 6 mit Pin 7 verbunden, halt überkreuz,
und folgenden Code benutzt:

/*
  Software serial multple serial test
 
 Receives from the hardware serial, sends to software serial.
 Receives from software serial, sends to hardware serial.
 
 The circuit: 
 * RX is digital pin 2 (connect to TX of other device)
 * TX is digital pin 3 (connect to RX of other device)
 
 created back in the mists of time
 modified 9 Apr 2012
 by Tom Igoe
 based on Mikal Hart's example
 
 This example code is in the public domain.
 
 */
#include <SoftwareSerial.h>

SoftwareSerial mySerial(6, 7); // RX, TX | bzw. 7, 6

void setup()  
{
 // Open serial communications and wait for port to open:
  Serial.begin(9600);

  // set the data rate for the SoftwareSerial port
  mySerial.begin(4800);
}

void loop() // run over and over
{
  if (mySerial.available())
    Serial.write(mySerial.read());
  if (Serial.available())
    mySerial.write(Serial.read());
}

Was habe ich falsch gemacht, oder gibt es Alternativen die funktionieren?
Zu beachten ist, dass der Multiplex-“Arduino” SPI verwendet, um den TLC anzusteuern, der zweite “Arduino” soll ihm Frames, die er von einer SD-Karte “live” liest, oder vom Computer über Serial erhält, senden.

Hallo,

diese Codezeile bzw. der Kommentar verwirren mich: SoftwareSerial mySerial(6, 7); // RX, TX | bzw. 7, 6

Hast Du den selben Code auf beiden Arduino? Oder auf dem zweiten die Pin's gedreht? Dann sollte die Verbindung nicht auch gekreuzt werden.

Grüße, Jürgen

Verbindung überkreuz und zwei versch. Sketches, sprich Pins getauscht.

Dann nicht kreuzen, sonst kommt RX auf RX und TX auf TX

Ok, danke!
Ich werds umstecken, testen und berichten.

Der Mega hat insgesamt 4 UART's die du verwenden kannst. Warum benutzt du die SoftSerial?

Was meinst du damit?
Wie soll ich es sonst machen?
Bin ja wie gesagt für Alternativen offen.

Edit:
Ich bringe SoftSerial einfach nicht zum Laufen.

Du sollst gänzlich auf die Softserial verzichten und statt dessen die Pins für die Hardware-UART nutzen. Das sollten die Pins 14-19 sein, die du als Serial1, Serial2 bzw. Serial3 nutzen kannst.

Achso, ja stimmt, ich hab das ganz vergessen. Mal schaun.

Danke.
Ich benutze jetzt Serial1. :wink:

Noch ne Frage:
Ich möchte per Serial die RGB Werte senden.
Das sind 64 * 3 Stück getrennt durch Kommata.
Wie schnell muss ich für 25 FPS die Baud-Rate machen.
Eigentlich doch 20800 oder, da 64 * (3 * 3 + 4) * 25 ?

Das wären dann 208000 (1 Zeichen braucht 10 Bits in der seriellen Übertragung), wenn Du's mit ASCII überträgst. Wenn Du's binär überträgst, kannst Du's auf (64 * 3 + 1) * 25 * 10bit = 48250 runterschrauben, was Du mit dem USART auch problemlos hinkriegen solltest.

Ich übertrage ja pro Pixel in folgendem Format: rrr,ggg,bbb,

Das Problem ist halt, dass auch noch gemultiplext werden muss. Eine zu hohe Baud-Rate könnte das Multiplexen stören oder?

Ich übertrage ja pro Pixel in folgendem Format: rrr,ggg,bbb,

Das habe ich schon kapiert, aber deshalb machte ich ja den Vorschlag, es per rgbrgbrgb... zu übertragen. Damit brauchst Du nicht mal einen Viertel der Übertragungskapazität.

Eine zu hohe Baud-Rate könnte das Multiplexen stören oder?

Könnte durchaus sein. Eine Baudrate von 230400 unterbricht den Arduino über 23040 Mal pro Sekunde, um das Byte aus dem Register in den Puffer zu schreiben. Zudem hast Du auf dem Arduino auch noch den Aufwand, die ASCII-Zeichen wieder in Integer zurückzukonvertieren. Alles viel Arbeit für die Katz. ASCII-Übertragung kann Sinn ergeben, wenn Menschen die Kommunikation mitlesen oder selbst verfassen müssen. Aber effizient ist das praktisch nie.

Ok, aber genauer soll ich das realisieren?
Ich hab momentan folgenden Code:

[...]
const int MatrixWidth = NUM_ROWS;
const int MatrixHeight = NUM_COLUMNS;

int PixelColor[MatrixWidth+1][MatrixHeight+1][4];

int SerialData;

int CurrentRow = 1;
int CurrentColumn = 1;

String CurrentColor = "r";

String rValue = "";
String gValue = "";
String bValue = "";

int LEDCounter = 0; //Wenn auf 64, sprich alle Pixel gesendet wurden, Bild zeichnen
[...]
if (Serial1.available())
  {
    SerialData = Serial1.read()-'0';
    if (CurrentColor=="r")
    {
      if(SerialData<0||SerialData>9)
      {
        CurrentColor="g";
      }
      else
      {
        rValue+=SerialData;
      }
    } 
    else if (CurrentColor=="g")
    {
      if(SerialData<0||SerialData>9)
      {
        CurrentColor="b";
      }
      else
      {
        gValue+=SerialData;
      }
    } 
    else if (CurrentColor=="b")
    {
      if(SerialData<0||SerialData>9)
      {
        //Serial.println("r="+r+" g="+g+" b="+b);
        LEDCounter++;
        
        char rValue_as_char[rValue.length()+1];
        rValue.toCharArray(rValue_as_char, rValue.length()+1);
        int rValue_as_int = atoi(rValue_as_char);
        
        char gValue_as_char[gValue.length()+1];
        gValue.toCharArray(gValue_as_char, gValue.length()+1);
        int gValue_as_int = atoi(gValue_as_char);
        
        char bValue_as_char[bValue.length()+1];
        bValue.toCharArray(bValue_as_char, bValue.length()+1);
        int bValue_as_int = atoi(bValue_as_char);
        
        //Serial.println("r="+String(rValue_as_int)+" g="+String(gValue_as_int)+" b="+String(bValue_as_int));

        rValue = "";
        gValue = "";
        bValue = "";
        
        CurrentColor="r";
        
        PixelColor[CurrentRow][CurrentColumn][1] = rValue_as_int;
        PixelColor[CurrentRow][CurrentColumn][2] = gValue_as_int;
        PixelColor[CurrentRow][CurrentColumn][3] = bValue_as_int; 
      
        if(CurrentRow == 8)
        {
          if(CurrentColumn == 8)
          {
            CurrentColumn = 1;
          }
          else
          {
            CurrentColumn += 1;
          }
          CurrentRow = 1; 
        }
        else
        {
         CurrentRow += 1;
        }
      }
      else
      {
        bValue+=SerialData;
      }
    }
  }
[...]

Als Erstes: für solche Sachen nie die String-Klasse benutzen. Die zerstückelt Dir den Speicher auf unbrauchbare Grössen, schneller als Du denken kannst. Da in der aktuellen IDE zudem noch ein Speicherleck im Code ist, wird Dein Code damit keine 2 Sekunden durchstehen. Zudem: Code willst Du fast 25’000 Mal pro Sekunden ausführen und auch noch etwas LED-Hardware ansteuern? Ich wünsche Dir viel Erfolg, aber das wird schiefgehen.

Ich würde die Synchronisation extern (also z.B. ein separater Pin oder etwas ähnliches) machen und die Werte dann direkt schreiben bzw. lesen:

uint8_t pixelColor[NUM_ROWS][NUM_COLUMNS][3];
for (uint8_t y = 0; < NUM_ROWS; y++) {
  for (uint8_t x = 0; x < NUM_COLUMNS; x++) {
    Serial.write(pixelColor[y][x], 3);
  }
}

Lesen:

uint8_t pixelColor[NUM_ROWS][NUM_COLUMNS][3];
uint8_t x = 0, y = 0, c = 0;
while (y < NUM_ROWS) {
  while (! Serial.available());
  pixelColor[y][x][c++] = Serial.read();
  if (c >= 3) {
    c = 0;
    x++;
  }
  if (x >= NUM_COLUMNS) {
    x = 0;
    y++;
  }
}

Mit solchem Code könntest Du schnell genug sein.

Wenn die externe Synchronisation nicht möglich ist, würde ich z.B. den hellsten Farbton als Marke definieren und bei den Farben 255,255,255 zu 254,254,254 umdefinieren. Dann kannst Du am Anfang immer 255,255,255 schicken und weisst, dass jetzt ein neues Frame anfängt.

Ok, das mit der Synchronisation wäre eine Überlegung Wert, ich halte dieses Vorgehen allerdings nicht für sehr gut, da ich vom PC an Arduino1 und von Arduino1 an Arduino2 mittels Serial die Daten sende und das deshalb lieber so machen möchte, dass er immer den gesamten Frame sendet.

Edit: Ich habe die Strings genommen, um die durch Serial.read erhaltenen Werte aneinanderzuhängen, also z.B. 2 5 5 zu 255. Wie soll ich das ganze mit einem byte-Array für die Pixelfarben und der Übertragung in bytes machen?

Komisch ist ja auch, dass mit 9600-baud alles klappt (2FPS) und wenn ich die baud-Rate erhöhe, es nicht mehr funktioniert.

Außerdem, wie soll ich die Kommunikation ohne Kommata durchführen? Wenn ich die z.B. 0, 50, 0 habe, woher soll der Arduino wissen, dass 0500 dieser Farbe entspricht? Andersrum: Wie könnte ich das machen um das so zu senden: 000050000?

Ok, das mit der Synchronisation wäre eine Überlegung Wert, ich halte dieses Vorgehen allerdings nicht für sehr gut, da ich vom PC an Arduino1 und von Arduino1 an Arduino2 mittels Serial die Daten sende und das deshalb lieber so machen möchte, dass er immer den gesamten Frame sendet.

Es geht ja gerade darum, immer den gesamten Frame zu senden, eine Synchronisation ist trotzdem notwendig.

Wie soll ich das ganze mit einem byte-Array für die Pixelfarben und der Übertragung in bytes machen?

Jedes Byte ist eine Pixel-Grundfarbe, 3 Bytes sind also ein ganzes Pixel.

Komisch ist ja auch, dass mit 9600-baud alles klappt (2FPS) und wenn ich die baud-Rate erhöhe, es nicht mehr funktioniert.

Solange Du SoftwareSerial verwendest, wundert mich das nicht.

Außerdem, wie soll ich die Kommunikation ohne Kommata durchführen?

Hast Du Dir den Code von mir angeschaut? Dort wird jeweils ein Byte pro Pixel und Farbe gesendet und Du hast überhaupt keinen Trennbedarf.

Ich verwende kein Softserial und trotzdem klappt es nur bei 9600baud. Bei deinem wird doch ein zusätzlicher Pin benutzt, für die Synchronisation, oder?

Bei deinem wird doch ein zusätzlicher Pin benutzt, für die Synchronisation, oder?

Das war eine Anmerkung, falls Du eine Synchronisation brauchst. Wenn Du sicherstellen kannst, dass die Arduinos immer in der richtigen Reihenfolge gestartet werden und jedes Byte wirklich über die serielle Schnittstelle geht, kannst Du Dir das auch sparen. Falls Du eine Synchronisation willst/brauchst, habe ich Dir eine rein softwaremässige Möglichkeit auch aufgezeigt. Liest Du meine Posts überhaupt?