Introduction: Inexpensive DMX Tester


Hello All,

I work part-time (more of a hobby) in the lighting industry and use DMX since it is the industry standard for communicating or controlling devices (lighting fixtures, controllers, consoles, etc..) I have seen commercial DMX testers on the market but I wanted to create my own.

I have been working on an idea to create a low cost (<$50), Arduino based DMX tester.

The tester would provide the following functionality:

  1. Simple input protocol for entering commands using 4 X 4 - 16 button keypad matrix.
  2. Support LCD display - 4 line x 20 character
  3. Output DMX for single channel or a range of channels at a set intensity level.

The Hardware:

I started with the following:

  1. Arduino UNO board
  2. A 4 x 4 (16) button key pad (button matrix)
  3. A 4 x 20 Character LCD display w I2C (Serial) Interface
  4. low cost DMX / RDM Shield purchased from EBay (model: CTC-DRA-10-1, low cost, non-isolated)

The Input Commands:

I wanted to use a 4 x 4 (16) button key pad to input all the commands with a simple / easy to remember protocol (format).

Here is the basic command format:

Channel@Intensity

Start Channel-End Channel@ Intensity

Here is the actual input protocol using only a 4 x 4 (16) button key pad:

XXX@III# (Single Channel at a Specified Intensity)

XXX-XXX@III# (Range of Channels at a Specified Intensity)

*@*# (All Channels at Full Intensity)

XXX@*# (Single Channel at Full Intensity)

XXX-*@III# (Start Channel to Max Channel at a Specified Intensity)

XXX-*@*# (Start Channel to Max Channel at Full Intensity)

Key Mappings:

A = @ (at sign)

B = Bump (not implemented)

D = - (dash)

C = Clear

# = Execute

* = Wildcard value: 512 for channel and 256 for Full intensity

XXX = 1 to 512 Channel Number

III = 1 to 256 Intensity Level

Code Development / Testing:

I developed / tested the code in several stages:

  1. Keypad input - 4 x 4 (16) button key pad (or switch array)
  2. LCD display - 4 x 20 Character LCD w I2C interface
  3. Verify/test the input commands (protocol) were working correctly
  4. Add DMX master (sending) code

Step 1: The Keypad

The Keypad

Hardware:
I had 3 types of key pads that I played with (switches on a PC board, membrane switch, soft-touch)
See the pictures of keypads.

Software:

I started with the Keypad library for easy matrix style keypad mapping. See http://playground.arduino.cc/code/Keypad for more information.

I had to play around with the Row and Column mapping to get my Key Pad switch matrix to work. The pin-out in the documentation wasn't correct on any of the keypads. So once I determined the correct pin-out, the code worked perfectly.

Here is code snippet showing how to use the Keypad library:

(This is for the 16 switches on PC board)

#include <Keypad.h>

const byte ROWS = 4; // define four rows
const byte COLS = 4; // define four columns
char keys [ROWS] [COLS] = {
{'1', '2', '3','@'},
{'4', '5', '6','B'},
{'7', '8', '9','C'},
{'*', '0', '#','-'}
};
// Pin  R/C 
// 8    C4
// 7    C3
// 6    C2
// 5    C1
// 4    R1
// 3    R2
// 2    R3
// 1    R4

// Connect 4 * 4 buttons faithfully port, the corresponding digital IO ports panel
byte colPins [COLS] = {10,11,12,13};

// Call the function library function Keypad
Keypad keypad = Keypad (makeKeymap (keys), rowPins, colPins, ROWS, COLS);

void loop () {  
  char key = keypad.getKey ();
  if (key != NO_KEY) {
    
    // Clear
    if(key == 'C') {
      state = CLEAR;
    }
}

Step 2: LCD Display

Hardware:

I used a standard 4x20 character display with I2C interface which can be purchased from Ebay for about $10.00. See picture of 4x20 character display.

Software:

I started with a I2C LCD display library. See LiquidCrystal_I2C Library for more information.

I really didn't have any problems getting the display to work. The 2x16 character display included in my Arduino kit didn't work so I ordered a 4x20 character display and it worked the first time I tried it.

Here is a code snippet showing how to use the LiquidCrystal_I2C library:

#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd(0x3F,20,4);

void setup () {
  lcd.init();
  lcd.backlight();
  lcd.setCursor(0,0);
  lcd.print("DMX Tester ");
  lcd.print(VERSION);
  lcd.setCursor(0,1);
  lcd.print("Enter Cmd:");
}

Step 3: The Input Protocol (Commands)

At first I was going to use a state machine logic to handle the input
from the keypad but I decided to try to just code it with normal logic. After writing the initial version, I spent about 4 or 5 hours debugging the code. I soon realized I should have created a state diagram and used state driven logic. to parse the input properly.

So I deleted most of the code and wrote a test plan and state diagram to match the input protocol.

Here is the test plan with all the input protocols defined: DMX Tester Test Plan

and here is the state diagram: DMX Tester State Diagram

Once I have the state diagram completed, I coded the input part of the projects in about 1.5 hours while I was on a sitting on plane. After I tested and was satisfied the input logic was working I attached the DMX shield and added the DMX library.

Step 4: Introduction to State Machine Logic

If you aren't familiar with or haven't used state machine logic in programming, it is the easiest way to to break complex problems into manageable states and state transitions. One of the easiest ways to implement a state machine is to use a switch statement.

Example of a state machine using a switch statement:

switch(state) {case INITIAL:
     // process INITIAL state  
   break;
   case STATE1:
     // process STATE1 state       
   break;
   case CLEAR:
     clearAll();
     state = INITIAL;
   break;
   default:
   break;
}

Depending on the state, there are only a few valid keys. Lets take a look at the first state called INITIAL. As you can see from the state diagram the INITIAL state can only have the following keys: 0-9 and '*' (asterisk), else it is a format error.


StateKeysNext StateCommentINITIAL 0-9 START1 X
* WILDCARD1 *@
Anything Else INITIAL Format Error

Here is a code snippet showing how I implemented the INITIAL state:

char key = keypad.getKey ();<br>  if (key != NO_KEY) {
  switch(state) {
      case INITIAL:
        // X
        if(validKeys0to9(key)) {
          pos = displayKey(key, pos);
          storeKey(key);
          state = START1;
        } else if (validWildCard(key)) {
          // *@
          pos = displayKey(key, pos);
          state = WILDCARD1;          
        } else {
          invalidFormat();
          clearAll();
        }
      break;

As you can see I created some helper functions to make the code easy to read.

// Validate key *<br>// return true if valid, else false
int validWildCard(int key) {
  int valid=0;
  switch(key) {
    case '*':
      valid=1;
    break;
  }
  return valid;
}
<br>// Validate key 0-9
// return true if valid, else false
int validKeys0to9(int key) {
  int valid=0;
  switch(key) {
    case '0':
    case '1':
    case '2':
    case '3':
    case '4':
    case '5':
    case '6':
    case '7':
    case '8':
    case '9':
      valid=1;
    break;
  }
  return valid;
}

Step 5: The DMX Shield

Hardware:

I used a DMX Shield - Model: CTC-DRA-10-1, low cost, non-isolated which can be purchased from Ebay for about $15.00

See picture for DMX shield.

Software:

I used the Conceptinetics DMX Library to handle the DMX master (sending). See Conceptinetics DMX Library and this DMX Shield Blog more information. The library is very simple to use. Initialize and use 2 different commands to send either a single channel or a range of channels.

Here is a code snippet showing how to initial and use the DMX Library:

#define DMX_MASTER_CHANNELS  512<br>
// Pin number to change read or write mode on the shield
#define RXEN_PIN                2<br>

// Configure a DMX master controller, the master controller
// will use the RXEN_PIN to control its write operation 
// on the bus
DMX_Master        dmx_master ( DMX_MASTER_CHANNELS, RXEN_PIN );

void setup () {
  dmx_master.enable ();
}

void sendDMX(int start, int end, unsigned char intensity) {
  if(start == end) {
      dmx_master.setChannelValue(start, intensity);    
  } else {
    dmx_master.setChannelRange(start, end, intensity );
  }
}

Step 6: Development Issues

During the development of this project I ran into a few issues. I will describe the issues and how I resolved them.

  1. The serial port and the DMX library have a conflict with the interrupt handler. This means you can't debug using the serial terminal and have the DMX shield working at the same time.


    Here what I did to resolve this issue:
    1. I defined SERIAL_DEBUG_ENABLED
    2. I used #ifdef to conditionally compile in/out the serial/DMX functions.
    3. For some unknown reason I couldn't #ifdef out the #include header file so I have to comment it in/out to make it work.

See examples below.

FOR DMX ENABLED

// Comment out for Serial but not DMX
//#define SERIAL_DEBUG_ENABLED

// Comment out for Serial - include for DMX
#include <conceptinetics.h>

// Serial or DMX but not both
#ifdef SERIAL_DEBUG_ENABLED
  Serial.begin (9600);
#else
  dmx_master.enable ();
#endif

FOR SERIAL ENABLED

// Comment out for Serial but not DMX
#define SERIAL_DEBUG_ENABLED

// Comment out for Serial - include for DMX
//#include <conceptinetics.h>

// Serial or DMX but not both
#ifdef SERIAL_DEBUG_ENABLED
  Serial.begin (9600);
#else
  dmx_master.enable ();
#endif

Step 7: Wrap Up

Packaging:

Here is the complete project without a case and no battery pack.

Source Code:

The complete DMX Tester source code is available here.

Parts List:

  1. Arduino Uno
  2. LCD display 4X20 character with I2C interface
  3. Keypay - 4X4 (16 button)
  4. DMX shield
  5. Plastic enclosure case
  6. Battery case
  7. XLR 5 pin connectors - chassis mount (I use 5 pin instead of 3 pin on the DMX shield)

Future Enhancements / Ideas:

  1. Allow selectable percent (1 to 100) or value (1 to 256) for intensity
  2. Support channel bump operation.
  3. Allow channels to be selected in a range by pressing the 'B'ump button.
  4. Add menu for additional features.
  5. Option to receive a channel and display the value.
  6. Support multifunction keys (keys can have multiple meaning depending on mode)

Other Projects:

  • I'm hoping to use this project to spin off into several other projects. Here is a brief description of the other projects: A proximity detector that sends a DMX trigger signal (message). I want to use this for a Halloween project. When a person walks by an area, the proximity detector will trigger and send a DMX message to a lighting console configured to accept this channel. The message will trigger a pre-programmed lighting scene.

Questions?

If you have any questions please feel free to ask.

I hope this article is helpful and useful to someone interested in DMX in the lighting field.

Comments

author
rothackerben8 (author)2017-01-24

Any chance of a schematic? I am wanting to build this as a school project

author

Yes. I will create a quick schematic and post on here.

author
Evdeals (author)2016-01-18

Could you design a single channel dmx controller with asdignable channels thag would be used to assigne the dmx output. No dimming just full on with a momentary switch.
Thank you

author
onewithhammer (author)Evdeals2016-01-24

Yes. This would be easy to do with the Arduino/shield combo but there are a number of DMX relay switch options that are inexpensive. Check Ebay for DMX relay switches.

author
DillyDog (author)2014-09-21

Is there any chance of a schematic?

About This Instructable

5,934views

14favorites

License:

Bio: Passionate about Technology, online payments, online security, Lighting Industry, Q/A automation and Arduino based projects.
More by onewithhammer:Web Driver IO Tutorial Using A Live Web Site And Working ExamplesInterests Keypad Input Validation Using State Machine Programming
Add instructable to: