Forum: Mikrocontroller und Digitale Elektronik Arduino DMX 256 Kanäle als Paket senden


von andyK (Gast)


Lesenswert?

Hallo,

ich suche eine Möglichkeit per Arduino 256 DMX Kanäle auf einmal (also 
als Paket) zu senden.
Ich habe einen DMX fähige Strahler der 256 LEDs besitzt die als Matrix 
angeordnet sind und die sich per DMX steueren lassen. (American DJ Revo 
4)

Ich habe schon ein paar DMX Projekte mit den allgemein bekannten 
Libraries aufgebaut, allerdings besitze ich leider nicht die tiefe 
Kenntnis, wie ich die Befehle optimieren kann.
Ich möchte auf Kopfdruck verschiedene Muster auf der Martix abrufen.
Ich habe versucht die Infos in ein Array zu speichern und dann 
abzurufen, aber das ist viel zu langsam.

Jetzt suche ich Hilfe, ob mir evtl Jemand sagen kann wie ich die 256 DMX 
Befehle in einem Rutsch senden kann.

Bin leider nicht der erfahrenste Programmierer und würde mich über Hilfe 
sehr freuen.

Vielen Dank und Grüße

von Falk B. (falk)


Lesenswert?

@andyK (Gast)

>ich suche eine Möglichkeit per Arduino 256 DMX Kanäle auf einmal (also
>als Paket) zu senden.

Das sollte relativ leicht gehen.

>Ich habe schon ein paar DMX Projekte mit den allgemein bekannten
>Libraries aufgebaut,

Dann sollte es noch leichter sein.

>allerdings besitze ich leider nicht die tiefe
>Kenntnis, wie ich die Befehle optimieren kann.

Also eher nahezu NULL Programierkenntnisse?

>Ich möchte auf Kopfdruck verschiedene Muster auf der Martix abrufen.

Das ist leicht.

>Ich habe versucht die Infos in ein Array zu speichern und dann
>abzurufen, aber das ist viel zu langsam.

Das ist ein Irrtum. Genau so macht man das. Und mit den richtigen Aufruf 
kann man die Daten auch problemlos und schnell senden.

>Jetzt suche ich Hilfe, ob mir evtl Jemand sagen kann wie ich die 256 DMX
>Befehle in einem Rutsch senden kann.

Zeig doch erstmal deinen aktuellen Quelltext. Dann reden wir weiter. 
SIehe Netiquette.

von Andy K. (andykoa)


Lesenswert?

(jetzt als Nicht-Mehr-Gast)

Hallo Falk,

danke für die schnelle Reaktion.
Es gibt noch keinen Quelltext da ich es erst mal theoretisch abklären 
wollte.

Ich nutze meist die SimpleDMX Library
Da werden die DMX Kanäle sehr einfach angesprochen:
DmxSimple.write(KANAL, WERT);

Ich dachte es wäre sinnvoll mir einen Editor zu schreiben, in dem ich 
auf dem 16x16 Matrix Muster generieren kann und in irgendeiner Form 
abspechern kann.
Im Grunde dachte ich an einen String aus 256 mal 1 oder 0 der dann für 1 
Muster steht.

Dann müsste der String wieder ausgelesen werden.
Das Ganze kann natürlich auch in ein Array geladen werden - Ich nutze 
einen Arduino Mega, damit sollte es vom Speicher her kein Problem sein.

Ich dachte nur, man könnte den binären String irgendwie umwandeln um 
Speicher zu sparen und dann wieder zurückwandeln zum auslesen.

Ich habe schon ein wenig Programmierkenntnisse - aber ich lerne noch und 
passe Beispiele so an daß es irgendwie funktioniert.

Es gibt sicher Leute die schöneren und effektiveren Code schreiben.

Ich hatte das mit dem Array mal versucht und über eine Schleife die 256 
Werte ausgelesen und per Befehl  DmxSimple.write(KANAL, WERT); an die 
DMX Lampe gesendet - war sehr langsam was sich bei einem Wechsel der 
Muster bemerkbar gemacht hat.

Also wenn dir etwas einfällt wie man die 256 Werte schneller sendet, 
würde ich mich über Vorschläge oder Beispiele sehr freuen.

Vielen Dank und Gruß.

: Bearbeitet durch User
von Bastian W. (jackfrost)


Lesenswert?

Wenn du das als String sendest brauchst 256 Byte für dein Muster , wenn 
du das als 32 x uint8 sendest brauchst du nur 32 Bytes.

Zum senden vom PC kannst du da HTerm nutzen.

Gruß JackFrost

: Bearbeitet durch User
von Andy K. (andykoa)


Lesenswert?

Und genau hören bei mir leider die Fähigkeiten auf.

Nehmen wir mal an ich würde ein Muster binär speichern:

0000111100001111
0000111100001111
0000111100001111
0000111100001111
0000111100001111
0000111100001111
0000111100001111
0000111100001111
0000111100001111
0000111100001111
0000111100001111
0000111100001111
0000111100001111
0000111100001111
0000111100001111
0000111100001111

256 Werte (16 x 16):

000011110000111100001111000011110000111100001111000011110000111100001111 
000011110000111100001111000011110000111100001111000011110000111100001111 
000011110000111100001111000011110000111100001111000011110000111100001111 
0000111100001111000011110000111100001111

Wie kann ich das Platzsparend speichern und wieder schnell auslesen?
mit einer Schleife?

Im Grunde würde ich gerne 20-40 Muster speichern.

: Bearbeitet durch User
von fop (Gast)


Lesenswert?

Bastian W. schrieb:
> Zum senden vom PC kannst du da HTerm nutzen.

Ich fürchte eher nicht, jedes Datenpaket auf dem DMX-Bus fängt mit einem 
Break an, das man mit normalen Terminalprogrammen nicht so einfach 
erzeugen kann. Ausserdem muss ständig ein neues Paket kommen, sonst 
vermuten die Empfänger einen Kabelbruch und gehen in einen Notlauf.

Man müsste mal den Quelltext von
1
DmxSimple.write()
 durchstöbern. Der legt das eine Byte vermutlich in einem Array ab, 
welches er dann im Interrupt ausgibt.

von Bastian W. (jackfrost)


Lesenswert?

Beine 256 Bits sind ja 32 Byte. Als String sind es 256 Byt.

Wenn es kleiner als 32 Bytes sein soll musst du komprimieren aber für 
das senden über DMX wieder entpacken.

Zum senden der 32 Bytes als 256 Kanäle musst du nur eine For-Schleife 
nutzen in der dann das entsprechende Bit maskiert wird und wenn es 1 ist 
wird eine 1 gesendet sonst eine 0.

Gruß JackFrost

von Dennis K. (scarfaceno1)


Lesenswert?

Bastian W. schrieb:
> Wenn du das als String sendest brauchst 256 Byte für dein Muster , wenn
> du das als 32 x uint8 sendest brauchst du nur 32 Bytes.
>
> Zum senden vom PC kannst du da HTerm nutzen.
>
> Gruß JackFrost

Ich denke nicht.

Der Wert für einen DMX Kanal ist immer ein Byte.
Auf dem Bus hast du also bei normalerweise 512 DMX Kanälen also 512 
Byte.
Sendest du nur die ersten 256 Byte, was durchaus möglich ist, dann 
benötigst du auch 256 Byte. Du kannst keine 32x uint8 senden.

von Bastian W. (jackfrost)


Lesenswert?

Ich bin vom ersten Post ausgegangen das es in seiner Matrix nur an und 
aus gibt.

Gruß JackFrost

von Falk B. (falk)


Lesenswert?

@ Andy Koa (andykoa)

>Es gibt noch keinen Quelltext da ich es erst mal theoretisch abklären
>wollte.

Dann hast du uns Märchen erzählt!

"Ich habe schon ein paar DMX Projekte mit den allgemein bekannten
Libraries aufgebaut,"

Man könnte es auch neudeutsch Fake News nennen!

>Ich nutze meist die SimpleDMX Library

Link?

>Da werden die DMX Kanäle sehr einfach angesprochen:
>DmxSimple.write(KANAL, WERT);

Da gibt es sicher andere Funktion, um die Daten dort reinzuschreiben. Im 
Extremfall greift man direkt auf die Membervariablen zu. Oder man 
schreibt eine einfache, neue Methode, um Arrays zu kopieren.

>Ich dachte es wäre sinnvoll mir einen Editor zu schreiben,

Laß das erstmal. Vorerst reicht eine manuelle Definiton deiner Daten per 
Hand. Ggf. nimmt man eine Exceltabelle oder sogar old school Papier!

>Ich dachte nur, man könnte den binären String irgendwie umwandeln um
>Speicher zu sparen und dann wieder zurückwandeln zum auslesen.

Was willst du denn bei 256 Bytes für 256 DMX-Kanäle sparen?

>Ich habe schon ein wenig Programmierkenntnisse - aber ich lerne noch und
>passe Beispiele so an daß es irgendwie funktioniert.

Hmmm.

>Es gibt sicher Leute die schöneren und effektiveren Code schreiben.

Dann schreib erstmal welchen! Den kann man dann verbessern!

>Ich hatte das mit dem Array mal versucht und über eine Schleife die 256
>Werte ausgelesen und per Befehl  DmxSimple.write(KANAL, WERT); an die
>DMX Lampe gesendet - war sehr langsam was sich bei einem Wechsel der
>Muster bemerkbar gemacht hat.

Kann sein, weil du erstens 256 mal die Funktion aufrufen mußt und diese 
wahrscheinlich ziemlich aufgeblasen und langsam ist, wie viele andere 
Arduino-Funktionen auch. Das ist aber ein lösbares Problem.

von Falk B. (falk)


Lesenswert?

@Andy Koa (andykoa)

>Nehmen wir mal an ich würde ein Muster binär speichern:

>0000111100001111
>0000111100001111
>0000111100001111
>0000111100001111
>0000111100001111
>0000111100001111
>0000111100001111
>0000111100001111
>0000111100001111
>0000111100001111
>0000111100001111
>0000111100001111
>0000111100001111
>0000111100001111
>0000111100001111
>0000111100001111

>256 Werte (16 x 16):

Bit

"Ich habe einen DMX fähige Strahler der 256 LEDs besitzt die als Matrix
angeordnet sind und die sich per DMX steueren lassen. (American DJ Revo
4)"

Wie werden denn die einzelnen LEDs dieses Strahlers adressiert? Eine 
LED/DMX-Kanal (0-255, dimmbar) oder 8 LEDs/DMX-Kanal (nur ein/aus pro 
LED)

Das ist nämlich die Frage.

>Wie kann ich das Platzsparend speichern und wieder schnell auslesen?
>mit einer Schleife?

Fürs Erste mußt du keinen Platz sparen. Pack die Muster einfach direkt 
in den Flashspeicher und lies sie aus. Der Mega hat mehr als genug 
davon.
Wie das geht, steht in der Arduino-Referenz.

von fop (Gast)


Lesenswert?

Wie Du die Daten senden musst, bestimmt der Empfänger. Wenn Du den 
später auch noch baust und jede Lampe nur an oder aus kennt, kannst Du 
natürlich die Werte bitkodieren und hast dann die Info für 8 Lampen in 
einem Byte.
Willst Du die Lampen dimmen, könntest Du 4 Helligkeitsstufen für 4 
Lampen in ein Byte packen oder 16 Helligkeitsstufen für 2 Lampen.
Normalerweise hat man 256 Helligkeitsstufen in einem Byte pro Lampe. 
Aber auch 65536 Helligkeitsstufen in zwei Byte pro Lampe sollen schon 
gesehen worden sein. Jedenfalls ist bei 512 Bytes Nutzdaten pro 
Datenblock Schicht am Schacht bei DMX512. Es steht Dir natürlich frei 
mehrere Busse zu nutzen. Wenn Du irgendwo den Begriff "universe" liest, 
dann werden da mehrere Busse genutzt und durchnumeriert.
Übrigens, wenn Du die vollen 512 Nutzdatenbytes ausnutzt, kommen die 
Datenblöcke mit ungefähr 40 Hz, schneller blinkt da also nix.

von Andy K. (andykoa)


Lesenswert?

Ich werde mal das Programm neu schreiben und Posten. Ist sicherlich 
einfacher. Auf jeden Fall schon mal Danke für die Tipps und Infos.

von Jürgen B. (hicom)


Lesenswert?

fop schrieb:
[..]
> Übrigens, wenn Du die vollen 512 Nutzdatenbytes ausnutzt, kommen die
> Datenblöcke mit ungefähr 40 Hz, schneller blinkt da also nix.

Ja in Sachen Speed ist DMX schon manch mal eine Spaßbremse, besonders 
wenn man bei LEDs ein sauberers Fading hinlegen will. Aber es steht 
einem frei, DMX auch mit 1Mb oder mehr statt mit 250kb zur fahren, wenn 
man Sender und Empfänger selber baut. Ist dann zwar nicht mehr 
normkonform aber 4x schneller.

Gruß
Jürgen

: Bearbeitet durch User
von Mikki M. (mmerten)


Lesenswert?

American DJ Revo 4 ist ja nicht gerade das HighEnd DMX Endgerät.
Kann in der Tat 256 Kanäle je 26 x R  G  B / W
Dürfte dann wohl auf jeweils 8 Bit PWM umgesetzt werden. Fraglich
ist ob der dort eingetzte Prozessor auch in der Lage ist, innerhalb 
eines
DMX Frame (ca. 20 ms) alle Werte umzurechen und auch synchron 
auszugeben.
Das Teile wird ja auch lediglich als Flower Effekt beworben. und die 
einzelnen R/G/B/W Punkte liegen auch nicht übereinander, also 256 Punkte 
mit unterschiedlicher Helligkeit aber kein Mischfarben.

von Andy K. (andykoa)


Lesenswert?

@Mikki

Das mit den Einschränklungen Revo ist mir absolut bewusst. Deswegen 
versuche ich ja auch etwas mehr herauszukitzeln. Leider kann er nur eine 
handvoll Muster auf Knopfduck darstellen.
Das mit der internen Verarbeitungsgeschwindigkeit des Revos ist 
natürlich eine große Unbekannte.

von Andy K. (andykoa)


Lesenswert?

Hier ist mein kleines Programm was momentan 4 Muster (das erste ist 
leer, also alle Leds aus) anzeigt. Nur leider in einer sehr 
inakzeptablen Geschwindigkeit - man kann den LED fast zuschauen wie sie 
nacheinander aufleuchten.
1
#include <DmxSimple.h>
2
#include <MIDI.h>
3
4
//MIDI_CREATE_DEFAULT_INSTANCE();
5
MIDI_CREATE_INSTANCE(HardwareSerial, Serial1, MIDI);
6
7
byte incomingByte;
8
byte note;
9
byte velocity;
10
byte midichannel;
11
12
int revo_array[] = { 
13
124,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
14
125,1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0,
15
126,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,
16
127,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0
17
}; 
18
19
int revo_array_size = 1028;
20
21
void setup() {
22
23
// MIDI SETUP
24
 
25
  MIDI.setHandleNoteOn(handleNoteOn); // Put only the name of the function
26
  MIDI.setHandleNoteOff(handleNoteOff);
27
  MIDI.begin(MIDI_CHANNEL_OMNI);
28
        
29
// DMX SETUP
30
  DmxSimple.usePin(3);
31
  DmxSimple.maxChannel(512);
32
  
33
}
34
35
void loop () {
36
MIDI.read();
37
38
}
39
40
void handleNoteOn(byte channel, byte note, byte velocity)
41
{
42
  // NOTE ON
43
  // combine midi channel and midi note number
44
  int channelnote = (channel*100)+note;
45
46
  // search for value in array
47
  
48
      for (int i=0; i<=revo_array_size; i=i+257) {
49
        
50
          if (channelnote == revo_array[i]) {
51
          
52
          // DMX OUTPUT
53
54
          for(int d=1;d<=256;d++) {
55
          
56
          DmxSimple.write(d, (revo_array[i+d])*255);
57
            
58
          }
59
          
60
          break;
61
        
62
      }
63
64
    }
65
      
66
}
67
68
void handleNoteOff(byte channel, byte pitch, byte velocity)
69
{
70
  // NOTE OFF
71
}

Zur Erklärung:
Der erste Eintrag 124 ist die Kombination aus MIDI Kanal und MIDI Note - 
in diesem Fall Kanal 1 und Note 24 - Wenn diese Kombination im Array 
gefunden wird, werden die folgenden 256 Werte per DMX an die Lampe 
geschickt. Der Suchpointer macht natürlich 257er Sprünge.

Ich hoffe das ist alles so einigermaßen verständlich.
würde mich freuen wenn hier Jemand eine Idee hätte wie das effizienter 
geht. Evtl. ganz ohne DMX Library sondern direkt.

von Falk B. (falk)


Lesenswert?

@ Andy Koa (andykoa)

>Hier ist mein kleines Programm was momentan 4 Muster (das erste ist
>leer, also alle Leds aus) anzeigt.

Und warum hat dein Array dann nur eine Dimension?

int revo_array[4][256]

wäre da deutlich sinnvoller.


> Nur leider in einer sehr
>inakzeptablen Geschwindigkeit - man kann den LED fast zuschauen wie sie
>nacheinander aufleuchten.

Tja, du bist auch so ein Künstler, der das Problem scheibchenweise 
präsentiert. Denn von MIDI war bisher noch keine Rede!

>#include <DmxSimple.h>

Ich fragte dich nach einem Link für deine DMX-Bibliothek. Naja.

https://github.com/PaulStoffregen/DmxSimple

Und wenn man da mal in den Quelltext schaut, erschaudert man!

/** Transmit a complete DMX byte
 * We have no serial port for DMX, so everything is timed using an exact
 * number of instruction cycles.

Die machen das alles in Software! So ein Mist!


>  MIDI.setHandleNoteOn(handleNoteOn); // Put only the name of the function
>  MIDI.setHandleNoteOff(handleNoteOff);
>  MIDI.begin(MIDI_CHANNEL_OMNI);

Auch hier muss man fragen, wie das MIDI wirklich gemacht ist? Per 
Software wäre auch hier ein ziemlicher CPU-Killer.

// DMX SETUP
>  DmxSimple.usePin(3);
>  DmxSimple.maxChannel(512);

Warum 512 Kanäle, wenn du nur 256 nutzt?


>}

>void loop () {
>MIDI.read();
>
>}

Wo werden hier die verschiedenen Muster angezeigt? Auch so, über die im 
Midi verstecken Funktionsaufrufe.

>Der erste Eintrag 124 ist die Kombination aus MIDI Kanal und MIDI Note -
>in diesem Fall Kanal 1 und Note 24 - Wenn diese Kombination im Array
>gefunden wird, werden die folgenden 256 Werte per DMX an die Lampe
>geschickt. Der Suchpointer macht natürlich 257er Sprünge.

Das halte ich für nicht sonderlich gescheit. Naja, es fehlen halt 
Grundlagen. Das sollte man trennen. Ein 2D Array für die Muster, ein 1D 
Array für die Midi-Noten. Das ist übersichtlicher. Man kann es auch mit 
einem Struct machen, das wäre professioneller, aber für dich im Moment 
wahrscheinlich zuviel Ablenkung vom eigentlichen Problem.

>würde mich freuen wenn hier Jemand eine Idee hätte wie das effizienter
>geht. Evtl. ganz ohne DMX Library sondern direkt.

Ja, aber dazu fehlt die viel zuviel Wissen.

: Bearbeitet durch User
von Marco H. (damarco)


Lesenswert?

Also das mit dem Ausrechnen und ausgeben lassen wir mal.. Denn selbst 
mit einen ARM ist das eine Spannende und Rechenintensive Aufgabe. Vor 
allem dann wenn alle 44ms der nächste Frame ausgegeben werden muss.

Was geht ist die Matrix und die Effekte mit einen externen Programm 
z.Bsp jinx zu erzeugen. Jinx kann die Ausgabe speichern und das Format 
ist recht simpel. Das File packt man auf eine SD. Lesen und Ausgeben -> 
fertig.

von Andy K. (andykoa)


Lesenswert?

Das mit dem MIDI ist absolut unproblematisch und funktioniert so wie es 
soll.
Ich habe ein weiteres Projekt in dem ich ein MIDI 2 DMX Shield entworfen 
und gebaut habe. Da werden Konfigurationsvariablen von einer SD Karte 
gelesen und RGB LED Strahler angesteuert - das funktioniert alles 
perfekt.

>  DmxSimple.usePin(3);
>  DmxSimple.maxChannel(512);

ich habe den Wert auf 256 reduziert und es läuft auch etwas schneller.

> int revo_array[4][256]

> Ein 2D Array für die Muster, ein 1D
> Array für die Midi-Noten. Das ist übersichtlicher. Man kann es auch mit
> einem Struct machen, das wäre professioneller, aber für dich im Moment
> wahrscheinlich zuviel Ablenkung vom eigentlichen Problem.

könnte ich hier einen Tipp bekommen?

Die Frage ist ja hier dann wirklich, ob es eine Verbesserung der 
Geschwindigkeit bewirkt.

Danke auf jeden Fall für die Unterstützung!

von Andy K. (andykoa)


Lesenswert?

@Marco

Jinx nutze ich für meine RGB Matrixen sehr erfolreich.
Ich suche eher eine kleine und kompakte Möglichkeit ohne PC und 
Windows(Jinx). Aber Danke :)

von Bastian W. (jackfrost)


Lesenswert?

Andy K. schrieb:
> könnte ich hier einen Tipp bekommen?
>
> Die Frage ist ja hier dann wirklich, ob es eine Verbesserung der
> Geschwindigkeit bewirkt.
>
> Danke auf jeden Fall für die Unterstützung!

Du hast ein uint16 Array dafür das die meisten deiner Werte nur 0 oder 1 
bzw 255 sind.

Du kannst die Noten in eine uint16 array packen und dann in dem kleinen 
Array suchen. Der Index ist der erste Index in deinem Musterarray.
Zudem spar dir die unötige Multiplikation
1
DmxSimple.write(d, (revo_array[i+d])*255);

indem du direkt im Array 0 bzw 255 verwendest.

Gruß JackFrost

von Falk B. (falk)


Angehängte Dateien:

Lesenswert?

@Andy Koa (andykoa)

>> Ein 2D Array für die Muster, ein 1D
>> Array für die Midi-Noten. Das ist übersichtlicher. Man kann es auch mit
>> einem Struct machen, das wäre professioneller, aber für dich im Moment
>> wahrscheinlich zuviel Ablenkung vom eigentlichen Problem.

>könnte ich hier einen Tipp bekommen?

>Die Frage ist ja hier dann wirklich, ob es eine Verbesserung der
>Geschwindigkeit bewirkt.

Kann sein, muss nicht.

https://www.arduino.cc/en/Reference/PROGMEM

Siehe Anhang.

von Andy K. (andykoa)


Lesenswert?

Funktioniert leider nicht.
Bin mir nicht sicher ob

> memcpy_P ((void*)dmxBuffer, dmx_data[i], 256);

von der DMX Simple Library verstanden wird.

Scheint aber genau an dieser Zeile zu liegen, dass nichts passiert bzw 
nichts ausgegeben wird.

Danke schon mal für die Mühe!

: Bearbeitet durch User
von Andy K. (andykoa)


Lesenswert?

Korrektur!
Es funktioniert.
ich habe die im Array die Werte auf 256 geändert anstelle der 1.
Es kommt mir so vor als wäre es einen Tick schneller - kann mich aber 
auch irren. Den erhofften Geschwindigkeitszuwachs hat es leider nicht 
bewirkt.
Danke trotzdem!

von Bastian W. (jackfrost)


Lesenswert?

Hast die Daten auf zwei Arrays gesplittet? 256 ist zu hoch, über die If 
Abfrage wird das auf 255 gesenkt kostet aber wieder einen unnötigen 
Takt. Ein uint16 ( int ) Array kostet auch unnötig Takte da der Zugriff 
über zweimal 8 Bit erfolgt.

Gruß JackFrost

von Falk B. (falk)


Lesenswert?

@ Andy Koa (andykoa)

>ich habe die im Array die Werte auf 256 geändert anstelle der 1.

Das geht gar nicht, denn das sind 8 Bit Daten, die können nur 0-255 
sein.

>Es kommt mir so vor als wäre es einen Tick schneller - kann mich aber
>auch irren. Den erhofften Geschwindigkeitszuwachs hat es leider nicht
>bewirkt.

Da sollte man vor allem erstmal testen, WO die niedrige Geschwindigkeit 
herkommt. ALso ohne Midi, nur mit DMX und dem Reinkopieren.

von Peter D. (peda)


Lesenswert?

Das Problem dürfte das DmxSimple.write(KANAL, WERT); sein.
DMX kennt keine Adressen, d.h. es werden jedesmal alle 256 Byte 
gesendet, auch wenn nur eins geändert wurde.
Du sendest in der Loop also nicht 256 Bytes sondern 256*256=65536 Byte. 
Das kann dauern.

Sende einfach nach dem Start alle 256 Byte aus dem Array, dauert ~10ms 
bei 250kBaud.

von Andy K. (andykoa)


Lesenswert?

@peda
Hört sich interessant an, aber ich habe keine Ahnung wie ich das 
umsetzen kann. Könnte ich evtl ein Beispiel haben wie das machbar wäre? 
Danke!

von Bastian W. (jackfrost)


Lesenswert?

Peter D. schrieb:
> Das Problem dürfte das DmxSimple.write(KANAL, WERT); sein.
> DMX kennt keine Adressen, d.h. es werden jedesmal alle 256 Byte
> gesendet, auch wenn nur eins geändert wurde.
> Du sendest in der Loop also nicht 256 Bytes sondern 256*256=65536 Byte.
> Das kann dauern.
>
> Sende einfach nach dem Start alle 256 Byte aus dem Array, dauert ~10ms
> bei 250kBaud.

Laut dem Github Code wird mit dem DMX.write die Werte des Kanals nur in 
den DMX Puffer geschrieben. Der Puffer wird per Timer ISR dauernd 
gesendet. Die Frage ist wie viel CPU Zeit gibt es noch für die Main. Mit 
den ganzen 16 Bit Zugriffen kostet das halt zusätzlich noch unnötige 
Zeit.

Gruß JackFrost

von Falk B. (falk)


Lesenswert?

@Peter Dannegger (peda)

>Das Problem dürfte das DmxSimple.write(KANAL, WERT); sein.

Jain. Es ist zwar eine nicht ganz so kurze Funktion, aber das hält sich 
in Grenzen.

>DMX kennt keine Adressen, d.h. es werden jedesmal alle 256 Byte
>gesendet, auch wenn nur eins geändert wurde.

Nein.

>Du sendest in der Loop also nicht 256 Bytes sondern 256*256=65536 Byte.
>Das kann dauern.

Unsinn! Er kopiert 256 Bytes aus seinem Array in das interne DMX-Array. 
Und in meiner Version sogar per memcpy_P. Das dauert nur ein paar 
Dutzend us.

>Sende einfach nach dem Start alle 256 Byte aus dem Array, dauert ~10ms
>bei 250kBaud.

Das macht das Programm schon längst.

Ich vermute eher, daß die DMX-Lampe recht lahmarschig ist und viele 
DMX-Frames braucht, um die neuen Daten intern zu verarbeiten. Das kann 
man leicht prüfen.

von Falk B. (falk)


Lesenswert?

@Andy Koa (andykoa)

>@peda
>Hört sich interessant an,

Ist aber Unsinn.

>umsetzen kann. Könnte ich evtl ein Beispiel haben wie das machbar wäre?

Ergänze mal dein neues Programm von mir.

In Setup() stellst du ein IO-Pin auf Ausgang, dort kommt eine Test-LED 
ran, aber bitte mit Vorwiderstand!

#define TEST_LED 7          // nutze IO 7 als Ausgang für die Test-LED
pinMode(TEST_LED, OUTPUT);      

Loop() wird dann so gemacht.
1
void loop () {
2
  static int i;
3
4
  digitalWrite(TEST_LED, HIGH);   
5
  memcpy_P ((void*)dmxBuffer, dmx_data[i], 256);
6
  i++;
7
  if (i>3) i=0;
8
  delay(10);
9
  digitalWrite(TEST_LED, LOW);
10
  delay(1000);
11
}

Damit wird zum Beginn der Kopieraktion die LED angeschaltet und danach 
wieder ausgeschaltet. Damit sieht man, wann der Kopiervorgang beginnt 
und wann der DMX-Strahler reagiert. Die delay(10) sind drin, damit der 
Lichtblitz nicht zu kurz wird. Dieser Test schaltet im 1s Rhythmus die 
Muster um. Damit ist auch MIDI als mögliche Quelle für Langsamkeit 
ausgeschlossen.

von Peter D. (peda)


Lesenswert?

Ich hab mal versucht, das CPP zu verstehen. Da steht was von T2 
Interrupt alle 64*510 Zyklen, das sind nur 2ms [16MHz].
Benötigt werden aber für 256 Byte ~10ms, d.h. die Mainloop wird massiv 
ausgebremst (alle 10ms wird nur ein Befehl ausgeführt).
Die Interruptperiode sollte auf mindestens 20ms verlängert werden.

von Marco H. (damarco)


Lesenswert?

Der Code ist totaler Quark. Die Berechnung des Frames muss in der Mark 
des DMX erfolgen diese könnte man bis 1s strecken. Dann geht aber die 
Framerate stark zurück. Da kein DMA im Spiel ist wird die Main nicht 
ausgeführt wenn die Übertragung läuft.

von Peter D. (peda)


Lesenswert?

Wenn man eine der 4 UARTs benutzt, könnte man im Hintergrund mit 
maximaler Rate senden, ohne das Main zu bremsen (2 Byte je Interrupt).

250kBaud mit SW-UART ist ziemlich suboptimal.

von Marco H. (damarco)


Lesenswert?

Es kommt darauf an wie man die ISR gestaltet. Man kann ja nach jedem 
byte +start+2xstop die ISR auslösen. Wenn man das intelligent macht 
bleibt auch genug Rechenzeit übrig.  Ich habe das sogar mit RDM und 
einen AVR realisiert.  Illusion ist es aber Frames online zu berechnen. 
Bis auf einfach Muster geht da nicht viel.

von Falk B. (falk)


Lesenswert?

@Peter Dannegger (peda)

>Ich hab mal versucht, das CPP zu verstehen. Da steht was von T2
>Interrupt alle 64*510 Zyklen, das sind nur 2ms [16MHz].

Ja.

>Benötigt werden aber für 256 Byte ~10ms,

Nein, denn er sendet pro ISR nur einen Teil der DMX-Daten. Ist ein wenig 
verquer.

>Die Interruptperiode sollte auf mindestens 20ms verlängert werden.

Nicht nötig.

von Marco H. (damarco)


Lesenswert?

(88+8+44+512*44) = 22668 us Zwischen den Channels bleiben 44µS ob die 
reichen?

Also in Assembler mit gewissen Umständen bekommt man das irgend wie hin 
aber bestimmt keine Plasma Effekte ;) .

In der Theorie würde ich immer um ein Channel Versatz rechnen, sofort 
wenn dieser übertragen wurde wird der neue Wert ausgerechnet und in den 
Buffer geschrieben. Einen Zeiten Buffer braucht man nicht. Der Zugriff 
ist beim AVR und ohne DMA Atomar.  Wenn man länger braucht verschiebt 
sich das in der MARK Time die bis zu 1sec lang sein darf. Auf 44,1HZ 
wird man mit einen AVR nicht kommen aber wenn man 30HZ erreicht ist doch 
das schon was tolles.


Das mit der SD Karte lesen klappt auch nur mit einen ARM da der AVR mit 
der FAT schon reichlich zu hätte.

: Bearbeitet durch User
von Falk B. (falk)


Lesenswert?

@ Marco H. (damarco)

>(88+8+44+512*44) = 22668 us Zwischen den Channels bleiben 44µS ob die
>reichen?

Das weißt du doch gar nicht! Schau dir den Quelltext an!
1
#define BITS_PER_TIMER_TICK (F_CPU / 31372)
2
3
...
4
5
6
ISR(ISR_NAME,ISR_NOBLOCK) {
7
8
  // Prevent this interrupt running recursively
9
  TIMER2_INTERRUPT_DISABLE();
10
11
  uint16_t bitsLeft = BITS_PER_TIMER_TICK; // DMX Bit periods per timer tick
12
  bitsLeft >>=2; // 25% CPU usage

Er nutzt hier BEWUßT nur 25% der CPU-Zeit für die DMX-Generierung!

1
  while (1) {
2
    if (dmxState == 0) {
3
      // Next thing to send is reset pulse and start code
4
      // which takes 35 bit periods
5
      uint8_t i;
6
      if (bitsLeft < 35) break;
7
      bitsLeft-=35;
8
      *dmxPort &= ~dmxBit;
9
      for (i=0; i<11; i++) delayMicroseconds(8);
10
      *dmxPort |= dmxBit;
11
      delayMicroseconds(12);
12
      dmxSendByte(0);

1
    } else {
2
      // Now send a channel which takes 11 bit periods
3
      if (bitsLeft < 11) break;
4
      bitsLeft-=11;
5
      dmxSendByte(dmxBuffer[dmxState-1]);
6
    }

Er sendet hier die DMX-Daten per SOFT-UART. Aber eben nur soviele, wie 
es 25% der Bitzeiten / ISR-Aufruf braucht. Das bedeutdet allerdings im 
Umkehrschluß, daß er nur 1/4 der maximalen Framerate von DMX schafft. 
Bei 256 Kanälen sind das ~ 80 Hz, diese Software schafft nur 20Hz.

>In der Theorie würde ich immer um ein Channel Versatz rechnen, sofort
>wenn dieser übertragen wurde wird der neue Wert ausgerechnet und in den
>Buffer geschrieben.

Da muss gar nichts gerechnet werden. Der Op muss nur nacheinander die 
vorberechneten muster ausgeben, fertig.

>sich das in der MARK Time die bis zu 1sec lang sein darf. Auf 44,1HZ
>wird man mit einen AVR nicht kommen

Woher weißt du das? Hast du das schon mal gemacht?

>Das mit der SD Karte lesen klappt auch nur mit einen ARM da der AVR mit
>der FAT schon reichlich zu hätte.

Unsinn! Ich hab vor Jahren einen DMX-Rekorder mit einem ATmega64 gebaut, 
der hat bei voller Bandbreite 512 Kanäle/44 Hz von/nach SD-Karte gelesen 
und geschrieben. Mittlere CPU-Last ca. 30% bei 16 MHz CPU-Takt.

: Bearbeitet durch User
von Marco H. (damarco)


Lesenswert?

Ja habe ich allerdings nicht mit einen AVR ;) Auch die FAT habe ich 
nicht genutzt sondern die SD selbst organisiert. Da schnell und die 
Daten brauchte auch kein Schwein zum lesen.

Wenn es doch so einfach ist warum nicht den Weg gehen den ich oben 
beschrieben habe? Einfach die Animationen als File einlesen und 
ausgeben.

: Bearbeitet durch User
von Mikki M. (mmerten)


Lesenswert?

44,1 Hz (22 ms) Refresh selbst bei 2 aktiven UART DMX Output, da 
langweilt sich ein 16 MHz ATmega AVR.

von Marco H. (damarco)


Lesenswert?

Es ging ja darum Animationen live zu berechnen und auszugeben. Da wird 
es schon spannend.

von Bastian W. (jackfrost)


Lesenswert?

Laut dem TO geht es darum fertige Muster aus einem Array an den Strahler 
zu senden. Die Musterauswahl erfolgt über MIDI Noten.

Gruß JackFrost

von Andy K. (andykoa)


Lesenswert?

Vielen Dank für die Vorschläge.

Ich bin schwer begeistert wie viele Leute hier das Thema diskutieren und 
auch tiefe Kenntnisse auch beim DMX Protokol haben - leider ist es für 
mich teilweise schwer verständlich - aber dann lerne ich ja auc noch was 
dazu :)

@falk

Ich glaube nicht daß MIDI das Problem ist, aber ich teste das Programm 
heute Abend man wenn ich ohne MIDI direkt die Muster aufrufe.

Es ist nicht so, daß man das Programm mit der momentanen Geschwindigkeit 
nicht nutzen könnte. Beim Umschalten der Muster wird es fast nicht 
deutlich, aber beim Auschalten aller LEDs - 256* den Wert 0 senden - 
nach einem Muster macht es erst deutlich.
Vielleicht wird mein Problem etwas deutlicher wenn ich ein kleines Video 
mache.

von Falk B. (falk)


Lesenswert?

@Andy Koa (andykoa)

>Es ist nicht so, daß man das Programm mit der momentanen Geschwindigkeit
>nicht nutzen könnte. Beim Umschalten der Muster wird es fast nicht
>deutlich, aber beim Auschalten aller LEDs - 256* den Wert 0 senden -
>nach einem Muster macht es erst deutlich.

Mein Gott, wird doch mal KONKRET! Wie lange dauert es, bis ein Muster 
von dem Leermuster gelöscht wird? 1s? 100ms?

>Vielleicht wird mein Problem etwas deutlicher wenn ich ein kleines Video
>mache.

Möglicherweise.

von Peter D. (peda)


Lesenswert?

Wie gesagt, mit einer der HW-UARTs könnte man im Hintergrund den Puffer 
mit der maximalen Refreshrate ausgeben lassen ohne merkbare CPU-Last, 
d.h. 11,44ms für 256 Byte. Für das Break stellt man die Baudrate auf 1/3 
um und sendet 0x00 (9*3 = 27 Bitzeiten).

von Marco H. (damarco)


Lesenswert?

Wenn es unglücklich läuft muss man 256x22ms rechnen So lange braucht es 
bis wenn im unglücklichsten Moment nur ein Wert pro Frame geändert wird.

von Martin K. (maart)


Lesenswert?

Marco H. schrieb:
> Wenn es unglücklich läuft muss man 256x22ms rechnen So lange braucht es
> bis wenn im unglücklichsten Moment nur ein Wert pro Frame geändert wird.

Danach hört es sich fast an.

von Falk B. (falk)


Lesenswert?

@Marco H. (damarco)

>Wenn es unglücklich läuft muss man 256x22ms rechnen So lange braucht es
>bis wenn im unglücklichsten Moment nur ein Wert pro Frame geändert wird.

Das wird es aber nicht! Zumindest nicht in DIESEM Sender! Und wenn es 
der Empfänger so macht, ist er Schrott! Wobei, im DMX-Bereich scheint es 
davon reichlich zu geben.

Beitrag "Re: DMX Steuerung 24 Kanal"

Dort wurde eine klapprige China-Steuerung mit DREI CPUs durch EINEN 
ATmega644@20MHz ersetzt.

von Marco H. (damarco)


Lesenswert?

Der Emfänger hat er weniger damit zu tun, sondern der Sender = 
Controller.

Der muss beim fading die Framezeit mit berücksichtigen und natürlich 
auch den Zeitpunkt wann Daten in den Buffer geschrieben werden.

Die Funktion die er da benutzt schreibt plump in den Buffer und wenn er 
pech hat ist der Channel gerade raus und er muss auf den nächsten Frame 
warten.

Channel++ erzeugt kein Fade jedenfalls nicht wenn noch was anderes 
nebenbei läuft ;)  Es entsteht er zufällig.

Der Weg etwas plump zu kopieren geht in die Hose.

: Bearbeitet durch User
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.