Sketch for 0016?

Hi, I am trying to use this sketch to receive DMX data and PWM RGB LED’s.

When the DMX controller is plugged in and initiated, the LED on pin 13 flashes very very quickly, meaning it should be receiving DMX data, but I dont get any PWM output on the LED’s. Also, in the sketch, it has Serial.begin(250000);, which isn’t even a valid baudrate in the serial monitor, is it?

Apparently the HardwareSerial.cpp or .h file needs to be modified for this sketch to work, though I have tried many things and it still doesn’t work.

Anyone see any problems?

* DMX-512 Reception                                        *
* Developed by Max Pierson                                 *
* Version Rev13 9 July 2009                                *
* Released under the WTFPL license, although I would       *
* appreciate Attribution and Share-Alike                   *
* See for the latest version. *

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

#include <EEPROM.h>
//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
int dmxaddress = 1;
/* The dmx address we will be listening to.  The value of this will be set in the Addressing()
*  function, if triggered, and read from EEPROM addresses 510 and 511.

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

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

/* 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.
volatile boolean dmxnewvalue = 0; //set to 1 when new dmx values are received.

/******************************* 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.  As written,
*  the timer2 ISR actually checks for 22 zeros in a row, for the full 88uS break.       */

void setup() {
  /******************************* Max485 configuration ***********************************/
  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
  byte switch1 = 0;
  byte switch0 = 0;  //the switch states for the 1 and 0 pin 
  switch0 = digitalRead(SWITCH_PIN_0);
  switch1 = digitalRead(SWITCH_PIN_1);
  if (switch0 == 0 || switch1 == 0)
  Addressing(switch0, switch1);
  //call the addressing subroutine if either switch is pressed.

  //read the previously stored value from EEPROM addresses 510 and 511.
  dmxaddress =;   //read the high byte into dmxaddress
  dmxaddress = dmxaddress << 8;  
  //bitshift the high byte left 8 bits to make room for the low byte
  dmxaddress =  dmxaddress |;   //read the low byte into dmxaddress
  dmxaddress = dmxaddress + 3;
  /*  this will allow the USART receive interrupt to fire an additional 3 times for every dmx frame.  
  *   Here's why:
  *   Once to account for the fact that DMX addresses run from 0-511, whereas channel numbers
  *        start numbering at 1.
  *   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).  */

  /******************************* USART configuration ************************************/
  /* 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...
  digitalWrite(13, HIGH);
  byte j;
  for(j = 0; j < NUMBER_OF_CHANNELS; j++) 
  analogWrite(9, dmxvalue[0]);
  analogWrite(9, dmxvalue[1]);
    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
  digitalWrite(13, LOW);
} //end loop()

//Timer2 compare match interrupt vector handler
  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 == 22)     // if 22 0's are received in a row (88uS break)
      bitClear(TIMSK2, OCIE2A);    //disable this interrupt and enable reception interrupt now that we're in a break.
      bitSet(UCSR0B, RXCIE0);
} //end Timer2 ISR

  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;
    if(i == NUMBER_OF_CHANNELS) {
      bitClear(UCSR0B, RXCIE0); 
      dmxnewvalue = 1;                        //set newvalue, so that the main code can be executed.
} // end ISR

Thanks :slight_smile:

Where did you get this sketch? Perhaps there are more clues there.

The sketch is from here:


Using a proggy to read serial data at 250K baud, I have found that dmxvalue[0] and [1] are actually useless data. dmxvalue[2] = channel 1 on the DMX controller.