Go Down

Topic: Reading serial bytes and packet from DMX software (Read 3233 times) previous topic - next topic

djred2000

I am wondering if it is possible for an Arduino to read and interpret the data that a DMX control program produces.  My thinking is to have the Arduino read the first 8 bytes that correspond to the first 8 channels and based on those values (0-255) set a digital pin to high or low.  DMX signals are sent in packets and each packet contains a start byte and then 512 bytes followed by a break (if I understand it correctly).  Each of the 512 bytes contains a value between 0-255.  So, in the software on the computer if I set DMX channel 1 to a value of 255 I want the Arduino to interpret that and set digital pin 2 (for example) to high.  If I then change the value of channel 1 to 0 then digital pin 2 will switch to low.

I'm not trying to have the Arduino generate DMX signals because the computer software does that already, I'm simply trying to have the Arduino interpret the signals sent to it over the serial connection.

Thanks for your help!

djred2000

Here is some code I started working on.  I am very new at this and have no idea if this even makes any sense.  I also don't have my Arduino with me currently so I can't test any of this but I want to see if I understand the concept.
Code: [Select]

int relay2 = 2;  //digital pin 2
int relay3 = 3;  //digital pin 3
int relay4 = 4;  //digital pin 4
int relay5 = 5;  //digital pin 5
int relay6 = 6;  //digital pin 6
int relay7 = 7;  //digital pin 7
int relay8 = 8;  //digital pin 8
int relay9 = 9;  //digital pin 9
byte channel0;    //variable for byte 1
byte channel1;    //variable for byte 2
byte channel2;    //variable for byte 3
void setup()
{
 Serial.begin(9600);  
 pinMode(relay2, OUTPUT);  
 pinMode(relay3, OUTPUT);
 pinMode(relay4, OUTPUT);
 pinMode(relay5, OUTPUT);
 pinMode(relay6, OUTPUT);
 pinMode(relay7, OUTPUT);
 pinMode(relay8, OUTPUT);
 pinMode(relay9, OUTPUT);
}


void loop()
{

 while(Serial.available() <= 513 )  //read 513 bytes
 {
   
    channel0 = Serial.read();
    channel1 = Serial.read();
    channel2 = Serial.read();
    //etc. for all 513 bytes (need to create a loop)
 }
 if(channel1 == '255')  
 {
   digitalWrite(relay2, HIGH);  //if channel1 value = 255 set pin 2 to high
 }
 else if(channel1 == '0')  //if channel1 value = 0 set pin 2 to low
 {
   digitalWrite(relay2, LOW);
 }

}


I know I need to create some kind of loop for all the byte variables.  I also know that this will only read the first 513 bytes (the first byte being the start byte and the next 512 bytes correspond to each channel).  DMX signals are a continuous stream and they also contain a break between packets which I do not know how to handle.  

Am I on the right track?  Any help would be greatly appreciated.


djred2000

I apologize for sounding stupid but I have spent a lot of time reading the DMX information found on the Arduino playground site and it does not seem helpful to me.  I am unable to find example code for receiving a DMX signal via the USB connection.  All the code is for either generating a DMX signal or receiving it from a shield.

PaulS

You should have the while loop reading data as long as there is any data available to read.

Code: [Select]
while(Serial.available() > 0)
{
  // Read and store the byte
}


You appear to think that you need to store all 512 bytes, but, if you are only interested in the first 8, then you could just read and ignore the other 504 bytes.

Code: [Select]
byte interestingBytes[8];
int numBytesRead = 0;
int byteRead;
while(Serial.available() > 0)
{
  byteRead = Serial.read();
  if(byteRead >= 0)
 {
    if(numBytesRead < 8)
      interestingBytes[numBytesRead] = byteRead;
    numBytesRead++;
 }
}

// Now do something with the interesting bytes,
// if there were more than 8 bytes read

djred2000

OK I think I'm starting to understand.  Will the 8 bytes that are read be reread each time the 512 byte packet restarts?

PaulS

Not the same 8 values, but the same first 8 bytes of each packet, presuming that you make sure to discard 504 bytes of un-interesting data.

admin

hello

arduino can easily read DMX signals.

Make sure you have a transceiver (MAX485 or similar) to receive the signal then connect it to the RX pin on the Arduino.

setup the serial port for a speed of 250000 bits per second
( Serial.begin(250000) )
then wait for the "break" signal that is a pulse around 800uSec
then read a byte from the serial port... if the byte is 0 then the signal is a valid dmx stream...

start reading and throw away bytes until you reach the right address

sorry for the short message but it should be enough :)

m



djred2000

OK I see now.  Does the break between packets matter? What about the start byte for each packet?  I will just have to offset everything by one then.  

I'm not trying to read DMX data from another DMX device.  I'm trying to read DMX data that a program called DMXControl produces and then outputs over USB to the Arduino board.  I'm basically trying to create an open USBDMX device but with out the shield.  

I wired 8 relays into my Arduino via the digital pins and my hope is to use it control Christmas lights.  DMXControl allows you to load a song and create cues based on timing within the song.  So my goal is to use DMX channel 1 to control relay 1 on or off with the DMX channel value and so on for all 8 relays.

VW1302S

http://blog.wingedvictorydesign.com/2009/03/20/receive-dmx-512-with-an-arduino/

This should get you going in the right direction

djred2000

OK thanks!  I will take a look at that and see what I can figure out.

djred2000

OK now that finals are over I can spend some more time on this.  I'm still trying to read the serial stream data.  Here is what I have come up with and so far it's not working.
Code: [Select]

int relay2 = 2;  //digital pin 2
int relay3 = 3;  //digital pin 3
int relay4 = 4;  //digital pin 4
int relay5 = 5;  //digital pin 5
int relay6 = 6;  //digital pin 6
int relay7 = 7;  //digital pin 7
int relay8 = 8;  //digital pin 8
int relay9 = 9;  //digital pin 9
int numBytesRead = 0;      //byte number variable
volatile byte zerocounter = 0;   //zero counter for break
void setup()
{
 Serial.begin(115200);  
 pinMode(relay2, OUTPUT);  
 pinMode(relay3, OUTPUT);
 pinMode(relay4, OUTPUT);
 pinMode(relay5, OUTPUT);
 pinMode(relay6, OUTPUT);
 pinMode(relay7, OUTPUT);
 pinMode(relay8, OUTPUT);
 pinMode(relay9, OUTPUT);
}


void loop()
{
byte interestingBytes[9];
int byteRead;
while(Serial.available() > 0)
{
  byteRead = Serial.read();
  numBytesRead++;
  if(byteRead >= 0)
 {
    if(numBytesRead <= 9)
    {
      interestingBytes[numBytesRead] = byteRead;
    }
 }
}
    /* detecting break between packets */
    if (bitRead(byteRead,1))  // if a one is detected, we're not in a break, reset zerocounter.
    {  
       zerocounter = 0;
   }
   if(bitRead(byteRead,0))  //if the bit is a 0 then we are in a break
   {
       zerocounter++;             // increment zerocounter
   }
   if (zerocounter == 22)        // if 22 0's are received in a row (88uS break)
     {  
         numBytesRead = 0;      //Set number of bytes read back to 0 so we can read the first 9 bytes of the new packet
     }

 /* Reading Byte data to control pins */
 if(interestingBytes[2] == '255')  
 {
   digitalWrite(relay2, HIGH);  //if byte2 value = 255 set pin 2 to high
 }
 else if(interestingBytes[2] == '0')  //if byte2 value = 0 set pin 2 to low
 {
   digitalWrite(relay2, LOW);
 }
if(interestingBytes[3] == '255')  
 {
   digitalWrite(relay3, HIGH);  //if byte3 value = 255 set pin 3 to high
 }
 else if(interestingBytes[3] == '0')  //if byte2 value = 0 set pin 3 to low
 {
   digitalWrite(relay3, LOW);
 }
  if(interestingBytes[4] == '255')  
 {
   digitalWrite(relay4, HIGH);  //if byte4 value = 255 set pin 4 to high
 }
 else if(interestingBytes[4] == '0')  //if byte4 value = 0 set pin 4 to low
 {
   digitalWrite(relay4, LOW);
 }
  if(interestingBytes[5] == '255')  
 {
   digitalWrite(relay5, HIGH);  //if byte5 value = 255 set pin 5 to high
 }
 else if(interestingBytes[5] == '0')  //if byte5 value = 0 set pin 5 to low
 {
   digitalWrite(relay5, LOW);
 }
  if(interestingBytes[6] == '255')  
 {
   digitalWrite(relay6, HIGH);  //if byte6 value = 255 set pin 6 to high
 }
 else if(interestingBytes[6] == '0')  //if byte6 value = 0 set pin 6 to low
 {
   digitalWrite(relay6, LOW);
 }
  if(interestingBytes[7] == '255')  
 {
   digitalWrite(relay7, HIGH);  //if byte7 value = 255 set pin 7 to high
 }
 else if(interestingBytes[7] == '0')  //if byte7 value = 0 set pin 7 to low
 {
   digitalWrite(relay7, LOW);
 }
  if(interestingBytes[8] == '255')  
 {
   digitalWrite(relay8, HIGH);  //if byte8 value = 255 set pin 8 to high
 }
 else if(interestingBytes[8] == '0')  //if byte8 value = 0 set pin 8 to low
 {
   digitalWrite(relay8, LOW);
 }
  if(interestingBytes[9] == '255')  
 {
   digitalWrite(relay9, HIGH);  //if byte9 value = 255 set pin 9 to high
 }
 else if(interestingBytes[9] == '0')  //if byte9 value = 0 set pin 9 to low
 {
   digitalWrite(relay9, LOW);
 }
}




I'm not sure if I'm reading the bytes properly and if you can simply check and see if a byte is equal to some value as I am doing.

PaulS

Code: [Select]

  numBytesRead++;
  if(byteRead >= 0)
 {
    if(numBytesRead <= 9)
    {
      interestingBytes[numBytesRead] = byteRead;
    }
 }


This code will increment the position in the array where the character is to be stored, even if the character should not be stored. You need to move the numBytesRead increment statement AFTER the test for a valid character.

Code: [Select]

if (bitRead(byteRead,1))  // if a one is detected, we're not in a break, reset zerocounter.
    {  
       zerocounter = 0;
   }


This code gets executed after the last byte was read, regardless of how many that was. Is that the intent? What does the bitRead function do? You didn't post the code for that function.

Code: [Select]

 if(interestingBytes[2] == '255')  
 {
   digitalWrite(relay2, HIGH);  //if byte2 value = 255 set pin 2 to high
 }


What is the result of this block of code if you only read one (or two) valid characters?

Quote
Here is what I have come up with and so far it's not working.


What a shame. Can you be just a little bit more precise as to HOW it's not working, and how you know it's not working?

Groove

Code: [Select]
if(interestingBytes[5] == '255')

That's a very odd constant there.
Is that what you meant?
Per Arduino ad Astra

djred2000

Here is a better explanation.  I am basing everything off of the information here: http://www.arduino.cc/playground/DMX/Protokoll

I'm trying to read the first 9 bytes of the stream with this code.  I'm only going to use bytes 2-9 because the first byte of every DMX stream is a start byte and it contains a value of 0.
Code: [Select]

while(Serial.available() > 0)
{
  byteRead = Serial.read();
 
  if(byteRead >= 0)
 {
   numBytesRead++;
    if(numBytesRead <= 9)
    {
      interestingBytes[numBytesRead] = byteRead;
    }
 }
}

The code is saying that while serial data is being received, record the data to byteRead.  If byteRead is greater then or equal to 0 then increase numBytesRead by one.  If the numBytesRead is less then 9 then record the serial data from byteRead to interestingBytes[1-9].  Each interestingByte should contain a value for a channel.
I'm not sure on how to handle the remaining 500 or so bytes in the stream.  My thought is just to ignore them but I'm not sure if that works.

The next section of code is designed to detect the break between the stream.  It's a bunch of bits with the value of 0 for approximately 88 milliseconds.

Code: [Select]

/* detecting break between packets */
    if (bitRead(byteRead,1))  // if a one is detected, we're not in a break, reset zerocounter.
    {  
       zerocounter = 0;
   }
   if(bitRead(byteRead,0))  //if the bit is a 0 then we are in a break
   {
       zerocounter++;             // increment zerocounter
   }
   if (zerocounter >= 22)        // if 22 0's are received in a row (88uS break)
     {  
         numBytesRead = 0;      //Set number of bytes read back to 0 so we can read the first 9 bytes of the new packet
     }


This code is reading each bit to see if it is a 0 or a 1.  Each time a 1 is received it resets zerocounter but if a 0 is received it increments zerocounter by 1.  When we receive 22 0's in a row then there is a break and we reset numBytesRead back to 0 to start reading the first 9 bytes from the stream again.

The final section is attempting to read the value of the byte.  In the DMX program I can set the value of a channel which corresponds to a byte to any number between 0 and 255.  I'm not sure if you can simply check to see if a variable is equal to a number like I am doing.

Code: [Select]

/* Reading Byte data to control pins */
 if(interestingBytes[2] == '255')  
 {
   digitalWrite(relay2, HIGH);  //if byte2 value = 255 set pin 2 to high
 }
 else if(interestingBytes[2] == '0')  //if byte2 value = 0 set pin 2 to low
 {
   digitalWrite(relay2, LOW);
 }


When I have the DMX program running I set channel 1 to a value of 255 which should correspond to the second byte of each packet/stream since byte 1 is the start byte.  However, when I change the value nothing happens.

I hope that is a better explanation and any help would be great.

Go Up