Trouble with DMX

I hope this is the right forum for this. I'm trying to control my Arduino via DMX. Not trying to do anything fancy, just want to print the DMX signal to a putty window for now.

I'm following this guide: http://www.maxwellrosspierson.com/2009/03/20/receive-dmx-512-with-an-arduino/2/ I'm not using a shield, I have a DMX connector attached to a breadboard where my MAX485 is hooked up. I've attached a picture of this.

I'm using Lights Up! as my software with ENTTEC OPENDMX USB as my DMX output. I've set channel 1 to full and set the address on the Arduino to respond to channel 1.

The code is the same as in the guide except I've set the address to 1 instead of set with buttons and I've set the number of channels to 1.

What do I need to do? I assume you'll need more information than this but I'm not sure what else to say.

Thanks for your help.

I'm not sure you will get stable results printing to the USB port and the RS485 at the same time.
You really need to post your code, a schematic and details of the RS485 chip your using as I also see no power/ground connections to it.

Powering it got it working. Not my brightest moment.

I'm trying to read from the RS485, not write to it. DMX is supposed to be input only, and I'm outputting through USB. Is that not possible?

As for my code, I'm working from the site I linked. Unfortunately, it's a bit above me.

/***********************************************************
* DMX-512 Reception                                        *
* Developed by Max Pierson                                 *
* Version Rev15 9 Oct 2010                                 *
* Released under the WTFPL license, although I would       *
* appreciate Attribution and Share-Alike                   *
* See blog.wingedvictorydesign.com for the latest version. *
************************************************************/



/******************************* Addressing variable declarations *****************************/

#include <EEPROM.h>
#define NUMBER_OF_CHANNELS 8
//the number of channels we want to receive (8 by default).

#define SWITCH_PIN_0 11 //the pin number of our "0" switch
#define SWITCH_PIN_1 12 //the pin number of our "1" switch
unsigned int dmxaddress = 1; //for some reason it's 7

/* The dmx address we will be listening to.  The value of this will be set in the Addressing()
*  function and read from EEPROM addresses 510 and 511.

/******************************* MAX485 variable declarations *****************************/

#define RECEIVER_OUTPUT_ENABLE 2
/* receiver output enable (pin2) on the max485.  
*  will be left low to set the max485 to receive data. */

#define DRIVER_OUTPUT_ENABLE 3
/* driver output enable (pin3) on the max485.  
*  will left low to disable driver output. */

#define RX_PIN 0   // serial receive pin, which takes the incoming data from the MAX485.
#define TX_PIN 1   // serial transmission pin

/******************************* DMX variable declarations ********************************/

volatile byte i = 0;              //dummy variable for dmxvalue[]
volatile byte dmxreceived = 0;    //the latest received value
volatile unsigned int dmxcurrent = 0;     //counter variable that is incremented every time we receive a value.
volatile byte dmxvalue[NUMBER_OF_CHANNELS];     
/*  stores the DMX values we're interested in using-- 
 *  keep in mind that this is 0-indexed. */
volatile boolean dmxnewvalue = false; 
/*  set to 1 when updated dmx values are received 
 *  (even if they are the same values as the last time). */

/******************************* Timer2 variable declarations *****************************/

volatile byte zerocounter = 0;          
/* a counter to hold the number of zeros received in sequence on the serial receive pin.  
*  When we've received a minimum of 11 zeros in a row, we must be in a break.  */




void setup() {
  
  /******************************* Max485 configuration ***********************************/
  
  pinMode(RECEIVER_OUTPUT_ENABLE, OUTPUT);
  pinMode(DRIVER_OUTPUT_ENABLE, OUTPUT);
  digitalWrite(RECEIVER_OUTPUT_ENABLE, LOW);
  digitalWrite(DRIVER_OUTPUT_ENABLE, LOW);    //sets pins 3 and 4 to low to enable reciever mode on the MAX485.

  pinMode(RX_PIN, INPUT);  //sets serial pin to receive data

  /******************************* Addressing subroutine *********************************/

  pinMode(SWITCH_PIN_0, INPUT);           //sets pin for '0' switch to input
  digitalWrite(SWITCH_PIN_0, HIGH);       //turns on the internal pull-up resistor for '0' switch pin
  pinMode(SWITCH_PIN_1, INPUT);           //sets pin for '1' switch to input  
  digitalWrite(SWITCH_PIN_1, HIGH);       //turns on the internal pull-up resistor for '1' switch pin
  
  /* Call the addressing subroutine.  Three behaviors are possible:
  *  1. Neither switch is pressed, in which case the value previously stored in EEPROM
  *  510 and 511 is recalled,
  *  2. Both switches are pressed, in which case the address is reset to 1.
  *  3. Either switch is pressed (but not both), in which case the new address may 
  *  be entered by the user.
  */
  //set this equal to a constant value if you just want to hardcode the address.
  dmxaddress = 1;
  
  /******************************* USART configuration ************************************/
  
  Serial.begin(250000);
  /* Each bit is 4uS long, hence 250Kbps baud rate */
  
  cli(); //disable interrupts while we're setting bits in registers
  
  bitClear(UCSR0B, RXCIE0);  //disable USART reception interrupt
  
  /******************************* Timer2 configuration ***********************************/
  
  //NOTE:  this will disable PWM on pins 3 and 11.
  bitClear(TCCR2A, COM2A1);
  bitClear(TCCR2A, COM2A0); //disable compare match output A mode
  bitClear(TCCR2A, COM2B1);
  bitClear(TCCR2A, COM2B0); //disable compare match output B mode
  bitSet(TCCR2A, WGM21);
  bitClear(TCCR2A, WGM20);  //set mode 2, CTC.  TOP will be set by OCRA.
  
  bitClear(TCCR2B, FOC2A);
  bitClear(TCCR2B, FOC2B);  //disable Force Output Compare A and B.
  bitClear(TCCR2B, WGM22);  //set mode 2, CTC.  TOP will be set by OCRA.
  bitClear(TCCR2B, CS22);
  bitClear(TCCR2B, CS21);
  bitSet(TCCR2B, CS20);   // no prescaler means the clock will increment every 62.5ns (assuming 16Mhz clock speed).
  
  OCR2A = 64;                
  /* Set output compare register to 64, so that the Output Compare Interrupt will fire
  *  every 4uS.  */
  
  bitClear(TIMSK2, OCIE2B);  //Disable Timer/Counter2 Output Compare Match B Interrupt
  bitSet(TIMSK2, OCIE2A);    //Enable Timer/Counter2 Output Compare Match A Interrupt
  bitClear(TIMSK2, TOIE2);   //Disable Timer/Counter2 Overflow Interrupt Enable          
  
  sei();                     //reenable interrupts now that timer2 has been configured. 
  
}  //end setup()


void loop()  {
  // the processor gets parked here while the ISRs are doing their thing. 
  
  if (dmxnewvalue == 1) {    //when a new set of values are received, jump to action loop...
    action();
    dmxnewvalue = 0;
    dmxcurrent = 0;
    zerocounter = 0;      //and then when finished reset variables and enable timer2 interrupt
    i = 0;
    bitSet(TIMSK2, OCIE2A);    //Enable Timer/Counter2 Output Compare Match A Interrupt
  }
} //end loop()


//Timer2 compare match interrupt vector handler
ISR(TIMER2_COMPA_vect) {
  if (bitRead(PIND, PIND0)) {  // if a one is detected, we're not in a break, reset zerocounter.
    zerocounter = 0;
    }
  else {
    zerocounter++;             // increment zerocounter if a zero is received.
    if (zerocounter == 20)     // if 20 0's are received in a row (80uS break)
      {   
      bitClear(TIMSK2, OCIE2A);    //disable this interrupt and enable reception interrupt now that we're in a break.
      bitSet(UCSR0B, RXCIE0);
      }
  }
} //end Timer2 ISR



ISR(USART_RX_vect){
  dmxreceived = UDR0;
  /* The receive buffer (UDR0) must be read during the reception ISR, or the ISR will just 
  *  execute again immediately upon exiting. */
 
  dmxcurrent++;                        //increment address counter
 
  if(dmxcurrent > dmxaddress) {         //check if the current address is the one we want.
    dmxvalue[i] = dmxreceived;
    i++;
    if(i == NUMBER_OF_CHANNELS) {
      bitClear(UCSR0B, RXCIE0); 
      dmxnewvalue = 1;                        //set newvalue, so that the main code can be executed.
    } 
  }
} // end ISR

void action() { 
  /*********** Put what you want the code to do with the values (dmxvalue) here *************
   * example code: print out the received values to the serial port, and set PWM pins 5 and 6 
   to the first two values received.  You can take this code out and put your own in.*/

  //begin example code
  //for(byte j = 0; j < NUMBER_OF_CHANNELS; j++) {

  Serial.println(dmxvalue[0],DEC);

  return;  //go back to loop()
} //end action() loop

unsigned int Addressing() {

  dmxaddress = 1;

}

Now, it's sort of working. I plug it all in and open the serial connection and turn on the DMX, but it spams 1, 0 and an occasional number around 137, regardless of what I set the outputs in LightsUp! to. Do you have any idea what might be going wrong? How can I troubleshoot it further? If it's outputting to serial that's the problem, it works just as well for me to output through an analog or digital pin.

The code your posted is using the hardware serial port of the Arduino (the same one used for USB) but appears to be hi-jacking the RX interrupt routine from the hardware serial so in theory you should be able to receive DMX and send to USB.
The PC serial speed would need setting to the same baud rate as the DMX (250000 baud) and some PC's serial ports might not go this fast.
A quick look at the link you supplied, the guy says he had to alter his hardware serial library to allow the RX interrupt hi-jacking.

If all you want to do is DMX receive a single channel on/off then maybe altering the code to just turn the Arduino's in build LED on off instead of sending the results over serial to the PC might help.

You seem to have a much better grasp on this than I do, I'm just following a guide. I appreciate your help.

However, the guide shows a problem. I've been having trouble with the DMX address being 7, regardless what I supposedly set it to. I'd like to be able to change this. There's a comment in the code I'm using that says "for some reason it's 7", so evidently I'm not the only one. I'm baffled by this. Perhaps you can offer some insight?

I don't know what I changed (it's possible that some wires were not in place, because I did plug some in, I don't know when they came out) but I can print to serial now and it mostly works but I get still something weird. It'll report the value I'm sending from LightsUp! a variable number of times, and then a 0. I can probably ignore this, but it'd be nice to deal with it

Thanks again.

#define RECEIVER_OUTPUT_ENABLE 2
/* receiver output enable (pin2) on the max485.  
*  will be left low to set the max485 to receive data. */

#define DRIVER_OUTPUT_ENABLE 3
/* driver output enable (pin3) on the max485.  
*  will left low to disable driver output. */

Is there any reason they have to be these values for the MAX485? I'm wanting to put an interrupt in here but these take up the two pins I need.

Once again I don't know what I changed and the occasional zeroes went away. I still can't figure out how to change the address.

I'm just posting in case anyone's reading this to find out things, you don't need to connect it to interrupts, you can change the 2 and 3 pins in the original code to 4 and 5 pins.

aoeud:

#define RECEIVER_OUTPUT_ENABLE 2

/* receiver output enable (pin2) on the max485. 
*  will be left low to set the max485 to receive data. */

#define DRIVER_OUTPUT_ENABLE 3
/* driver output enable (pin3) on the max485. 
*  will left low to disable driver output. */




Is there any reason they have to be these values for the MAX485? I'm wanting to put an interrupt in here but these take up the two pins I need.

Sorry for the late reply, was away for the weekend.
The MAX485's DE/~RE do not need to be on pins 2/3 and you should be able to combine them both onto the same single pin as the signals are mutually exclusive. When ~RE is low, DE needs to be low and vice versa as your not transmitting and receiving at the same time.

When I disconnect the DMX the last thing that was happening continues happening. Is there any way to prevent this and switch to a default value?

aoeud:
When I disconnect the DMX the last thing that was happening continues happening. Is there any way to prevent this and switch to a default value?

This is the usual thing for DMX.

A very quick look at the code and dmxnewvalue is set when new values arrive over DMX (even if they are same values as last time). You could write some test code to see how often this value updates and when you know this add code to you sketch to perform the alternate action if no DMX received for x amount of time.

Hi, I have done many many projects with DMX and adruino's of all sizes... I think if you are using a 328-based microcontroller you will struggle to receive DMX and transmit data back through the USB simultaneously, to get over this you may have to upgrade to a 2560-based board or choose another arduino option with more than one uart/usart.

ALTERNATIVELY:
Find the 'softwareserial' library and get a serial-to-usb convertor, you can then transmit data from any pin you like, which then goes through the serial-usb convertor and back to the PC (if thats what you are trying to do)

Incidentally if you are just reading DMX into the MAX485, both of the enable lines need to be grounded (from memory) in fact only one of them will actually be useful for RX, the other one enables transmission

Regards Bob

Hello AOEUD.

I'm also using this old, yet very useful piece of code and I'm having the same issue as you. At first I really had a hard time getting it to work, but now that I've finally gotten it to work, I'm experiencing the same issue as you. The address is 7. Did you find a solution to this issue or what did you end up doing?

EDIT: I have tested this once again, and it seems that the address is set to NUMBER_OF_CHANNELS - dmxaddress. Haven't tested it a lot, but my NUMBER_OF_CHANNELS was set to 8 and dmxaddress set to 1. If I changed the NUMBER_OF_CHANNELS to, say 4, my starting address would be 3. I'll look into to this when I'm less sleep deprived.

Best regards: Laboratory

Okay, I think I figured it out (only tested with channels 1 through 8 )

This excerpt should be placed right at the end of void setup()

I dug up some of the older revisions that didn't include all the Address() and here's what I found:

  dmxaddress = dmxaddress + 3;
  /*  this will allow the USART receive interrupt to fire an additional 3 times.  Here's why:
  *   Once for the last value received by the USART before the break, which will still be in the USART buffer, 
  *         causing the receive ISR to execute immediately upon enabling it,
  *   Once for the Mark After Break (MAB), which will be detected by the USART as a valid character 
  *        (a zero, eight more zeros, followed by a one)
  *   Once for the START code that precedes the 512 DMX values (used for RDM).  */