Introduction: DMX Relay Module

Receives DMX to control a 12v Relay for a candle led

Step 1: Materials

1x Adruino Uno

1x MAX485 Module

1x 5v Relay Module

1x TM1637 4 Digit 7 Segment Display

1x Rotary Encoder (5pins, push switch)

1x Male 3pin DMX connector

1x >5v LED

1x 12v Battery

1x 12v LED

Various resistors and wire based on your parts and set up

Step 2: Wire for DMX

Connect the MAX485 Module to the Arduino, Male 3Pin DMX connector, and breadboard, and the Male 3pin DMX connector to the breadboard

Step 3: Rotary Encoder

Connect the Rotary Encoder to the Arduino and breadboard

Step 4: Display

Connect the TM1637 4 Digit 7 Segment Display to the Arduino and breadboard

Step 5: LED >5v

Connect the LED and resistors on the breadboard

Step 6: Relay Module

Connect 5v Relay Module, 12v Battery, and 12v LED

Step 7: Code

#include <DMXSerial.h>

#include <EEPROM.h> #include <Arduino.h> #include <SevenSegmentTM1637>

const int GreenPin = 5; // PWM output pin for Green Light.

const int RelayPin = 8; // output pin for Relay int ChValue = 0;

#define GreenDefaultLevel 0

// Rotary encoder declarations static int pinA = 2; // Our first hardware interrupt pin is digital pin 2 static int pinB = 3; // Our second hardware interrupt pin is digital pin 3 volatile byte aFlag = 0; // let's us know when we're expecting a rising edge on pinA to signal that the encoder has arrived at a detent volatile byte bFlag = 0; // let's us know when we're expecting a rising edge on pinB to signal that the encoder has arrived at a detent (opposite direction to when aFlag is set) volatile int encoderPos = 0; //this variable stores our current value of encoder position. Change to int or uin16_t instead of byte if you want to record a larger range than 0-255 volatile int oldEncPos = 0; //stores the last encoder position value so we can compare to the current reading and see if it has changed (so we know when to print to the serial monitor) volatile byte reading = 0; //somewhere to store the direct values we read from our interrupt pins before checking to see if we have moved a whole detent

// Button reading, including debounce without delay function declarations const byte buttonPin = 4; // this is the Arduino pin we are connecting the push button to byte oldButtonState = HIGH; // assume switch open because of pull-up resistor const unsigned long debounceTime = 10; // milliseconds unsigned long buttonPressTime; // when the switch last changed state boolean buttonPressed = 0; // a flag variable

const byte PIN_CLK = 6; // define CLK pin (any digital pin) const byte PIN_DIO = 7; // define DIO pin (any digital pin) SevenSegmentTM1637 display(PIN_CLK, PIN_DIO);

//set up EEPROM int address = 1; //DMX starting address int addr = 0; //EEPROM address int a = 0; //holds value for EEPROM data division int b = 0; //holds value for EEPROM data division int val; //stores value of dmx int mapVal; //stores mapped value of dmx

void setup() { DMXSerial.init(DMXReceiver); // set some default values DMXSerial.write(1, 0); DMXSerial.write(2, 0); DMXSerial.write(3, 0); DMXSerial.write(4, 0); // enable pwm outputs pinMode(GreenPin, OUTPUT);

pinMode(RelayPin, OUTPUT); // sets the digital pin as output

display.begin(); // initializes the display display.setBacklight(100); // set the brightness to 100 % display.print("INIT"); // display INIT on the display delay(1000); // wait 1000 ms display.clear();

//Rotary encoder section of setup pinMode(pinA, INPUT_PULLUP); // set pinA as an input, pulled HIGH to the logic voltage (5V or 3.3V for most cases) pinMode(pinB, INPUT_PULLUP); // set pinB as an input, pulled HIGH to the logic voltage (5V or 3.3V for most cases) attachInterrupt(0, PinA, RISING); // set an interrupt on PinA, looking for a rising edge signal and executing the "PinA" Interrupt Service Routine (below) attachInterrupt(1, PinB, RISING); // set an interrupt on PinB, looking for a rising edge signal and executing the "PinB" Interrupt Service Routine (below)

// button section of setup pinMode (buttonPin, INPUT_PULLUP); // setup the button pin // Button reading with non-delay() debounce - thank you Nick Gammon! byte buttonState = digitalRead (buttonPin); if (buttonState != oldButtonState) { if (millis () - buttonPressTime >= debounceTime) { // debounce buttonPressTime = millis (); // when we closed the switch oldButtonState = buttonState; // remember for next time if (buttonState == LOW) { //this means the button has been pressed buttonPressed = 1; } else { //this means the button is not currently pressed buttonPressed = 0; } } // end if debounce time up } // end of state change

// Load saved DMX address int a = EEPROM.read(0); int b = EEPROM.read(1); address = a * 256 + b; encoderPos = (address); //set encoder value to start at saved address }

void loop() { display.clear(); display.print(encoderPos); rotaryMenu();

int k;

// Show decimal numbers with/without leading zeros bool lz = false; for (uint8_t z = 0; z < 2; z++) { for (k = 0; k < 10000; k += k * 4 + 7) { display.print(encoderPos); } lz = true; } //save DMX address to EEPROM and display "done" when set if (digitalRead (buttonPin) == LOW) { a = encoderPos / 256; //split DMX address into two parts so that it can fit in the EEPROM b = encoderPos % 256; EEPROM.write(0, a); //store dmx address in EEPROM EEPROM.write(1, b); // Done! display.print("SET"); delay (1000); display.print(encoderPos); }

// Calculate how long no data backet was received unsigned long lastPacket = DMXSerial.noDataSince(); if (lastPacket < 5000) { // read recent DMX values and set pwm levels analogWrite(GreenPin, DMXSerial.read(1));

ChValue = DMXSerial.read(encoderPos);

if (ChValue > 20) { // read recent DMX values and set pwm levels digitalWrite(RelayPin, HIGH); } else { digitalWrite(RelayPin, LOW); } } }

void rotaryMenu() { //This handles the bulk of the menu functions without needing to install/include/compile a menu library //Rotary encoder update display if turned if (oldEncPos != encoderPos) { // DEBUGGING oldEncPos = encoderPos;// DEBUGGING

delay(10); } //Do not allow encoder to read below 1 or above 508 if (encoderPos < 1) { encoderPos = 1; } if (encoderPos > 508) { encoderPos = 508; }

}

//Rotary encoder interrupt service routine for one encoder pin void PinA() { cli(); //stop interrupts happening before we read pin values reading = PIND & 0xC; // read all eight pin values then strip away all but pinA and pinB's values if (reading == B00001100 && aFlag) { //check that we have both pins at detent (HIGH) and that we are expecting detent on this pin's rising edge encoderPos --; //decrement the encoder's position count bFlag = 0; //reset flags for the next turn aFlag = 0; //reset flags for the next turn } else if (reading == B00000100) bFlag = 1; //signal that we're expecting pinB to signal the transition to detent from free rotation sei(); //restart interrupts }

//Rotary encoder interrupt service routine for the other encoder pin void PinB() { cli(); //stop interrupts happening before we read pin values reading = PIND & 0xC; //read all eight pin values then strip away all but pinA and pinB's values if (reading == B00001100 && bFlag) { //check that we have both pins at detent (HIGH) and that we are expecting detent on this pin's rising edge encoderPos ++; //increment the encoder's position count bFlag = 0; //reset flags for the next turn aFlag = 0; //reset flags for the next turn } else if (reading == B00001000) aFlag = 1; //signal that we're expecting pinA to signal the transition to detent from free rotation sei(); //restart interrupts } // end of sketch!

Step 8: Coding Brief Notes

Greenpin (Pin5) is just a monitor LED to make sure I was getting good DMX and is independent of all the other components, currently it is set to respond to Address 1.

RelayPin (Pin8) is a signal pin going to the Relay Module to be switched on and off through the light board by raising the level above 20(out of a possible 255).

The way the rotary encoder works is that it is able to store its value with EEPROM so that even when it doesn't have power it can remember. So on start up it will check for the last saved value and show it on the display, this is the current DMX Address that will control the relay. The rotary encoder allows you to change the number on the display by spinning, and once you press it down it will save that value to EEPROM and flash "DONE" before showing you the saved value.

Step 9: Test - Working