├── DmxSimple.cpp ├── DmxSimple.h ├── README.md ├── docs └── issue_template.md ├── examples ├── FadeUp │ └── FadeUp.ino └── SerialToDmx │ └── SerialToDmx.ino ├── extras └── lights.jpg ├── keywords.txt ├── library.properties └── release_notes.txt /DmxSimple.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * DmxSimple - A simple interface to DMX. 3 | * 4 | * Copyright (c) 2008-2009 Peter Knight, Tinker.it! All rights reserved. 5 | */ 6 | // modified to support all Teensy boards 7 | #include 8 | #include 9 | #include 10 | #include "pins_arduino.h" 11 | 12 | #include "Arduino.h" 13 | #include "DmxSimple.h" 14 | 15 | /** dmxBuffer contains a software copy of all the DMX channels. 16 | */ 17 | volatile uint8_t dmxBuffer[DMX_SIZE]; 18 | static uint16_t dmxMax = 16; /* Default to sending the first 16 channels */ 19 | static uint8_t dmxStarted = 0; 20 | static uint16_t dmxState = 0; 21 | 22 | #if defined(ARDUINO_TEENSY40) || defined(ARDUINO_TEENSY41) || defined(ARDUINO_TEENSY_MICROMOD) 23 | // Teensy 4.X has 32-bit ports 24 | static volatile uint32_t *dmxPort; 25 | #else 26 | static volatile uint8_t *dmxPort; 27 | #endif 28 | 29 | static uint8_t dmxBit = 0; 30 | static uint8_t dmxPin = 3; // Defaults to output on pin 3 to support Tinker.it! DMX shield 31 | 32 | void dmxBegin(); 33 | void dmxEnd(); 34 | void dmxSendByte(volatile uint8_t); 35 | void dmxWrite(int,uint8_t); 36 | void dmxMaxChannel(int); 37 | 38 | /* TIMER2 has a different register mapping on the ATmega8. 39 | * The modern chips (168, 328P, 1280) use identical mappings. 40 | */ 41 | #if defined(__AVR_ATmega168__) || defined(__AVR_ATmega168P__) || defined(__AVR_ATmega328P__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) || defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__) 42 | #define TIMER2_INTERRUPT_ENABLE() TIMSK2 |= _BV(TOIE2) 43 | #define TIMER2_INTERRUPT_DISABLE() TIMSK2 &= ~_BV(TOIE2) 44 | #define ISR_NAME TIMER2_OVF_vect 45 | #define BITS_PER_TIMER_TICK (F_CPU / 31372) 46 | 47 | // older ATMEGA8 has slighly different timer2 48 | #elif defined(__AVR_ATmega8__) 49 | #define TIMER2_INTERRUPT_ENABLE() TIMSK |= _BV(TOIE2) 50 | #define TIMER2_INTERRUPT_DISABLE() TIMSK &= ~_BV(TOIE2) 51 | #define ISR_NAME TIMER2_OVF_vect 52 | #define BITS_PER_TIMER_TICK (F_CPU / 31372) 53 | 54 | // ATMEGA32U4 on Teensy and Leonardo has no timer2, but has timer4 55 | #elif defined (__AVR_ATmega32U4__) 56 | #define TIMER2_INTERRUPT_ENABLE() TIMSK4 |= _BV(TOIE4) 57 | #define TIMER2_INTERRUPT_DISABLE() TIMSK4 &= ~_BV(TOIE4) 58 | #define ISR_NAME TIMER4_OVF_vect 59 | #define BITS_PER_TIMER_TICK (F_CPU / 31372) 60 | 61 | // Teensy 3.0 has IntervalTimer, unrelated to any PWM signals 62 | #elif defined(CORE_TEENSY) && defined(__arm__) 63 | #define TIMER2_INTERRUPT_ENABLE() 64 | #define TIMER2_INTERRUPT_DISABLE() 65 | #define ISR_NAME DMXinterrupt 66 | #define ISR(function, option) void function(void) 67 | #define BITS_PER_TIMER_TICK 500 68 | void DMXinterrupt(void); 69 | IntervalTimer DMXtimer; 70 | 71 | #else 72 | #define TIMER2_INTERRUPT_ENABLE() 73 | #define TIMER2_INTERRUPT_DISABLE() 74 | #define ISR_NAME TIMER2_OVF_vect 75 | /* Produce an error (warnings to not print on Arduino's default settings) 76 | */ 77 | #error "DmxSimple does not support this CPU" 78 | #endif 79 | 80 | 81 | /** Initialise the DMX engine 82 | */ 83 | void dmxBegin() 84 | { 85 | dmxStarted = 1; 86 | 87 | // Set up port pointers for interrupt routine 88 | dmxPort = portOutputRegister(digitalPinToPort(dmxPin)); 89 | dmxBit = digitalPinToBitMask(dmxPin); 90 | 91 | // Set DMX pin to output 92 | pinMode(dmxPin,OUTPUT); 93 | 94 | // Initialise DMX frame interrupt 95 | // 96 | // Presume Arduino has already set Timer2 to 64 prescaler, 97 | // Phase correct PWM mode 98 | // So the overflow triggers every 64*510 clock cycles 99 | // Which is 510 DMX bit periods at 16MHz, 100 | // 255 DMX bit periods at 8MHz, 101 | // 637 DMX bit periods at 20MHz 102 | #if defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__) 103 | TCCR2A = (1<>=2; // 25% CPU usage 215 | while (1) { 216 | if (dmxState == 0) { 217 | // Next thing to send is reset pulse and start code 218 | // which takes 35 bit periods 219 | uint8_t i; 220 | if (bitsLeft < 35) break; 221 | bitsLeft-=35; 222 | *dmxPort &= ~dmxBit; 223 | for (i=0; i<11; i++) delayMicroseconds(8); 224 | *dmxPort |= dmxBit; 225 | delayMicroseconds(12); 226 | dmxSendByte(0); 227 | } else { 228 | // Now send a channel which takes 11 bit periods 229 | if (bitsLeft < 11) break; 230 | bitsLeft-=11; 231 | dmxSendByte(dmxBuffer[dmxState-1]); 232 | } 233 | // Successfully completed that stage - move state machine forward 234 | dmxState++; 235 | if (dmxState > dmxMax) { 236 | dmxState = 0; // Send next frame 237 | break; 238 | } 239 | } 240 | 241 | // Enable interrupts for the next transmission chunk 242 | TIMER2_INTERRUPT_ENABLE(); 243 | } 244 | 245 | void dmxWrite(int channel, uint8_t value) { 246 | if (!dmxStarted) dmxBegin(); 247 | if ((channel > 0) && (channel <= DMX_SIZE)) { 248 | if (value<0) value=0; 249 | if (value>255) value=255; 250 | dmxMax = max((unsigned)channel, dmxMax); 251 | dmxBuffer[channel-1] = value; 252 | } 253 | } 254 | 255 | void dmxMaxChannel(int channel) { 256 | if (channel <=0) { 257 | // End DMX transmission 258 | dmxEnd(); 259 | dmxMax = 0; 260 | } else { 261 | dmxMax = min(channel, DMX_SIZE); 262 | if (!dmxStarted) dmxBegin(); 263 | } 264 | } 265 | 266 | 267 | /* C++ wrapper */ 268 | 269 | 270 | /** Set output pin 271 | * @param pin Output digital pin to use 272 | */ 273 | void DmxSimpleClass::usePin(uint8_t pin) { 274 | bool restartRequired = dmxStarted; 275 | 276 | if (restartRequired) dmxEnd(); 277 | dmxPin = pin; 278 | if (restartRequired) dmxBegin(); 279 | } 280 | 281 | /** Set DMX maximum channel 282 | * @param channel The highest DMX channel to use 283 | */ 284 | void DmxSimpleClass::maxChannel(int channel) { 285 | dmxMaxChannel(channel); 286 | } 287 | 288 | /** Write to a DMX channel 289 | * @param address DMX address in the range 1 - 512 290 | */ 291 | void DmxSimpleClass::write(int address, uint8_t value) 292 | { 293 | dmxWrite(address, value); 294 | } 295 | DmxSimpleClass DmxSimple; 296 | -------------------------------------------------------------------------------- /DmxSimple.h: -------------------------------------------------------------------------------- 1 | /** 2 | * DmxSimple - A simple interface to DMX. 3 | * 4 | * Copyright (c) 2008-2009 Peter Knight, Tinker.it! All rights reserved. 5 | */ 6 | 7 | #ifndef DmxSimple_h 8 | #define DmxSimple_h 9 | 10 | #include 11 | 12 | #if RAMEND <= 0x4FF 13 | #define DMX_SIZE 128 14 | #else 15 | #define DMX_SIZE 512 16 | #endif 17 | 18 | class DmxSimpleClass 19 | { 20 | public: 21 | void maxChannel(int); 22 | void write(int, uint8_t); 23 | void usePin(uint8_t); 24 | }; 25 | extern DmxSimpleClass DmxSimple; 26 | 27 | #endif 28 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DmxSimple 2 | 3 | ![](extras/lights.jpg) 4 | 5 | DMX controlled lights and visual effects are easily available from DJ or theatrical suppliers. This library gives you a simple way to drive spot lamps, floods, wall washers, lasers, smoke machines and more from a normal Arduino using DMX. If you can use analogWrite() to dim an LED, you will have no problems using DmxSimple to control something much bigger and brighter. 6 | 7 | The software output is compatible with the Tinker.it! DMX shield, or DIY DMX circuits. 8 | 9 | DmxSimple does some fancy stuff behind the scenes, so there is no need to worry about DMX frames, retransmissions and channel orders. Specify which channels you want at which value, and the library will handle everything else for you. 10 | 11 | ## Compatibility 12 | 13 | DmxSimple is compatible with all known Arduinos including the Mega. The following Arduinos are recommended, as they support both DmxSimple and the Tinker.it! DMX shield: Arduino Mega, Arduino Duemilanove 328, Arduino Duemilanove, Arduino Diecimila, Arduino Bluetooth, Arduino Pro (5V version only), Arduino NG, Arduino Serial. 14 | 15 | ## Installation 16 | 17 | Download the archive. Extract to (arduino install)/hardware/libraries/DmxSimple . Restart Arduino so it recognises the library. 18 | 19 | ## Example code 20 | 21 | FadeUp 22 | SerialToDmx 23 | 24 | The example code is also built into the library. Open Arduino, and look under File > Sketchbook > Examples > Library-DmxSimple. 25 | 26 | ## Function calls 27 | 28 | ### DmxSimple.write(channel, value); 29 | 30 | Set DMX channel to value. Channel has the range 1 to 512 (128 on old Arduinos with a 168 or Mega 8). Value is in the range 0 (off) to 255 (full brightness). 31 | 32 | ### DmxSimple.maxChannel(channel); 33 | 34 | Set the number of DMX channels in the DMX system. The DMX system sends out channels in order, starting at 1. So it takes longer to send channels 1-512 than it does to send only channels 1-10. DmxSimple defaults to sending all channels, but by reducing this you can increase the lamp update rate for even smoother animation. Using DmxSimple.maxChannel(0) turns off the DMX system, so you can use pin 3 as a regular pin. It will revert to a DMX output next time you call DmxSimple.write() or DmxSimple.maxChannel(nonzero). 35 | 36 | ### DmxSimple.usePin(pin); 37 | 38 | Set the output pin. DmxSimple defaults to using pin 3, making it compatible with the Tinker.it! DMX shield. But if you use this function, you can output on any pin capable of digital output. 39 | 40 | ## DmxSimple community 41 | 42 | We now have a group on Google Groups. Get assistance starting with DMX, or show off your installations. 43 | 44 | ## Library limitations 45 | 46 | Timer 2 is used. Due to the small amount of RAM on 168 and Mega8 Arduinos, only the first 128 channels are supported. Arduinos with processor sockets can easily be upgraded to a 328 to control all 512 channels. 47 | 48 | ## Upgrade notes 49 | 50 | The original version 1 of DmxSimple used a file "DmxInterrupt.h". This has since been removed. To upgrade old sketches, remove the #include "DmxInterrupt.h" line. When upgrading the library from v1, delete all the old files before copying the contents of the new archive. 51 | -------------------------------------------------------------------------------- /docs/issue_template.md: -------------------------------------------------------------------------------- 1 | Please use this form only to report code defects or bugs. 2 | 3 | For any question, even questions directly pertaining to this code, post your question on the forums related to the board you are using. 4 | 5 | Arduino: forum.arduino.cc 6 | Teensy: forum.pjrc.com 7 | ESP8266: www.esp8266.com 8 | ESP32: www.esp32.com 9 | Adafruit Feather/Metro/Trinket: forums.adafruit.com 10 | Particle Photon: community.particle.io 11 | 12 | If you are experiencing trouble but not certain of the cause, or need help using this code, ask on the appropriate forum. This is not the place to ask for support or help, even directly related to this code. Only use this form you are certain you have discovered a defect in this code! 13 | 14 | Please verify the problem occurs when using the very latest version, using the newest version of Arduino and any other related software. 15 | 16 | 17 | ----------------------------- Remove above ----------------------------- 18 | 19 | 20 | 21 | ### Description 22 | 23 | Describe your problem. 24 | 25 | 26 | 27 | ### Steps To Reproduce Problem 28 | 29 | Please give detailed instructions needed for anyone to attempt to reproduce the problem. 30 | 31 | 32 | 33 | ### Hardware & Software 34 | 35 | Board 36 | Shields / modules used 37 | Arduino IDE version 38 | Teensyduino version (if using Teensy) 39 | Version info & package name (from Tools > Boards > Board Manager) 40 | Operating system & version 41 | Any other software or hardware? 42 | 43 | 44 | ### Arduino Sketch 45 | 46 | ```cpp 47 | // Change the code below by your sketch (please try to give the smallest code which demonstrates the problem) 48 | #include 49 | 50 | // libraries: give links/details so anyone can compile your code for the same result 51 | 52 | void setup() { 53 | } 54 | 55 | void loop() { 56 | } 57 | ``` 58 | 59 | 60 | ### Errors or Incorrect Output 61 | 62 | If you see any errors or incorrect output, please show it here. Please use copy & paste to give an exact copy of the message. Details matter, so please show (not merely describe) the actual message or error exactly as it appears. 63 | 64 | 65 | -------------------------------------------------------------------------------- /examples/FadeUp/FadeUp.ino: -------------------------------------------------------------------------------- 1 | /* Welcome to DmxSimple. This library allows you to control DMX stage and 2 | ** architectural lighting and visual effects easily from Arduino. DmxSimple 3 | ** is compatible with the Tinker.it! DMX shield and all known DIY Arduino 4 | ** DMX control circuits. 5 | ** 6 | ** DmxSimple is available from: http://code.google.com/p/tinkerit/ 7 | ** Help and support: http://groups.google.com/group/dmxsimple */ 8 | 9 | /* To use DmxSimple, you will need the following line. Arduino will 10 | ** auto-insert it if you select Sketch > Import Library > DmxSimple. */ 11 | 12 | #include 13 | 14 | void setup() { 15 | /* The most common pin for DMX output is pin 3, which DmxSimple 16 | ** uses by default. If you need to change that, do it here. */ 17 | DmxSimple.usePin(3); 18 | 19 | /* DMX devices typically need to receive a complete set of channels 20 | ** even if you only need to adjust the first channel. You can 21 | ** easily change the number of channels sent here. If you don't 22 | ** do this, DmxSimple will set the maximum channel number to the 23 | ** highest channel you DmxSimple.write() to. */ 24 | DmxSimple.maxChannel(4); 25 | } 26 | 27 | void loop() { 28 | int brightness; 29 | /* Simple loop to ramp up brightness */ 30 | for (brightness = 0; brightness <= 255; brightness++) { 31 | 32 | /* Update DMX channel 1 to new brightness */ 33 | DmxSimple.write(1, brightness); 34 | 35 | /* Small delay to slow down the ramping */ 36 | delay(10); 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /examples/SerialToDmx/SerialToDmx.ino: -------------------------------------------------------------------------------- 1 | /* This program allows you to set DMX channels over the serial port. 2 | ** 3 | ** After uploading to Arduino, switch to Serial Monitor and set the baud rate 4 | ** to 9600. You can then set DMX channels using these commands: 5 | ** 6 | ** c : Select DMX channel 7 | ** v : Set DMX channel to new value 8 | ** 9 | ** These can be combined. For example: 10 | ** 100c355w : Set channel 100 to value 255. 11 | ** 12 | ** For more details, and compatible Processing sketch, 13 | ** visit http://code.google.com/p/tinkerit/wiki/SerialToDmx 14 | ** 15 | ** Help and support: http://groups.google.com/group/dmxsimple */ 16 | 17 | #include 18 | 19 | void setup() { 20 | Serial.begin(9600); 21 | Serial.println("SerialToDmx ready"); 22 | Serial.println(); 23 | Serial.println("Syntax:"); 24 | Serial.println(" 123c : use DMX channel 123"); 25 | Serial.println(" 45w : set current channel to value 45"); 26 | } 27 | 28 | int value = 0; 29 | int channel; 30 | 31 | void loop() { 32 | int c; 33 | 34 | while(!Serial.available()); 35 | c = Serial.read(); 36 | if ((c>='0') && (c<='9')) { 37 | value = 10*value + c - '0'; 38 | } else { 39 | if (c=='c') channel = value; 40 | else if (c=='w') { 41 | DmxSimple.write(channel, value); 42 | Serial.println(); 43 | } 44 | value = 0; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /extras/lights.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PaulStoffregen/DmxSimple/7ac2b4ec8ee1e1ae44fb8b65d4b96bf55d3737ad/extras/lights.jpg -------------------------------------------------------------------------------- /keywords.txt: -------------------------------------------------------------------------------- 1 | ####################################### 2 | # Syntax Coloring Map For DmxSimple 3 | ####################################### 4 | 5 | ####################################### 6 | # Datatypes (KEYWORD1) 7 | ####################################### 8 | 9 | DmxSimple KEYWORD1 10 | 11 | ####################################### 12 | # Methods and Functions (KEYWORD2) 13 | ####################################### 14 | 15 | write KEYWORD2 16 | maxChannel KEYWORD2 17 | usePin KEYWORD2 18 | 19 | ####################################### 20 | # Constants (LITERAL1) 21 | ####################################### 22 | 23 | -------------------------------------------------------------------------------- /library.properties: -------------------------------------------------------------------------------- 1 | name=DmxSimple 2 | version=3.1 3 | author=Peter Knight, Tinker.it! 4 | maintainer=Paul Stoffregen 5 | sentence=Drive DMX controlled lights and visual effects available from DJ or theatrical suppliers. 6 | paragraph= 7 | category=Communication 8 | url=https://code.google.com/p/tinkerit/wiki/DmxSimple 9 | architectures=* 10 | 11 | -------------------------------------------------------------------------------- /release_notes.txt: -------------------------------------------------------------------------------- 1 | DmxSimple v3 release: 2 | Changes from v2 to v3: 3 | Optimised interrupt routine now supports serial baud rates up to 115200. 4 | DMX output pin can be changed with the DmxSimple.usePin() function. 5 | Automatic support for future clock rates and pin mappings. 6 | Syntax highlighting in Arduino editor fixed. 7 | More comments added to FadeUp and SerialToDmx examples 8 | FadeUp example now demonstrates all DmxSimple functions. 9 | Release notes file added. (For older revisions, see SVN log on Google Code) 10 | --------------------------------------------------------------------------------