Forum: Mikrocontroller und Digitale Elektronik Serielle Kommunikation mit 7x7 LED Matrix


von Janik S. (xkap50x)


Lesenswert?

Hallo zusammen,

ich habe gerade ein kleines Problem. Ich möchte eine LED Matrix über die 
Serielle Schnittstelle steuern. Im folgendem erst mal der Arduino Code:
1
#include <FastLED.h>
2
#define NUM_LEDS 50
3
#define DATA_PIN 3
4
CRGB leds[NUM_LEDS];
5
6
void M_RESET() {
7
  for (int i = 0; i < 49; i++) {
8
    leds[i].setRGB(0, 0, 0);
9
  }
10
  FastLED.show();
11
}
12
13
void setup() {
14
  FastLED.addLeds<WS2811, DATA_PIN>(leds, NUM_LEDS);
15
  Serial.begin(115200);
16
  M_RESET();
17
}
18
void loop() {
19
  int i = 0;
20
  while (Serial.available() > 0) {
21
    leds[i].setRGB(Serial.parseInt(), Serial.parseInt(), Serial.parseInt());
22
    Serial.println(i);
23
    i++;
24
    if(i > 48) {
25
      FastLED.show();
26
      i = 0;
27
    }
28
  }
29
}

Wenn ich beispielsweise den String 
"0,255,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,0,255,0,255,0,0,255,0,0 
,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,0,0,255 
,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,0,0,255,0,0,255,0,0,255,255,0,0 
,255,0,0,255,0,0,255,0,0,255,0,0,0,0,255,255,0,0,255,0,0,255,0,0,255,0,0 
,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,0,255,0,255,0,0,255,0,0 
,255,0,0,255,0,0,255,0,0,0,255,0,"  sende, dann nehmen alle LEDs die 
richtige Farbe an, soweit so gut.
Wenn ich aber nach kurzer Zeit denselben (oder einen anderen) String 
abschicke, wird auf der Matrix nur noch ein Haufen Schwachsinn 
angezeigt.
Auf dem seriellem Monitor kann ich zunächst nur (durch 
Serial.println(i); ) die Zahlen 0-48 sehen, so wie es ja sein sollte, 
aber nach wenigen Sekunden taucht noch eine "0" auf. Und wenn man bevor 
die "0" auftaucht einen weiteren String abschickt geht das Bild kaputt, 
wenn man wartet, bis die "0" erscheint, ist alles ok.

Jetzt frage ich mich wieso überhaupt noch etwas empfangen wird. Ich 
beschäftige mich noch nicht lange mit Serieller Kommunikation, deswegen 
ist es möglich, dass ein sehr "billiger" Fehler vorliegt, sorry im 
Voraus für mein Unwissen ^^

Lg
Janik Sch.

von Michael U. (amiga)


Lesenswert?

Hallo,

ich halte Deine Auswertung der ankommenden Daten für etwas gewagt.
Wie schickst Du diese und stellst so sicher, daß alle umgehend versebdet 
werden und die Anzahl immer stimmt (Tippfehler usw.)

Wenn das erste Zeichen auftaucht, läßt Du mit Serial.parseInt() nach 
Integer suchen und auswerten.
Wer sagt Dir, daß überhaupt schon genug Zeichen im seriellen Buffer 
angekommen sind?

Einlesen, bis ein Komma kommt, dannd en Wert parsen und übergeben könnte 
gehen. Außerdem NewLine o.ä. als Ende-Zeichen, damit Du den Kram wieder 
auf Start bekommst, wenn die Anzahl mal nicht stimmte.
Du hörst nach 48 gewandelten Werten auf.
Ob die wirklich Deinen getrennten Werten entsprechen oder z.B. aus 
0,255, plötzlich ein 0 2 55 für die ersten drei Werte wird, hängt so nur 
davon ab, wie schnell die Zeichen kommen und bearbeitet werden können.

Gelesene Daten einem String zuordnen, bis ein Komma kommt.
Wandeln in int und merken.
Wenn 3 Werte für die Farben da sind, setRGB aufrufen.
Wenn alle Werte da sind und das letzte Zeichen Dein Endezeichen war, 
FastLED.show() aufrufen.
Jedes eingelesen Zeichen auf Dein Endezeichen prüfen, wenn das kommt und 
nicht ausreichend Daten da sind, abbrechen und Fehlermeldung.

Gruß aus Berlin
Michael

von Janik S. (xkap50x)


Lesenswert?

Hi, danke für die Antwort!
Ich habe bereits mit verschiedenen Versionen getestet. Ich habe den 
ganzen String auslesen lassen, aber festgestellt, dass es in C wohl 
relativ kompliziert ist einen String in Integer zu splitten... Ich habe 
es jedenfalls nicht hinbekommen, hättest du ein Code Ausschnitt, der mir 
aus einem String wie "255,0,24" drei integer gibt? Dann bräuchte ich ja 
bei Serial.readUntilString() das Zeichen einsetzen, welches dann immer 
nach drei Zahlen kommt, und es müsste funktionieren. Oder kann ich 
einfach die Serial.readUntilString(',') machen und den Wert in einer 
globalen Variablen speichern (zuerst r, dann g, dann b) und eine weitere 
globale, die mir sagt, on es eben gerade r, g oder b ist? Oder wäre das 
so unschön, dass jeden erfahrenem Programmierer die Haare ausfallen 
würde? :D

Es ist unwahrscheinlich, dass eine andere Anzahl als 49*3 Zahlen 
ankommen, da der Code computergeneriert wird, trotzdem kann ich das 
versuchen zu fixen, aber ich bräuchte vielleicht einen Ansatz. Also ein 
Link oder ein Beispiel für mein Problem, wäre supi :)

Lg

von Michael U. (amiga)


Lesenswert?

Hallo,

natürlich kannst Du mit Serial.readUntilString(',') die Werte lesen.
Gahen wir mal davon aus, daß der Datenblock immer ok ist.
1
  if (Serial.available())
2
  {
3
    for (char i=0; i<48; i++)
4
    {
5
      String rot = Serial.readStringUntil(',');
6
      char rotwert = rot.toInt(); 
7
      String gruen = Serial.readStringUntil(',');
8
      char gruenwert = gruen.toInt(); 
9
      String blau = Serial.readStringUntil(',');
10
      char blauwert = blau.toInt();
11
12
      leds[i].setRGB(rot, gruen, blau);
13
    }
14
  }
15
16
  FastLED.show();

sollte als Ansatz so klappen.

readStringUntil() liest bis zum Endezeichen oder bis timeout, wenn 
nichts kommt.
toInt() liefert auch 0 zurück, wenn nichts sinnvolles im String war.

Gruß aus Berlin
Michael

von Karl M. (Gast)


Lesenswert?

Hallo Janik,

denn sende doch keine Integer !

Ich würde mir bei solch einer Anforderung, in einer geeigneten 
Programmiersprache, eine anderes Datenprotokoll definieren.

Auf jeden Fall werden die Nutzendaten <rgbN> binär gesendet.
Die <Kopfdaten> könnten einfach eine fortlaufende Nunmmer sein;
die <crc-16> ist eine binäre 16 Bit CRC Checksumme.
<Kopfdaten><rgbN>..<crc-16>

von Michael U. (amiga)


Lesenswert?

Hallo,

wenn er LED-Nummer, RGB, \n für jede LED schickt, ist es ohnehin 
flexibler, man kann einfach einzelne LEDs oder Gruppen umfärben.
Eine Prüfsumme kann man sich sehr wahrscheinlich hier sparen, so 
lebenswichtig dürfte eine falsche LED-Farbe icht sein und Fehler habe 
ich z.B. bei 30cm Kabel im Drahtverhau mit 115200 zwischen ProMini und 
USB-Adapter bisher keine.

Gruß aus Berlin
Michael.

von Frank E. (Firma: Q3) (qualidat)


Lesenswert?

Wo ist eigentlich das Problem, einfach gleich Binärwerte zu senden?

ICH mache das in einer etwas größeren Anwendung (Arduino Mega und 
RGB-Matrix 32x64) so, dass ich immer zuerst 2Byte für die Anzahl der 
Pixel sende, dann die Pixelwerte und dann auf ein OK vom Arduino warte. 
Kommt das zu früh oder nicht, weiss ich, da ist was schief gelaufen und 
sende ggf. einfach binäre Nullen, bis es kommt ...

So ein Minimum an Handshake macht das Leben bedeutend einfacher :-)

Anderer Ansatz: Der Wert 1-1-1 (RGB) ist übrigens so dunkel, dass man 
getrost auf 0-0-0 verzichten kann um dieses quasi als Synchronzeichen zu 
verwenden.

von Karl M. (Gast)


Lesenswert?

Hallo Janik,

rechne dir bitte auch den Baudraten-Fehler für 115200 Bit/s bei Fclk = 
16MHz aus !

Siehe Datenblatt, da sieht man schon, dass das vorhaben nicht klappen 
kann.

Fall a) mit Vorteiler 1:16
16MHz/16/8 ==> 125,000 kBit/s
16MHz/16/9 ==> 111,111 kBit/s

Fall b) mit Vorteiler 1:8
16MHz/8/17 ==> 117,647 kBit/s

relativer Fehler
error = (1 - 117,647 kBit/s /115,200 kBit/s) *100
error = +2,12%

von Michael U. (amiga)


Lesenswert?

Hallo,

rechnerisch alles richtig.
Praktisch lief bei mir bisher 115200 mit den üblichen USB-TTL-Adaptern 
immer zuverlässig an einem 16MHz AVR.

1,5% sind sicher, praktisch verkraften UARTs mit Mehrfachabtastung der 
Bitzeit bis nahe 6% ohne aus dem Tritt zu kommen.

Ich habe hier jetzt mit einem Nano und 115200 nicht einen Fehler in den 
übertragenen Daten seit ca. 10 Minuten Laufzeit im Loop.
Verlorene Bytes passieren da schneller, wenn der AVR noch mehr zu tun 
hat, dann reicht sein serieller Puffer gern mal nicht aus, wenn man 
nicht aufpaßt im Programm.

Gruß aus Berlin
Michael

von Janik S. (xkap50x)


Lesenswert?

Michael U. schrieb:
> if (Serial.available())
>   {
>     for (char i=0; i<48; i++)
>     {
>       String rot = Serial.readStringUntil(',');
>       char rotwert = rot.toInt();
>       String gruen = Serial.readStringUntil(',');
>       char gruenwert = gruen.toInt();
>       String blau = Serial.readStringUntil(',');
>       char blauwert = blau.toInt();
>       Serial.println(i - '0'); //Von mir hinzugefügt
>       leds[i].setRGB(rot, gruen, blau);
>     }
>   }
>
>   FastLED.show();

Hallo Leute, danke für die ganze Hilfe, ich kann leider wegen meinen 
geringen Kenntnissen nicht mit allem was anfangen, aber ich bemühe mich 
:)

Den Code habe ich sofort mal ausprobiert und das Ergebnis ist dasselbe 
wie vorher. Nachdem die LEDs alle so leuchten, werden trotzdem noch 
Bytes zurückgegeben! Ich habe im Code ein Serial.println eingefügt und 
bekomme nach der einen Übertragung ungefähr alle 2-3 Sekunden eine 
Antwort, wieso?? Mein Serieller Monitor sieht so aus:
-48
-47
-46
-45
-44
-43
-42
-41
-40
-39
-38
-37
-36
-35
-34
-33
-32
-31
-30
-29
-28
-27
-26
-25
-24
-23
-22
-21
-20
-19
-18
-17
-16
-15
-14
-13
-12
-11
-10
-9
-8
-7
-6
-5
-4
-3
-2
-1
-48
-47
-46
-45
-44
-43
-42
-41
-40
-39
-38
-37
-36
-35
-34
-33
-32
-31
-30
-29
-28
-27
-26
-25
-24
-23
-22
-21
-20
-19
-18
-17
-16
-15
-14
-13
-12
-11
-10
-9
-8
-7
-6
-5
-4
-3
-2
-1

Die Daten werden alle doppelt übertragen? Und wieso zuerst "instant" und 
beim zweiten Mal dann mit einem so großem Abstand? Ich versteh das 
wirklich nicht, vielleicht hat ja jemand ne Idee, weil dann könnte ich 
ja auch mit meinem Ursprünglichem Code arbeiten, wenn diese merkwürdigen 
Übertragungen nach der geplanten Übertragung verschwinden würden.

Lg

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.