Start Elkretssimulator


DMX styrning



Vi gör en DMX -styrning med arduino! Men först lite DMX -teori. OBS nedan använder jag ordet lampa, spotlight, armatur och fixtur men jag syftar på samma grej här, nämligen en DMX -styrd lampa/spotlight.

Styrbara DMX-spotlight

Tidigare var sådana här DMX -styrbara spotlight dyra och förekom bara på teater eller scener. Idag är de billiga - några hundra kronor - och dessutom energisnåla tack vare led och som grädde på moset ofta huserad i en väldigt tjusig armatur. Det går därför att göra vanliga miljöer trevliga och ljussatta, t.ex. cafeer, restauranger, butiker eller vilken miljö som helst egentligen inklusive där hemma, diskot eller den lilla scenen i skolan.



Vad är DMX

DMX är en standard för överföring av data för att kontrollera ljus. Om du tänker dig en scen med väldigt många strålkastare och ett kontrollbord där alla lampor styrs, så sker överföringen av data med hjälp av ett DMX -protokoll. På så vis behöver man bara köra en datakabel genom alla lampor och in i ett kontrollbord. Varje lampa ges ett visst nummer (med inställningar bak på lampan) och sedan kommer man åt den lampan via kontrollbordet.



På baksidan av en typisk DMX -styrd lampa finns dels en ingång (hane) och en utgång (hona) för en XLR -kabel (mer om det längre ner) så att styrsignalen till flera lampor kan kopplas i en kedja, men också någon typ av möjlighet att justera inställningar för lampan, t.ex. vilket nummer lampan har så att vi kan adressera den med vår kontroller.

Vi kan sedan koppla ihop väldigt många lampor på detta vis.



DMX protokoll

En väldigt viktig grej att förstå när det kommer till DMX är själva adresseringen av de olika lamporna (fixturerna). Bak på varje lampa finns en möjlighet att ställa in en adress. Vad denna adress skall vara beror på hur DMX -kontrollern mappar sina reglage på adresser. Det kan skilja från kontroller till kontroller.

DMX-kontroller

Kontrollern skickar ut en ström med värden från 0-255. Första värdet ligger på adress 1, andra värdet på adress 2, tredje värdet på adress 3 osv. En ljusmixer med 8 stycken reglage kan t.ex. fungera så att om man, på ljusmixern, klickar på fixtur 1 så kommer värdet på dessa 8 reglage hamna på adresserna 1-8. Om man klickar på fixture 2 så hamnar värdet på dessa reglage istället på adresserna 9-17.

DMX-spotlight

Om man vidare har 2 stycken DMX-styrda spotlight, så ställer man förslagsvis in den första på adresss 1. Det betyder att spotlighten läser in adressen 1 och så många adresser den är byggd för att läsa. Den första spotlighten ligger alltid på adress 1. Den andra hamnar sedan på adress 9. Det betyder att denna spotlight hämtar data från adress 9 och så många adresser fram som den är kontruerad att läsa.



Hur många adresser en spotlight läser beror kort på hur avancerad den är. En vanlig RGB -spotligt har förstås 3 adresser för rött, grönt och blått. Men sen finns ofta adresser för lite andra saker också. En mer avancerad armatur med motorer eller servon kan ha väldigt många adresser som den hämtar data ifrån.

Nu är inte detta någon manual för hur man kopplar ihop DMX -styrda ljusbord med DMX -styrda lampor, men för att förklara hur allt hänger ihop kan det vara bra att ha detta klart för sig.

Ok, fine. Så hur skapar vi detta utskick med datavärden till våra DMX -lampor?

DMX-protokollet

Själva DMX -protokollet ser då ut som nedan. Vad vi måste skapa är alltså en dataström på följande format. Vad det handlar om är en ström av dataframes (max 512 stycken) och varje dataframe består av en byte (0-255) som inleds med en startbit som är 0 och avslutas med 2 stoppbitar som är 1. Hela listan med dataframes inleds av en break som består av minst 88 uS lång "nolla".



Om man tittar lite på arduino'n UART (seriekommunikation, TX, RX) så går den faktiskt att köra på 250 KBaud hastighet. Vi kan vidare konfigurera denna så att den har en startbit = 0 och två stopbitar = 11. Så här ser det ut i Atmega328P dokumentering (sid. 181).



Perfekt för oss. Paritetsbiten struntar vi i. Vi behöver alltså bara snickra till startblocket (DMX -protokollet kallar det "break"), som skall vara noll en längre period, och sedan kan vi dunka ut vår data till DMX -lamporna med arduinons serie-interface. Vi konfigurerar det till 250 KBaud, 8 databitar och 2 stopbitar.

Kod för att skapa DMX på serieporten (TX)

Jag skriver nedan ut 255 följt av 26 följt av 255. En liten "detalj" är att när jag ställer om hastigheten på serieporten så tappar den inställning med stopbitar, så jag sätter detta register på nytt efter att hastigheten ändrats. Ytterligare en grej här, det är att när vi skickar data till UARTen så fortsätter vårt program att rulla samtidigt som UARTen skickar ut data. Så vi måste vänta lite i vår kod och ge seriekretsen chans att jobba färdigt.


#define DMX_MAX 8 
uint8_t Channels[DMX_MAX];
 
void SetChannel(int ch, uint8_t val)
{
  Channels[ch-1] = val;
}

void Send()
{
  // Vi skapar BREAK med en lång nolla med lägre hastighet
  Serial.begin(30000);
  Serial.write((uint8_t)0);

  delayMicroseconds(30);

  // Tillbaka till rätt hastighet för data
  Serial.begin(250000);
  /* Måste initiera om UCSR0C ifall vi ändrar baudrate */
  /* Annars tappar vi våra 2 stop-bitar */
  UCSR0C = (1 << USBS0)|(3 << UCSZ00);
  Serial.write((uint8_t)0); // Första = 0
  Serial.write(Channels, sizeof(Channels)); // data
} 
 
void setup() 
{
  Serial.begin(30000);
  /* Set frame format: 8data, 2stop bit */
  UCSR0C = (1 << USBS0)|(3 << UCSZ00);
  
  for (int n = 0; n < DMX_MAX; n++)
    Channels[n] = 0;

  SetChannel(1, 255);
  SetChannel(2, 26);
  SetChannel(3, 255);
} 
 
void loop() 
{
  Send();
  delay(1);
}

Logikanalysatorn inkopplat på TX -pinnen ger följande bild. Jag har kladdat in själv vad som är break och vilka bit värden det är. Logikanalysatorn kan hjälpa till med detta, mer om det längre ner.



Det ser väldigt DMX -aktigt ut, tycker jag själv. Break är på plats längre än föreskrivna 88 uS och dataframes ser bra ut, där den första adressen lämnas som noll. Gul är startbit och orange är 2 stopbitar, däremellan data.

Elektrisk överföring

Rent elektriskt skall denna dataström skickas på en balanserad kabel (RS-485). Detta krånglar till saker lite. Vi är vana vid att vi oftast bara har att göra med GND och en SIGNAL. Detta fungerar vid korta avstånd. Men DMX -fixturer är gjorda för att kunna fungera med långa kabelavstånd och varje fixtur har XLR -kontakter och överföringen sker balanserat med RS-485.

XLR -kabel mellan lamporna

Obalanserad överföring

Överföringskablar mellan 2 elektriska saker i hemmet, t.ex. i en HIFI -anläggning mellan TV och en förstärkare, sker med obalanserade kablar. Det är en kabel med signal och GND. Detta fungerar utmärkt för små avstånd.



Försöker man dra en obalanserad signalkabel en längre sträcka så kommer det troligtvis uppstå brum i signalen. Speciellt i ljud -kablar, mikrofonkablar, är brum otroligt irriterande och värdelöst.

Balanserad överföring

För att komma runt detta problem så har man uppfunnit den balanserade överföringen, som trollar bort allt brum och överhuvudtaget transporterar en signal en lång sträcka utan att den förvanskas allt för mycket.



När vi pratar DMX, då pratar vi förstås inte ljud utan data. Men problemet och dess lösning är samma. Utan en balanserad överföring skulle data förvanskas och bli oläsligt för mottagaren om man har lite otur.

Med detta förtydligat så är det nu glasklart varför vi har att göra med en balanserad överföring här. Vi kan då ha väldigt långa DMX -kablar till väldigt många lampor på en scen och det kommer fungera utmärkt tack vare den balanserade överföringen (RS-485).

MAX485 fixar RS-485

Det finns en liten käck krets som åstadkommer en balanserad överföring åt oss, nämligen MAX485. En detalj som underlättar lite är att kommunikationen enbart sker mot DMX -armaturerna, alltså enbart i en riktning.

En testlösning

RS-485, protokollet och kretsen alltså, kan hantera dataöverföring i båda riktningarna men det är halv duplex vi pratar om. Det betyder att överföringen enbart kan ske i en riktning åt gången. Full duplex hade inneburit överföring i båda riktningar samtidigt, men så är alltså inte fallet med RS-485, utan det är halv duplex. Nu kommer vi aldrig skicka data i 2 riktningar (eftersom detta inte görs i DMX) så vi bygger egentligen en simplex -kommunikation här. Alltså enbart överföring i en riktning, ungefär som TV-sändningar.



Den här kretsen kommer lösa problemet med den balanserade överföringen. Det är ingen mega-robust lösning för en "industriell" lösning som måste kunna hantera felinkopplingar och diverse störningar, men lösningen fungerar bra i en mindre skala och för att testa konceptet. Mer om hur man kan skapa en stabilare krets i någon annan tutorial.

DMX -kontakter: XLR5 och XLR3

Signalerna skall sedan in i en XLR -kontakt. Standarden föreskriver alltså en 5-polig XLR -kontakt. Av dessa 5 stift används då enbart 3 stycken. I praktiken, om man köper en DMX -lampa, så sitter det faktiskt en 3 -polig XLR -kontakt där bak. 3 -poliga XLR -kontakter används t.ex. som mikronkablar eller audiokablar mellan ljudenheter.



RS-485 sändare/mottagare

RS-485 -kretsen ifråga, ovan beskriven, finns med kringkomponenter monterad på ett bekvämt litet kretskort för några tior vilket jag råkat skaffat mig. Kretskortet verkar konstruerat enligt nedan.

R1 = R2 = R3 = R4 = 10KΩ
R5 = R6 = 20KΩ
R7 = 120Ω
R8 = 1KΩ
C1 = 10 uF
C2 = 0.1 uF


Detta kopplar vi in på arduinos TX -port på följande vis.



Den DMX -lampan jag har framför mig nu är en "Stairville LED PAR 64". På sidan 23 i manualen ser det ut såhär.



Jag ställer in DIP-switchen så att bit 1 = On och resten Off. Det betyder då att den ligger på kanal 1. Switchen ställer jag på "music" som på bilden. Tror inte det spelar någon roll, men är lätt gjort. Det betyder vidare att om CH-1 sätts till 0 ("RGB Control") så bör CH-2, CH-3, CH-4 vara röd, grön, blå. Lets do it.

Ovanstående koppling och inställning verkar fungera utmärkt. Nedan kod ger starkt grönt ljus i DMX -spotlighten vilket är exakt vad som borde hända.


#define DMX_MAX 5
uint8_t Channels[DMX_MAX];
 
void SetChannel(int ch, uint8_t val)
{
  Channels[ch-1] = val;
}

void Send()
{
  // Vi skapar BREAK med en lång nolla med lägre hastighet
  Serial.begin(30000);
  Serial.write((uint8_t)0);

  delayMicroseconds(30);

  // Tillbaka till rätt hastighet för data
  Serial.begin(250000);
  /* Måste initiera om UCSR0C ifall vi ändrar baudrate */
  /* Annars tappar vi våra 2 stop-bitar */
  UCSR0C = (1 << USBS0)|(3 << UCSZ00);
  Serial.write((uint8_t)0); // Första = 0
  Serial.write(Channels, sizeof(Channels)); // data
} 
 
void setup() 
{
  Serial.begin(30000);
  /* Set frame format: 8data, 2stop bit */
  UCSR0C = (1 << USBS0)|(3 << UCSZ00);
  
  for (int n = 0; n < DMX_MAX; n++)
    Channels[n] = 0;

  SetChannel(1, 0); // Mode
  SetChannel(2, 0); // Röd
  SetChannel(3, 255); // Grön
  SetChannel(4, 0); // Blå
  SetChannel(5, 0); // Speed 
} 
 
void loop() 
{
  Send();
  delay(1);
}

Nog blir det grönt!



Jag använder själv logikanalysatorn Saleae. Har haft den sedan många år. Den har en smart finess, nämligen att man kan lägga till en "analyzer" på en kanal. Om man lägger till DMX-512 så får man all data tolkad på DMX -språk. Detta bekräftar också att formatet stämmer. Nu visste jag det redan eftersom jag hade lite bråttom koppla in lampan och såg att det fungerade. Men om man vill felsöka på en digital signal eller tolka data som skickas så är dessa analyzers väldigt praktiska. Se nedan:



Om vi zoomar lite ser vi bättre:



Om vi zoomar lite till syns även bit -nivån:



Om man vill testa något roligare än att sätta en enstaka färg, kan man t.ex. knacka några rader kod som ger en vandring över regnbågens alla färger. Detta är lätt gjort om man istället för RGB använder sig av HSV som beskrivet här. Koden blir då såhär.


#define DMX_MAX 5

// 
// hue 0-1
// sat 0-1
// val 0-1
//
float hue = 0;
float sat = 1;
float val = 1;

uint8_t Channels[DMX_MAX];
 
void SetChannel(int ch, uint8_t val)
{
  Channels[ch-1] = val;
}

int * HSVtoRGB(float h, float s, float v) 
{
    static int vr[3];
    int i;
    float r,g,b,f,p,q,t;
    i=(int)(h*6);
    f=h*6-(float)i;
    p=v*(1-s);
    q=v*(1-f*s);
    t=v*(1-(1-f)*s);
    switch (i%6) 
    {
        case 0: r=v, g=t, b=p; break;
        case 1: r=q, g=v, b=p; break;
        case 2: r=p, g=v, b=t; break;
        case 3: r=p, g=q, b=v; break;
        case 4: r=t, g=p, b=v; break;
        case 5: r=v, g=p, b=q; break;
    }
    vr[0]=(int)(r*255);
    vr[1]=(int)(g*255);
    vr[2]=(int)(b*255);    
    return vr;
}

void Send()
{
  // Vi skapar BREAK med en lång nolla med lägre hastighet
  Serial.begin(30000);
  Serial.write((uint8_t)0);

  delayMicroseconds(30);

  // Tillbaka till rätt hastighet för data
  Serial.begin(250000);
  /* Måste initiera om UCSR0C ifall vi ändrar baudrate */
  /* Annars tappar vi våra 2 stop-bitar */
  UCSR0C = (1 << USBS0)|(3 << UCSZ00);
  Serial.write((uint8_t)0); // Första = 0
  Serial.write(Channels, sizeof(Channels)); // data
} 
 
void setup() 
{
  Serial.begin(30000);
  /* Set frame format: 8data, 2stop bit */
  UCSR0C = (1 << USBS0)|(3 << UCSZ00);
  
  for (int n = 0; n < DMX_MAX; n++)
    Channels[n] = 0;
} 
   
void loop() 
{
  hue += 0.0001;
  if(hue>1)
    hue = 0;
    
  int *v;
  v = HSVtoRGB(hue, sat, val);
  int red = v[0];
  int green = v[1];
  int blue = v[2];
  
  SetChannel(2, red); // Röd
  SetChannel(3, green); // Grön
  SetChannel(4, blue); // Blå

  Send();
  delay(1);
}


Lite reflektioner

Det var rätt så enkelt styra en DMX -lampa med ett arduino -kompatibelt kort, en RS-485 -krets samt en XLR3 -kontakt och några rader kod.

Fortsättning på detta projekt i någon annan tutorial blir att styra flera lampor med olika typer av scener eller få lamporna att styras till musik. Det blir en annan tutorial längre fram.

Avslutningsvis:

DMX -kablar

Om man nu har den 3-poliga kontakten i DMX -lamporna man köpte (vilket är högst sannolikt!), är det egalt om man använder en mikrofonkabel eller en äkta DMX -kabel, som DMX -kabel? Mikrofonkabeln ser likadan ut med samma kontakter och är dessutom troligtvis billigare. Men det är troligtvis ingen bra ide' använda mikrofonkabeln. DMX -kabeln är en 120 Ohms -kabel virad för att fungera bra med höga frekvenser. DMX -data är trots allt 250.000 Baud = 250 KBaud. Min egen erfarenhet är att mikrofonkablar fungerar om man har korta kablar, annars inte. En artikel på detta tema.

Terminering

Om man kopplar ihop ett gäng DMX -lampor skall sista lampan i kjedjan har en terminering på 110-120 Ω på signalsladdarna.

Lycka till!